Merge "Add getCardIdForDefaultEuicc method"
diff --git a/Android.bp b/Android.bp
index 9f5459b..80070b7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,6 +47,7 @@
],
static_libs: [
"telephony-protos",
+ "ecc-protos-lite",
"android.hardware.radio-V1.0-java",
"android.hardware.radio-V1.1-java",
"android.hardware.radio-V1.2-java",
diff --git a/proto/src/telephony.proto b/proto/src/telephony.proto
index 6fa46df..d49c2b2 100644
--- a/proto/src/telephony.proto
+++ b/proto/src/telephony.proto
@@ -1556,4 +1556,20 @@
// Amount of time modem is in tx (ms)
repeated int64 tx_time_ms = 9;
+
+ // Number of bytes sent (tx)
+ optional int64 num_bytes_tx = 10;
+
+ // Number of packets received (rx)
+ optional int64 num_packets_rx = 11;
+
+ // Number of bytes received (rx)
+ optional int64 num_bytes_rx = 12;
+
+ // Amount of time phone spends in various Radio Access Technologies (ms)
+ repeated int64 time_in_rat_ms = 13;
+
+ // Amount of time phone spends in various cellular
+ // rx signal strength levels (ms)
+ repeated int64 time_in_rx_signal_strength_level_ms = 14;
}
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index d5e7e0c..2695951 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -78,6 +78,7 @@
protected RegistrantList mNattKeepaliveStatusRegistrants = new RegistrantList();
protected RegistrantList mPhysicalChannelConfigurationRegistrants = new RegistrantList();
protected RegistrantList mLceInfoRegistrants = new RegistrantList();
+ protected RegistrantList mEmergencyNumberListRegistrants = new RegistrantList();
protected Registrant mGsmSmsRegistrant;
protected Registrant mCdmaSmsRegistrant;
@@ -783,6 +784,17 @@
mSubscriptionStatusRegistrants.remove(h);
}
+ @Override
+ public void registerForEmergencyNumberList(Handler h, int what, Object obj) {
+ Registrant r = new Registrant(h, what, obj);
+ mEmergencyNumberListRegistrants.add(r);
+ }
+
+ @Override
+ public void unregisterForEmergencyNumberList(Handler h) {
+ mEmergencyNumberListRegistrants.remove(h);
+ }
+
//***** Protected Methods
/**
* Store new RadioState and send notification based on the changes
diff --git a/src/java/com/android/internal/telephony/CallFailCause.java b/src/java/com/android/internal/telephony/CallFailCause.java
index acc1432..6e4e01c 100644
--- a/src/java/com/android/internal/telephony/CallFailCause.java
+++ b/src/java/com/android/internal/telephony/CallFailCause.java
@@ -149,6 +149,9 @@
int DIAL_MODIFIED_TO_SS = 245;
int DIAL_MODIFIED_TO_DIAL = 246;
+ //Access class blocked - TS 31.121 5.2.1
+ int ACCESS_CLASS_BLOCKED = 260;
+
//Emergency Redial
int EMERGENCY_TEMP_FAILURE = 325;
int EMERGENCY_PERM_FAILURE = 326;
diff --git a/src/java/com/android/internal/telephony/CarrierActionAgent.java b/src/java/com/android/internal/telephony/CarrierActionAgent.java
index 4582404..40fe386 100644
--- a/src/java/com/android/internal/telephony/CarrierActionAgent.java
+++ b/src/java/com/android/internal/telephony/CarrierActionAgent.java
@@ -118,6 +118,10 @@
log("SET_METERED_APNS_ENABLED: " + mCarrierActionOnMeteredApnEnabled);
mMeteredApnEnabledLog.log("SET_METERED_APNS_ENABLED: "
+ mCarrierActionOnMeteredApnEnabled);
+ int otaspState = (mCarrierActionOnMeteredApnEnabled)
+ ? mPhone.getServiceStateTracker().getOtasp()
+ : TelephonyManager.OTASP_SIM_UNPROVISIONED;
+ mPhone.notifyOtaspChanged(otaspState);
mMeteredApnEnableRegistrants.notifyRegistrants(
new AsyncResult(null, mCarrierActionOnMeteredApnEnabled, null));
break;
diff --git a/src/java/com/android/internal/telephony/CellularNetworkService.java b/src/java/com/android/internal/telephony/CellularNetworkService.java
index fa84b20..edbbcda 100644
--- a/src/java/com/android/internal/telephony/CellularNetworkService.java
+++ b/src/java/com/android/internal/telephony/CellularNetworkService.java
@@ -276,7 +276,7 @@
return new NetworkRegistrationState(domain, transportType, regState,
accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
cellIdentity, maxDataCalls, false /* isDcNrRestricted */,
- false /* isNrAvailable */);
+ false /* isNrAvailable */, false /* isEnDcAvailable */);
} else if (result instanceof android.hardware.radio.V1_2.DataRegStateResult) {
android.hardware.radio.V1_2.DataRegStateResult dataRegState =
@@ -293,7 +293,25 @@
return new NetworkRegistrationState(domain, transportType, regState,
accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
cellIdentity, maxDataCalls, false /* isDcNrRestricted */,
- false /* isNrAvailable */);
+ false /* isNrAvailable */, false /* isEnDcAvailable */);
+ } else if (result instanceof android.hardware.radio.V1_4.DataRegStateResult) {
+ android.hardware.radio.V1_4.DataRegStateResult dataRegState =
+ (android.hardware.radio.V1_4.DataRegStateResult) result;
+ int regState = getRegStateFromHalRegState(dataRegState.base.regState);
+ int accessNetworkTechnology =
+ getAccessNetworkTechnologyFromRat(dataRegState.base.rat);
+ int reasonForDenial = dataRegState.base.reasonDataDenied;
+ boolean emergencyOnly = isEmergencyOnly(dataRegState.base.regState);
+ int maxDataCalls = dataRegState.base.maxDataCalls;
+ int[] availableServices = getAvailableServices(regState, domain, emergencyOnly);
+ CellIdentity cellIdentity =
+ convertHalCellIdentityToCellIdentity(dataRegState.base.cellIdentity);
+ android.hardware.radio.V1_4.NrIndicators nrIndicators = dataRegState.nrIndicators;
+
+ return new NetworkRegistrationState(domain, transportType, regState,
+ accessNetworkTechnology, reasonForDenial, emergencyOnly, availableServices,
+ cellIdentity, maxDataCalls, nrIndicators.isDcNrRestricted,
+ nrIndicators.isNrAvailable, nrIndicators.isEndcAvailable);
}
return null;
}
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 8b39e8b..cda5cd7 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -2221,6 +2221,22 @@
void unregisterForNattKeepaliveStatus(Handler h);
/**
+ * Register for unsolicited Emergency Number List Indications
+ *
+ * @param h Handler for notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ void registerForEmergencyNumberList(Handler h, int what, Object obj);
+
+ /**
+ * Deregister for unsolicited Emergency Number List Indications
+ *
+ * @param h Handler for notification message.
+ */
+ void unregisterForEmergencyNumberList(Handler h);
+
+ /**
* Start sending NATT Keepalive packets on a specified data connection
*
* @param contextId cid that identifies the data connection for this keepalive
diff --git a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
index c4701f7..ee2a9bb 100644
--- a/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/DefaultPhoneNotifier.java
@@ -31,6 +31,7 @@
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
+import android.telephony.emergency.EmergencyNumber;
import java.util.List;
@@ -362,6 +363,19 @@
}
}
+ @Override
+ public void notifyEmergencyNumberList(Phone sender,
+ List<EmergencyNumber> emergencyNumberList) {
+ int subId = sender.getSubId();
+ try {
+ if (mRegistry != null) {
+ mRegistry.notifyEmergencyNumberList(emergencyNumberList);
+ }
+ } catch (RemoteException ex) {
+ // system process is dead
+ }
+ }
+
/**
* Convert the {@link Phone.DataActivityState} enum into the TelephonyManager.DATA_* constants
* for the public API.
diff --git a/src/java/com/android/internal/telephony/DeviceStateMonitor.java b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
index 3a96630..358f15f 100644
--- a/src/java/com/android/internal/telephony/DeviceStateMonitor.java
+++ b/src/java/com/android/internal/telephony/DeviceStateMonitor.java
@@ -27,6 +27,9 @@
import android.hardware.display.DisplayManager;
import android.hardware.radio.V1_2.IndicationFilter;
import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
import android.os.BatteryManager;
import android.os.Handler;
import android.os.Message;
@@ -39,11 +42,14 @@
import android.util.SparseIntArray;
import android.view.Display;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Set;
/**
* The device state monitor monitors the device state such as charging state, power saving sate,
@@ -58,21 +64,65 @@
protected static final boolean DBG = false; /* STOPSHIP if true */
protected static final String TAG = DeviceStateMonitor.class.getSimpleName();
- private static final int EVENT_RIL_CONNECTED = 0;
- private static final int EVENT_UPDATE_MODE_CHANGED = 1;
- private static final int EVENT_SCREEN_STATE_CHANGED = 2;
- private static final int EVENT_POWER_SAVE_MODE_CHANGED = 3;
- private static final int EVENT_CHARGING_STATE_CHANGED = 4;
- private static final int EVENT_TETHERING_STATE_CHANGED = 5;
- private static final int EVENT_RADIO_AVAILABLE = 6;
+ static final int EVENT_RIL_CONNECTED = 0;
+ static final int EVENT_UPDATE_MODE_CHANGED = 1;
+ @VisibleForTesting
+ static final int EVENT_SCREEN_STATE_CHANGED = 2;
+ static final int EVENT_POWER_SAVE_MODE_CHANGED = 3;
+ @VisibleForTesting
+ static final int EVENT_CHARGING_STATE_CHANGED = 4;
+ static final int EVENT_TETHERING_STATE_CHANGED = 5;
+ static final int EVENT_RADIO_AVAILABLE = 6;
+ @VisibleForTesting
+ static final int EVENT_WIFI_CONNECTION_CHANGED = 7;
// TODO(b/74006656) load hysteresis values from a property when DeviceStateMonitor starts
private static final int HYSTERESIS_KBPS = 50;
+ private static final int WIFI_UNAVAILABLE = 0;
+ private static final int WIFI_AVAILABLE = 1;
+
private final Phone mPhone;
private final LocalLog mLocalLog = new LocalLog(100);
+ private final NetworkRequest mWifiNetworkRequest =
+ new NetworkRequest.Builder()
+ .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+ .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
+ .removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
+ .build();
+
+ private final ConnectivityManager.NetworkCallback mNetworkCallback =
+ new ConnectivityManager.NetworkCallback() {
+ Set<Network> mWifiNetworks = new HashSet<>();
+
+ @Override
+ public void onAvailable(Network network) {
+ synchronized (mWifiNetworks) {
+ if (mWifiNetworks.size() == 0) {
+ // We just connected to Wifi, so send an update.
+ obtainMessage(EVENT_WIFI_CONNECTION_CHANGED, WIFI_AVAILABLE, 0).sendToTarget();
+ log("Wifi (default) connected", true);
+ }
+ mWifiNetworks.add(network);
+ }
+ }
+
+ @Override
+ public void onLost(Network network) {
+ synchronized (mWifiNetworks) {
+ mWifiNetworks.remove(network);
+ if (mWifiNetworks.size() == 0) {
+ // We just disconnected from the last connected wifi, so send an update.
+ obtainMessage(
+ EVENT_WIFI_CONNECTION_CHANGED, WIFI_UNAVAILABLE, 0).sendToTarget();
+ log("Wifi (default) disconnected", true);
+ }
+ }
+ }
+ };
+
/**
* Flag for wifi/usb/bluetooth tethering turned on or not
*/
@@ -105,6 +155,22 @@
*/
private boolean mIsLowDataExpected;
+ /**
+ * Wifi is connected. True means both that cellular is likely to be asleep when the screen is
+ * on and that in most cases the device location is relatively close to the WiFi AP. This means
+ * that fewer location updates should be provided by cellular.
+ */
+ private boolean mIsWifiConnected;
+
+ @VisibleForTesting
+ static final int CELL_INFO_INTERVAL_SHORT_MS = 2000;
+ @VisibleForTesting
+ static final int CELL_INFO_INTERVAL_LONG_MS = 10000;
+
+ /** The minimum required wait time between cell info requests to the modem */
+ private int mCellInfoMinInterval = CELL_INFO_INTERVAL_SHORT_MS;
+
+
private SparseIntArray mUpdateModes = new SparseIntArray();
/**
@@ -202,6 +268,10 @@
mPhone.mCi.registerForRilConnected(this, EVENT_RIL_CONNECTED, null);
mPhone.mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
+
+ ConnectivityManager cm = (ConnectivityManager) phone.getContext().getSystemService(
+ Context.CONNECTIVITY_SERVICE);
+ cm.registerNetworkCallback(mWifiNetworkRequest, mNetworkCallback);
}
/**
@@ -212,6 +282,27 @@
}
/**
+ * @return The minimum period between CellInfo requests to the modem
+ */
+ @VisibleForTesting
+ public int computeCellInfoMinInterval() {
+ // The screen is on and we're either on cellular or charging. Screen on + Charging is
+ // a likely vehicular scenario, even if there is a nomadic AP.
+ if (mIsScreenOn && !mIsWifiConnected) {
+ // Screen on without WiFi - We are in a high power likely mobile situation.
+ return CELL_INFO_INTERVAL_SHORT_MS;
+ } else if (mIsScreenOn && mIsCharging) {
+ // Screen is on and we're charging, so we favor accuracy over power.
+ return CELL_INFO_INTERVAL_SHORT_MS;
+ } else {
+ // If the screen is off, apps should not need cellular location at rapid intervals.
+ // If the screen is on but we are on wifi and not charging then cellular location
+ // accuracy is not crucial, so favor modem power saving over high accuracy.
+ return CELL_INFO_INTERVAL_LONG_MS;
+ }
+ }
+
+ /**
* @return True if signal strength update should be turned off.
*/
private boolean shouldTurnOffSignalStrength() {
@@ -358,6 +449,9 @@
case EVENT_TETHERING_STATE_CHANGED:
onUpdateDeviceState(msg.what, msg.arg1 != 0);
break;
+ case EVENT_WIFI_CONNECTION_CHANGED:
+ onUpdateDeviceState(msg.what, msg.arg1 != WIFI_UNAVAILABLE);
+ break;
default:
throw new IllegalStateException("Unexpected message arrives. msg = " + msg.what);
}
@@ -389,10 +483,22 @@
mIsPowerSaveOn = state;
sendDeviceState(POWER_SAVE_MODE, mIsPowerSaveOn);
break;
+ case EVENT_WIFI_CONNECTION_CHANGED:
+ if (mIsWifiConnected == state) return;
+ mIsWifiConnected = state;
+
+ break;
default:
return;
}
+ final int newCellInfoMinInterval = computeCellInfoMinInterval();
+ if (mCellInfoMinInterval != newCellInfoMinInterval) {
+ mCellInfoMinInterval = newCellInfoMinInterval;
+ setCellInfoMinInterval(mCellInfoMinInterval);
+ log("CellInfo Min Interval Updated to " + newCellInfoMinInterval, true);
+ }
+
if (mIsLowDataExpected != isLowDataExpected()) {
mIsLowDataExpected = !mIsLowDataExpected;
sendDeviceState(LOW_DATA_EXPECTED, mIsLowDataExpected);
@@ -437,6 +543,7 @@
setUnsolResponseFilter(mUnsolicitedResponseFilter, true);
setSignalStrengthReportingCriteria();
setLinkCapacityReportingCriteria();
+ setCellInfoMinInterval(mCellInfoMinInterval);
}
/**
@@ -501,6 +608,10 @@
LINK_CAPACITY_UPLINK_THRESHOLDS, AccessNetworkType.CDMA2000);
}
+ private void setCellInfoMinInterval(int rate) {
+ mPhone.setCellInfoMinInterval(rate);
+ }
+
/**
* @return True if the device is currently in power save mode.
* See {@link android.os.BatteryManager#isPowerSaveMode BatteryManager.isPowerSaveMode()}.
@@ -579,6 +690,7 @@
ipw.println("mIsPowerSaveOn=" + mIsPowerSaveOn);
ipw.println("mIsLowDataExpected=" + mIsLowDataExpected);
ipw.println("mUnsolicitedResponseFilter=" + mUnsolicitedResponseFilter);
+ ipw.println("mIsWifiConnected=" + mIsWifiConnected);
ipw.println("Local logs:");
ipw.increaseIndent();
mLocalLog.dump(fd, ipw, args);
diff --git a/src/java/com/android/internal/telephony/GsmCdmaConnection.java b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
index ae1155b..84c9e0a 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaConnection.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaConnection.java
@@ -528,6 +528,7 @@
case CallFailCause.USER_ALERTING_NO_ANSWER:
return DisconnectCause.TIMED_OUT;
+ case CallFailCause.ACCESS_CLASS_BLOCKED:
case CallFailCause.ERROR_UNSPECIFIED:
case CallFailCause.NORMAL_CLEARING:
default:
@@ -562,7 +563,8 @@
}
}
if (isPhoneTypeGsm()) {
- if (causeCode == CallFailCause.ERROR_UNSPECIFIED) {
+ if (causeCode == CallFailCause.ERROR_UNSPECIFIED ||
+ causeCode == CallFailCause.ACCESS_CLASS_BLOCKED ) {
if (phone.mSST.mRestrictedState.isCsRestricted()) {
return DisconnectCause.CS_RESTRICTED;
} else if (phone.mSST.mRestrictedState.isCsEmergencyRestricted()) {
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index c98d9b0..4ce5a8c 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -77,7 +77,9 @@
import com.android.internal.telephony.cdma.CdmaMmiCode;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
+import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.gsm.GsmMmiCode;
import com.android.internal.telephony.gsm.SuppServiceNotification;
import com.android.internal.telephony.test.SimulatedRadioControl;
@@ -169,6 +171,7 @@
private IsimUiccRecords mIsimUiccRecords;
public GsmCdmaCallTracker mCT;
public ServiceStateTracker mSST;
+ public EmergencyNumberTracker mEmergencyNumberTracker;
private ArrayList <MmiCode> mPendingMMIs = new ArrayList<MmiCode>();
private IccPhoneBookInterfaceManager mIccPhoneBookIntManager;
// Used for identify the carrier of current subscription
@@ -224,20 +227,29 @@
initRatSpecific(precisePhoneType);
// CarrierSignalAgent uses CarrierActionAgent in construction so it needs to be created
// after CarrierActionAgent.
- mCarrierActionAgent = mTelephonyComponentFactory.makeCarrierActionAgent(this);
- mCarrierSignalAgent = mTelephonyComponentFactory.makeCarrierSignalAgent(this);
- mTransportManager = mTelephonyComponentFactory.makeTransportManager(this);
- mSST = mTelephonyComponentFactory.makeServiceStateTracker(this, this.mCi);
+ mCarrierActionAgent = mTelephonyComponentFactory.inject(CarrierActionAgent.class.getName())
+ .makeCarrierActionAgent(this);
+ mCarrierSignalAgent = mTelephonyComponentFactory.inject(CarrierSignalAgent.class.getName())
+ .makeCarrierSignalAgent(this);
+ mTransportManager = mTelephonyComponentFactory.inject(TransportManager.class.getName())
+ .makeTransportManager(this);
+ mSST = mTelephonyComponentFactory.inject(ServiceStateTracker.class.getName())
+ .makeServiceStateTracker(this, this.mCi);
+ mEmergencyNumberTracker = mTelephonyComponentFactory
+ .inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker(
+ this, this.mCi);
// DcTracker uses SST so needs to be created after it is instantiated
for (int transport : mTransportManager.getAvailableTransports()) {
- mDcTrackers.put(transport, mTelephonyComponentFactory.makeDcTracker(this,
- transport));
+ mDcTrackers.put(transport, mTelephonyComponentFactory.inject(DcTracker.class.getName())
+ .makeDcTracker(this, transport));
}
- mCarrierResolver = mTelephonyComponentFactory.makeCarrierResolver(this);
+ mCarrierResolver = mTelephonyComponentFactory.inject(CarrierResolver.class.getName())
+ .makeCarrierResolver(this);
mSST.registerForNetworkAttached(this, EVENT_REGISTERED_TO_NETWORK, null);
- mDeviceStateMonitor = mTelephonyComponentFactory.makeDeviceStateMonitor(this);
+ mDeviceStateMonitor = mTelephonyComponentFactory.inject(DeviceStateMonitor.class.getName())
+ .makeDeviceStateMonitor(this);
mSST.registerForVoiceRegStateOrRatChanged(this, EVENT_VRS_OR_RAT_CHANGED, null);
logd("GsmCdmaPhone: constructor: sub = " + mPhoneId);
@@ -258,12 +270,17 @@
mSimulatedRadioControl = (SimulatedRadioControl) ci;
}
- mCT = mTelephonyComponentFactory.makeGsmCdmaCallTracker(this);
- mIccPhoneBookIntManager = mTelephonyComponentFactory.makeIccPhoneBookInterfaceManager(this);
+ mCT = mTelephonyComponentFactory.inject(GsmCdmaCallTracker.class.getName())
+ .makeGsmCdmaCallTracker(this);
+ mIccPhoneBookIntManager = mTelephonyComponentFactory
+ .inject(IccPhoneBookInterfaceManager.class.getName())
+ .makeIccPhoneBookInterfaceManager(this);
PowerManager pm
= (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, LOG_TAG);
- mIccSmsInterfaceManager = mTelephonyComponentFactory.makeIccSmsInterfaceManager(this);
+ mIccSmsInterfaceManager = mTelephonyComponentFactory
+ .inject(IccSmsInterfaceManager.class.getName())
+ .makeIccSmsInterfaceManager(this);
mCi.registerForAvailable(this, EVENT_RADIO_AVAILABLE, null);
mCi.registerForOffOrNotAvailable(this, EVENT_RADIO_OFF_OR_NOT_AVAILABLE, null);
@@ -276,10 +293,11 @@
mCi.setOnSs(this, EVENT_SS, null);
//CDMA
- mCdmaSSM = mTelephonyComponentFactory.getCdmaSubscriptionSourceManagerInstance(mContext,
+ mCdmaSSM = mTelephonyComponentFactory.inject(CdmaSubscriptionSourceManager.class.getName())
+ .getCdmaSubscriptionSourceManagerInstance(mContext,
mCi, this, EVENT_CDMA_SUBSCRIPTION_SOURCE_CHANGED, null);
- mEriManager = mTelephonyComponentFactory.makeEriManager(this, mContext,
- EriManager.ERI_FROM_XML);
+ mEriManager = mTelephonyComponentFactory.inject(EriManager.class.getName())
+ .makeEriManager(this, mContext, EriManager.ERI_FROM_XML);
mCi.setEmergencyCallbackMode(this, EVENT_EMERGENCY_CALLBACK_MODE_ENTER, null);
mCi.registerForExitEmergencyCallbackMode(this, EVENT_EXIT_EMERGENCY_CALLBACK_RESPONSE,
null);
@@ -476,6 +494,11 @@
}
@Override
+ public EmergencyNumberTracker getEmergencyNumberTracker() {
+ return mEmergencyNumberTracker;
+ }
+
+ @Override
public CallTracker getCallTracker() {
return mCT;
}
@@ -1869,9 +1892,7 @@
int serviceClass) {
if (isPhoneTypeGsm()) {
Phone imsPhone = mImsPhone;
- if ((imsPhone != null)
- && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
- || imsPhone.isUtEnabled())) {
+ if ((imsPhone != null) && imsPhone.isUtEnabled()) {
imsPhone.getCallBarring(facility, password, onComplete, serviceClass);
return;
}
@@ -1886,9 +1907,7 @@
Message onComplete, int serviceClass) {
if (isPhoneTypeGsm()) {
Phone imsPhone = mImsPhone;
- if ((imsPhone != null)
- && ((imsPhone.getServiceState().getState() == ServiceState.STATE_IN_SERVICE)
- || imsPhone.isUtEnabled())) {
+ if ((imsPhone != null) && imsPhone.isUtEnabled()) {
imsPhone.setCallBarring(facility, lockState, password, onComplete, serviceClass);
return;
}
diff --git a/src/java/com/android/internal/telephony/IccCard.java b/src/java/com/android/internal/telephony/IccCard.java
index 7bab408..75f3377 100644
--- a/src/java/com/android/internal/telephony/IccCard.java
+++ b/src/java/com/android/internal/telephony/IccCard.java
@@ -275,6 +275,14 @@
return false;
}
+ /**
+ * @return whether the card is an empty profile, meaning there's no UiccCardApplication,
+ * and that we don't need to wait for LOADED state.
+ */
+ public boolean isEmptyProfile() {
+ return false;
+ }
+
private void sendMessageWithCardAbsentException(Message onComplete) {
AsyncResult ret = AsyncResult.forMessage(onComplete);
ret.exception = new RuntimeException("No valid IccCard");
diff --git a/src/java/com/android/internal/telephony/InboundSmsHandler.java b/src/java/com/android/internal/telephony/InboundSmsHandler.java
index a115dba..5124748 100644
--- a/src/java/com/android/internal/telephony/InboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/InboundSmsHandler.java
@@ -259,7 +259,8 @@
mWakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, name);
mWakeLock.acquire(); // wake lock released after we enter idle state
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
- mDeviceIdleController = TelephonyComponentFactory.getInstance().getIDeviceIdleController();
+ mDeviceIdleController = TelephonyComponentFactory.getInstance()
+ .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController();
addState(mDefaultState);
addState(mStartupState, mDefaultState);
@@ -719,8 +720,9 @@
destPort = smsHeader.portAddrs.destPort;
if (DBG) log("destination port: " + destPort);
}
-
- tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(),
+ tracker = TelephonyComponentFactory.getInstance()
+ .inject(InboundSmsTracker.class.getName())
+ .makeInboundSmsTracker(sms.getPdu(),
sms.getTimestampMillis(), destPort, is3gpp2(), false,
sms.getOriginatingAddress(), sms.getDisplayOriginatingAddress(),
sms.getMessageBody());
@@ -729,8 +731,9 @@
SmsHeader.ConcatRef concatRef = smsHeader.concatRef;
SmsHeader.PortAddrs portAddrs = smsHeader.portAddrs;
int destPort = (portAddrs != null ? portAddrs.destPort : -1);
-
- tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(sms.getPdu(),
+ tracker = TelephonyComponentFactory.getInstance()
+ .inject(InboundSmsTracker.class.getName())
+ .makeInboundSmsTracker(sms.getPdu(),
sms.getTimestampMillis(), destPort, is3gpp2(), sms.getOriginatingAddress(),
sms.getDisplayOriginatingAddress(), concatRef.refNumber, concatRef.seqNumber,
concatRef.msgCount, false, sms.getMessageBody());
diff --git a/src/java/com/android/internal/telephony/LocaleTracker.java b/src/java/com/android/internal/telephony/LocaleTracker.java
index d582762..b6d2871 100755
--- a/src/java/com/android/internal/telephony/LocaleTracker.java
+++ b/src/java/com/android/internal/telephony/LocaleTracker.java
@@ -100,7 +100,7 @@
/** Current cell tower information */
@Nullable
- private List<CellInfo> mCellInfo;
+ private List<CellInfo> mCellInfoList;
/** Count of invalid cell info we've got so far. Will reset once we get a successful one */
private int mFailCellInfoCount;
@@ -146,14 +146,14 @@
case EVENT_UNSOL_CELL_INFO:
processCellInfo((AsyncResult) msg.obj);
// If the unsol happened to be useful, use it; otherwise, pretend it didn't happen.
- if (mCellInfo != null && mCellInfo.size() > 0) requestNextCellInfo(true);
+ if (mCellInfoList != null && mCellInfoList.size() > 0) requestNextCellInfo(true);
break;
case EVENT_RESPONSE_CELL_INFO:
processCellInfo((AsyncResult) msg.obj);
// If the cellInfo was non-empty then it's business as usual. Either way, this
// cell info was requested by us, so it's our trigger to schedule another one.
- requestNextCellInfo(mCellInfo != null && mCellInfo.size() > 0);
+ requestNextCellInfo(mCellInfoList != null && mCellInfoList.size() > 0);
break;
case EVENT_SERVICE_STATE_CHANGED:
@@ -209,10 +209,10 @@
@Nullable
private String getMccFromCellInfo() {
String selectedMcc = null;
- if (mCellInfo != null) {
+ if (mCellInfoList != null) {
Map<String, Integer> countryCodeMap = new HashMap<>();
int maxCount = 0;
- for (CellInfo cellInfo : mCellInfo) {
+ for (CellInfo cellInfo : mCellInfoList) {
String mcc = null;
if (cellInfo instanceof CellInfoGsm) {
mcc = ((CellInfoGsm) cellInfo).getCellIdentity().getMccString();
@@ -281,13 +281,28 @@
private void processCellInfo(AsyncResult ar) {
if (ar == null || ar.exception != null) {
- mCellInfo = null;
+ mCellInfoList = null;
return;
}
- mCellInfo = (List<CellInfo>) ar.result;
- String msg = "getCellInfo: cell info=" + mCellInfo;
+ List<CellInfo> cellInfoList = (List<CellInfo>) ar.result;
+ String msg = "getCellInfo: cell info=" + cellInfoList;
if (DBG) log(msg);
- mLocalLog.log(msg);
+ if (cellInfoList != null) {
+ // We only log when cell identity changes, otherwise the local log is flooded with cell
+ // info.
+ if (mCellInfoList == null || cellInfoList.size() != mCellInfoList.size()) {
+ mLocalLog.log(msg);
+ } else {
+ for (int i = 0; i < cellInfoList.size(); i++) {
+ if (!Objects.equals(mCellInfoList.get(i).getCellIdentity(),
+ cellInfoList.get(i).getCellIdentity())) {
+ mLocalLog.log(msg);
+ break;
+ }
+ }
+ }
+ }
+ mCellInfoList = cellInfoList;
updateLocale();
}
@@ -355,7 +370,7 @@
String msg = "Stopping LocaleTracker";
if (DBG) log(msg);
mLocalLog.log(msg);
- mCellInfo = null;
+ mCellInfoList = null;
resetCellInfoRetry();
}
@@ -392,12 +407,11 @@
countryIso = MccTable.countryCodeForMcc(mcc);
}
- String msg = "updateLocale: mcc = " + mcc + ", country = " + countryIso;
- log(msg);
- mLocalLog.log(msg);
+ log("updateLocale: mcc = " + mcc + ", country = " + countryIso);
boolean countryChanged = false;
if (!Objects.equals(countryIso, mCurrentCountryIso)) {
- msg = "updateLocale: Change the current country to " + countryIso;
+ String msg = "updateLocale: Change the current country to \"" + countryIso
+ + "\", mcc = " + mcc;
log(msg);
mLocalLog.log(msg);
mCurrentCountryIso = countryIso;
@@ -447,7 +461,7 @@
ipw.println("mIsTracking = " + mIsTracking);
ipw.println("mOperatorNumeric = " + mOperatorNumeric);
ipw.println("mSimState = " + mSimState);
- ipw.println("mCellInfo = " + mCellInfo);
+ ipw.println("mCellInfoList = " + mCellInfoList);
ipw.println("mCurrentCountryIso = " + mCurrentCountryIso);
ipw.println("mFailCellInfoCount = " + mFailCellInfoCount);
ipw.println("Local logs:");
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index c4f203e..e6ec174 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -57,6 +57,7 @@
import android.telephony.TelephonyManager;
import android.telephony.data.ApnSetting;
import android.telephony.data.ApnSetting.ApnType;
+import android.telephony.emergency.EmergencyNumber;
import android.telephony.ims.stub.ImsRegistrationImplBase;
import android.text.TextUtils;
import android.util.SparseArray;
@@ -68,6 +69,7 @@
import com.android.internal.telephony.dataconnection.DataConnectionReasons;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsPhoneCall;
import com.android.internal.telephony.test.SimulatedRadioControl;
import com.android.internal.telephony.uicc.IccCardApplicationStatus.AppType;
@@ -483,7 +485,8 @@
mCi = ci;
mActionDetached = this.getClass().getPackage().getName() + ".action_detached";
mActionAttached = this.getClass().getPackage().getName() + ".action_attached";
- mAppSmsManager = telephonyComponentFactory.makeAppSmsManager(context);
+ mAppSmsManager = telephonyComponentFactory.inject(AppSmsManager.class.getName())
+ .makeAppSmsManager(context);
if (Build.IS_DEBUGGABLE) {
mTelephonyTester = new TelephonyTester(this);
@@ -545,11 +548,15 @@
// Initialize device storage and outgoing SMS usage monitors for SMSDispatchers.
mTelephonyComponentFactory = telephonyComponentFactory;
- mSmsStorageMonitor = mTelephonyComponentFactory.makeSmsStorageMonitor(this);
- mSmsUsageMonitor = mTelephonyComponentFactory.makeSmsUsageMonitor(context);
+ mSmsStorageMonitor = mTelephonyComponentFactory.inject(SmsStorageMonitor.class.getName())
+ .makeSmsStorageMonitor(this);
+ mSmsUsageMonitor = mTelephonyComponentFactory.inject(SmsUsageMonitor.class.getName())
+ .makeSmsUsageMonitor(context);
mUiccController = UiccController.getInstance();
mUiccController.registerForIccChanged(this, EVENT_ICC_CHANGED, null);
- mSimActivationTracker = mTelephonyComponentFactory.makeSimActivationTracker(this);
+ mSimActivationTracker = mTelephonyComponentFactory
+ .inject(SimActivationTracker.class.getName())
+ .makeSimActivationTracker(this);
if (getPhoneType() != PhoneConstants.PHONE_TYPE_SIP) {
mCi.registerForSrvccStateChanged(this, EVENT_SRVCC_STATE_CHANGED, null);
}
@@ -1629,6 +1636,13 @@
}
/**
+ * Retrieves the EmergencyNumberTracker of the phone instance.
+ */
+ public EmergencyNumberTracker getEmergencyNumberTracker() {
+ return null;
+ }
+
+ /**
* Get call tracker
*/
public CallTracker getCallTracker() {
@@ -1722,6 +1736,11 @@
return (r != null) ? r.getRecordsLoaded() : false;
}
+ /** Set the minimum interval for CellInfo requests to the modem */
+ public void setCellInfoMinInterval(int interval) {
+ getServiceStateTracker().setCellInfoMinInterval(interval);
+ }
+
/**
* @return the last known CellInfo
*/
@@ -2241,6 +2260,11 @@
mNotifier.notifySrvccStateChanged(this, state);
}
+ /** Notify the list of {@link EmergencyNumber} changes. */
+ public void notifyEmergencyNumberList(List<EmergencyNumber> emergencyNumberList) {
+ mNotifier.notifyEmergencyNumberList(this, emergencyNumberList);
+ }
+
/**
* @return true if a mobile originating emergency call is active
*/
@@ -3917,6 +3941,17 @@
pw.println("++++++++++++++++++++++++++++++++");
}
+ if (getEmergencyNumberTracker() != null) {
+ try {
+ getEmergencyNumberTracker().dump(fd, pw, args);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ pw.flush();
+ pw.println("++++++++++++++++++++++++++++++++");
+ }
+
if (mCarrierActionAgent != null) {
try {
mCarrierActionAgent.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/PhoneNotifier.java b/src/java/com/android/internal/telephony/PhoneNotifier.java
index 0568187..30b53d7 100644
--- a/src/java/com/android/internal/telephony/PhoneNotifier.java
+++ b/src/java/com/android/internal/telephony/PhoneNotifier.java
@@ -21,6 +21,7 @@
import android.telephony.PhoneCapability;
import android.telephony.PhysicalChannelConfig;
import android.telephony.TelephonyManager;
+import android.telephony.emergency.EmergencyNumber;
import java.util.List;
@@ -78,4 +79,7 @@
public void notifyPhoneCapabilityChanged(PhoneCapability capability);
void notifyRadioPowerStateChanged(@TelephonyManager.RadioPowerState int state);
+
+ /** Notify of change to EmergencyNumberList. */
+ void notifyEmergencyNumberList(Phone sender, List<EmergencyNumber> emergencyNumberList);
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 9181e98..eb10904 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -3138,10 +3138,6 @@
}
}
- void setCellInfoListRate() {
- setCellInfoListRate(Integer.MAX_VALUE, null, mRILDefaultWorkSource);
- }
-
@Override
public void setInitialAttachApn(DataProfile dataProfile, boolean isRoaming, Message result) {
diff --git a/src/java/com/android/internal/telephony/RadioIndication.java b/src/java/com/android/internal/telephony/RadioIndication.java
index f2214d6..1614a27 100644
--- a/src/java/com/android/internal/telephony/RadioIndication.java
+++ b/src/java/com/android/internal/telephony/RadioIndication.java
@@ -672,7 +672,6 @@
// Initial conditions
mRil.setRadioPower(false, null);
mRil.setCdmaSubscriptionSource(mRil.mCdmaSubscription, null);
- mRil.setCellInfoListRate();
// todo: this should not require a version number now. Setting it to latest RIL version for
// now.
mRil.notifyRegistrantsRilConnectionChanged(15);
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 4d91a27..cd1f44a 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -128,13 +128,13 @@
private ServiceState mNewSS;
// This is the minimum interval at which CellInfo requests will be serviced by the modem.
- // Any requests that arrive within MAX_AGE of the previous reuqest will simply receive the
+ // Any requests that arrive within MinInterval of the previous reuqest will simply receive the
// cached result. This is a power-saving feature, because requests to the modem may require
// wakeup of a separate chip and bus communication. Because the cost of wakeups is
// architecture dependent, it would be preferable if this sort of optimization could be
// handled in SoC-specific code, but for now, keep it here to ensure that in case further
// optimizations are not present elsewhere, there is a power-management scheme of last resort.
- private static final long LAST_CELL_INFO_LIST_MAX_AGE_MS = 2000;
+ private int mCellInfoMinIntervalMs = 2000;
// Maximum time to wait for a CellInfo request before assuming it won't arrive and returning
// null to callers. Note, that if a CellInfo response does arrive later, then it will be
@@ -494,7 +494,9 @@
private static final int INVALID_LTE_EARFCN = -1;
public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
- mNitzState = TelephonyComponentFactory.getInstance().makeNitzStateMachine(phone);
+ mNitzState = TelephonyComponentFactory.getInstance()
+ .inject(NitzStateMachine.class.getName())
+ .makeNitzStateMachine(phone);
mPhone = phone;
mCi = ci;
@@ -522,9 +524,9 @@
mRegStateManagers.get(transportType).registerForNetworkRegistrationStateChanged(
this, EVENT_NETWORK_STATE_CHANGED, null);
}
-
- mLocaleTracker = TelephonyComponentFactory.getInstance().makeLocaleTracker(
- mPhone, mNitzState, getLooper());
+ mLocaleTracker = TelephonyComponentFactory.getInstance()
+ .inject(LocaleTracker.class.getName())
+ .makeLocaleTracker(mPhone, mNitzState, getLooper());
mCi.registerForImsNetworkStateChanged(this, EVENT_IMS_STATE_CHANGED, null);
mCi.registerForRadioStateChanged(this, EVENT_RADIO_STATE_CHANGED, null);
@@ -4354,6 +4356,11 @@
return mLastCellInfoList;
}
+ /** Set the minimum time between CellInfo requests to the modem, in milliseconds */
+ public void setCellInfoMinInterval(int interval) {
+ mCellInfoMinIntervalMs = interval;
+ }
+
/**
* Request the latest CellInfo from the modem.
*
@@ -4381,7 +4388,7 @@
// Check to see whether the elapsed time is sufficient for a new request; if not, then
// return the result of the last request (if expected).
final long curTime = SystemClock.elapsedRealtime();
- if ((curTime - mLastCellInfoReqTime) < LAST_CELL_INFO_LIST_MAX_AGE_MS) {
+ if ((curTime - mLastCellInfoReqTime) < mCellInfoMinIntervalMs) {
if (rspMsg != null) {
if (DBG) log("SST.requestAllCellInfo(): return last, back to back calls");
AsyncResult.forMessage(rspMsg, mLastCellInfoList, null);
@@ -4563,6 +4570,7 @@
pw.println(" mDeviceShuttingDown=" + mDeviceShuttingDown);
pw.println(" mSpnUpdatePending=" + mSpnUpdatePending);
pw.println(" mLteRsrpBoost=" + mLteRsrpBoost);
+ pw.println(" mCellInfoMinIntervalMs=" + mCellInfoMinIntervalMs);
dumpEarfcnPairList(pw);
mLocaleTracker.dump(fd, pw, args);
diff --git a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
index 32edb9c..516ca3f 100644
--- a/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
+++ b/src/java/com/android/internal/telephony/SmsBroadcastUndelivered.java
@@ -165,7 +165,8 @@
while (cursor.moveToNext()) {
InboundSmsTracker tracker;
try {
- tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(cursor,
+ tracker = TelephonyComponentFactory.getInstance()
+ .inject(InboundSmsTracker.class.getName()).makeInboundSmsTracker(cursor,
isCurrentFormat3gpp2);
} catch (IllegalArgumentException e) {
Rlog.e(TAG, "error loading SmsTracker: " + e);
diff --git a/src/java/com/android/internal/telephony/SubscriptionController.java b/src/java/com/android/internal/telephony/SubscriptionController.java
index 09fc531..09fcc93 100644
--- a/src/java/com/android/internal/telephony/SubscriptionController.java
+++ b/src/java/com/android/internal/telephony/SubscriptionController.java
@@ -21,6 +21,7 @@
import android.Manifest;
import android.annotation.Nullable;
import android.app.AppOpsManager;
+import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
@@ -615,7 +616,7 @@
return;
}
- boolean opptSubListChanged = false;
+ boolean opptSubListChanged;
synchronized (mSubInfoListLock) {
mCacheActiveSubInfoList.clear();
@@ -2450,14 +2451,31 @@
}
}
-
private boolean refreshCachedOpportunisticSubscriptionInfoList() {
synchronized (mSubInfoListLock) {
List<SubscriptionInfo> oldOpptCachedList = mCacheOpportunisticSubInfoList;
- mCacheOpportunisticSubInfoList = mCacheActiveSubInfoList.stream()
- .filter(subscriptionInfo -> subscriptionInfo.isOpportunistic())
- .collect(Collectors.toList());
+ List<SubscriptionInfo> subList = getSubInfo(
+ SubscriptionManager.IS_OPPORTUNISTIC + "=1 AND ("
+ + SubscriptionManager.SIM_SLOT_INDEX + ">=0 OR "
+ + SubscriptionManager.IS_EMBEDDED + "=1)", null);
+
+ if (subList != null) {
+ subList.sort(SUBSCRIPTION_INFO_COMPARATOR);
+ } else {
+ subList = new ArrayList<>();
+ }
+
+ mCacheOpportunisticSubInfoList = subList;
+
+ for (SubscriptionInfo info : mCacheOpportunisticSubInfoList) {
+ if (shouldDisableSubGroup(info.getGroupUuid())) {
+ info.setGroupDisabled(true);
+ if (isActiveSubId(info.getSubscriptionId())) {
+ deactivateSubscription(info);
+ }
+ }
+ }
if (DBG_CACHE) {
if (!mCacheOpportunisticSubInfoList.isEmpty()) {
@@ -2473,4 +2491,25 @@
return !oldOpptCachedList.equals(mCacheOpportunisticSubInfoList);
}
}
+
+ private boolean shouldDisableSubGroup(String groupUuid) {
+ if (groupUuid == null) return false;
+
+ for (SubscriptionInfo activeInfo : mCacheActiveSubInfoList) {
+ if (!activeInfo.isOpportunistic() && groupUuid.equals(activeInfo.getGroupUuid())) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ private void deactivateSubscription(SubscriptionInfo info) {
+ // TODO: b/120439488 deactivate pSIM.
+ if (info.isEmbedded()) {
+ EuiccManager euiccManager = new EuiccManager(mContext);
+ euiccManager.switchToSubscription(SubscriptionManager.INVALID_SUBSCRIPTION_ID,
+ PendingIntent.getService(mContext, 0, new Intent(), 0));
+ }
+ }
}
diff --git a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
index 4bf8638..e3c8cad 100644
--- a/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
+++ b/src/java/com/android/internal/telephony/SubscriptionInfoUpdater.java
@@ -276,16 +276,8 @@
break;
case EVENT_SIM_NOT_READY:
- broadcastSimStateChanged(msg.arg1, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
- null);
- broadcastSimCardStateChanged(msg.arg1, TelephonyManager.SIM_STATE_PRESENT);
- broadcastSimApplicationStateChanged(msg.arg1, TelephonyManager.SIM_STATE_NOT_READY);
+ handleSimNotReady(msg.arg1);
// intentional fall through
- // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
- // phase, the subscription list is accessible.
- // TODO(b/64216093): Clean up this special case, likely by treating NOT_READY
- // as equivalent to ABSENT, once the rest of the system can handle it. Currently
- // this breaks SystemUI which shows a "No SIM" icon.
case EVENT_REFRESH_EMBEDDED_SUBSCRIPTIONS:
if (updateEmbeddedSubscriptions()) {
@@ -359,6 +351,26 @@
}
}
+ private void handleSimNotReady(int slotId) {
+ logd("handleSimNotReady: slotId: " + slotId);
+
+ IccCard iccCard = mPhone[slotId].getIccCard();
+ if (iccCard.isEmptyProfile()) {
+ // ICC_NOT_READY is a terminal state for an eSIM on the boot profile. At this
+ // phase, the subscription list is accessible. Treating NOT_READY
+ // as equivalent to ABSENT, once the rest of the system can handle it.
+ mIccId[slotId] = ICCID_STRING_FOR_NO_SIM;
+ if (isAllIccIdQueryDone()) {
+ updateSubscriptionInfoByIccId();
+ }
+ }
+
+ broadcastSimStateChanged(slotId, IccCardConstants.INTENT_VALUE_ICC_NOT_READY,
+ null);
+ broadcastSimCardStateChanged(slotId, TelephonyManager.SIM_STATE_PRESENT);
+ broadcastSimApplicationStateChanged(slotId, TelephonyManager.SIM_STATE_NOT_READY);
+ }
+
private void handleSimLoaded(int slotId) {
logd("handleSimLoaded: slotId: " + slotId);
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 4522d8a..a8fa4b8 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -16,17 +16,21 @@
package com.android.internal.telephony;
+import android.annotation.NonNull;
import android.content.Context;
+import android.content.res.XmlResourceParser;
import android.database.Cursor;
import android.os.Handler;
import android.os.IDeviceIdleController;
import android.os.Looper;
import android.os.ServiceManager;
+import android.telephony.Rlog;
import com.android.internal.telephony.cdma.CdmaSubscriptionSourceManager;
import com.android.internal.telephony.cdma.EriManager;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -34,14 +38,149 @@
import com.android.internal.telephony.uicc.UiccCard;
import com.android.internal.telephony.uicc.UiccProfile;
+import dalvik.system.PathClassLoader;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.function.Consumer;
+
/**
* This class has one-line methods to instantiate objects only. The purpose is to make code
* unit-test friendly and use this class as a way to do dependency injection. Instantiating objects
* this way makes it easier to mock them in tests.
*/
public class TelephonyComponentFactory {
+
+ private static final String TAG = TelephonyComponentFactory.class.getSimpleName();
+
private static TelephonyComponentFactory sInstance;
+ private InjectedComponents mInjectedComponents;
+
+ private static class InjectedComponents {
+ private static final String ATTRIBUTE_JAR = "jar";
+ private static final String ATTRIBUTE_PACKAGE = "package";
+ private static final String TAG_INJECTION = "injection";
+ private static final String TAG_COMPONENTS = "components";
+ private static final String TAG_COMPONENT = "component";
+
+ private final Set<String> mComponentNames = new HashSet<>();
+ private TelephonyComponentFactory mInjectedInstance;
+ private String mPackageName;
+ private String mJarPath;
+
+ private boolean isInjected() {
+ return mPackageName != null && mJarPath != null;
+ }
+
+ private void makeInjectedInstance() {
+ if (isInjected()) {
+ PathClassLoader classLoader = new PathClassLoader(mJarPath,
+ ClassLoader.getSystemClassLoader());
+ try {
+ Class<?> cls = classLoader.loadClass(mPackageName);
+ mInjectedInstance = (TelephonyComponentFactory) cls.newInstance();
+ } catch (ClassNotFoundException e) {
+ Rlog.e(TAG, "failed: " + e.getMessage());
+ } catch (IllegalAccessException | InstantiationException e) {
+ Rlog.e(TAG, "injection failed: " + e.getMessage());
+ }
+ }
+ }
+
+ private boolean isComponentInjected(String componentName) {
+ if (mInjectedInstance == null) {
+ return false;
+ }
+ return mComponentNames.contains(componentName);
+ }
+
+ /**
+ * Find the injection tag, set attributes, and then parse the injection.
+ */
+ private void parseXml(@NonNull XmlPullParser parser) {
+ parseXmlByTag(parser, false, p -> {
+ setAttributes(p);
+ parseInjection(p);
+ }, TAG_INJECTION);
+ }
+
+ /**
+ * Only parse the first injection tag. Find the components tag, then try parse it next.
+ */
+ private void parseInjection(@NonNull XmlPullParser parser) {
+ parseXmlByTag(parser, false, p -> parseComponents(p), TAG_COMPONENTS);
+ }
+
+ /**
+ * Only parse the first components tag. Find the component tags, then try parse them next.
+ */
+ private void parseComponents(@NonNull XmlPullParser parser) {
+ parseXmlByTag(parser, true, p -> parseComponent(p), TAG_COMPONENT);
+ }
+
+ /**
+ * Extract text values from component tags.
+ */
+ private void parseComponent(@NonNull XmlPullParser parser) {
+ try {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.TEXT) {
+ mComponentNames.add(parser.getText());
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Rlog.e(TAG, "Failed to parse the component." , e);
+ }
+ }
+
+ /**
+ * Iterates the tags, finds the corresponding tag and then applies the consumer.
+ */
+ private void parseXmlByTag(@NonNull XmlPullParser parser, boolean allowDuplicate,
+ @NonNull Consumer<XmlPullParser> consumer, @NonNull final String tag) {
+ try {
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
+ consumer.accept(parser);
+ if (!allowDuplicate) {
+ return;
+ }
+ }
+ }
+ } catch (XmlPullParserException | IOException e) {
+ Rlog.e(TAG, "Failed to parse or find tag: " + tag, e);
+ }
+ }
+
+ /**
+ * Sets the mPackageName and mJarPath by <injection/> tag.
+ * @param parser
+ * @return
+ */
+ private void setAttributes(@NonNull XmlPullParser parser) {
+ for (int i = 0; i < parser.getAttributeCount(); i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+ if (InjectedComponents.ATTRIBUTE_PACKAGE.equals(name)) {
+ mPackageName = value;
+ } else if (InjectedComponents.ATTRIBUTE_JAR.equals(name)) {
+ mJarPath = value;
+ }
+ }
+ }
+ }
+
public static TelephonyComponentFactory getInstance() {
if (sInstance == null) {
sInstance = new TelephonyComponentFactory();
@@ -49,6 +188,46 @@
return sInstance;
}
+ /**
+ * Inject TelephonyComponentFactory using a xml config file.
+ * @param parser a nullable {@link XmlResourceParser} created with the injection config file.
+ * The config xml should has below formats:
+ * <injection package="package.InjectedTelephonyComponentFactory" jar="path to jar file">
+ * <components>
+ * <component>example.package.ComponentAbc</component>
+ * <component>example.package.ComponentXyz</component>
+ * <!-- e.g. com.android.internal.telephony.GsmCdmaPhone -->
+ * </components>
+ * </injection>
+ */
+ public void injectTheComponentFactory(XmlResourceParser parser) {
+ if (mInjectedComponents != null) {
+ Rlog.i(TAG, "Already injected.");
+ return;
+ }
+
+ if (parser != null) {
+ mInjectedComponents = new InjectedComponents();
+ mInjectedComponents.parseXml(parser);
+ mInjectedComponents.makeInjectedInstance();
+ Rlog.i(TAG, "Total components injected: "
+ + mInjectedComponents.mComponentNames.size());
+ }
+ }
+
+ /**
+ * Use the injected TelephonyComponentFactory if configured. Otherwise, use the default.
+ * @param componentName Name of the component class uses the injected component factory,
+ * e.g. GsmCdmaPhone.class.getName() for {@link GsmCdmaPhone}
+ * @return injected component factory. If not configured or injected, return the default one.
+ */
+ public TelephonyComponentFactory inject(String componentName) {
+ if (mInjectedComponents != null && mInjectedComponents.isComponentInjected(componentName)) {
+ return mInjectedComponents.mInjectedInstance;
+ }
+ return sInstance;
+ }
+
public GsmCdmaCallTracker makeGsmCdmaCallTracker(GsmCdmaPhone phone) {
return new GsmCdmaCallTracker(phone);
}
@@ -66,6 +245,13 @@
}
/**
+ * Create a new EmergencyNumberTracker.
+ */
+ public EmergencyNumberTracker makeEmergencyNumberTracker(Phone phone, CommandsInterface ci) {
+ return new EmergencyNumberTracker(phone, ci);
+ }
+
+ /**
* Sets the NitzStateMachine implementation to use during implementation. This boolean
* should be removed once the new implementation is stable.
*/
diff --git a/src/java/com/android/internal/telephony/WapPushOverSms.java b/src/java/com/android/internal/telephony/WapPushOverSms.java
index eff5c67..2e66a6d 100755
--- a/src/java/com/android/internal/telephony/WapPushOverSms.java
+++ b/src/java/com/android/internal/telephony/WapPushOverSms.java
@@ -19,6 +19,7 @@
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_DELIVERY_IND;
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_NOTIFICATION_IND;
import static com.google.android.mms.pdu.PduHeaders.MESSAGE_TYPE_READ_ORIG_IND;
+
import android.app.Activity;
import android.app.AppOpsManager;
import android.app.BroadcastOptions;
@@ -38,7 +39,6 @@
import android.os.IBinder;
import android.os.IDeviceIdleController;
import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.provider.Telephony;
@@ -51,8 +51,6 @@
import com.android.internal.telephony.uicc.IccUtils;
-import java.util.HashMap;
-
import com.google.android.mms.MmsException;
import com.google.android.mms.pdu.DeliveryInd;
import com.google.android.mms.pdu.GenericPdu;
@@ -62,6 +60,8 @@
import com.google.android.mms.pdu.PduPersister;
import com.google.android.mms.pdu.ReadOrigInd;
+import java.util.HashMap;
+
/**
* WAP push handler class.
*
@@ -133,7 +133,8 @@
public WapPushOverSms(Context context) {
mContext = context;
- mDeviceIdleController = TelephonyComponentFactory.getInstance().getIDeviceIdleController();
+ mDeviceIdleController = TelephonyComponentFactory.getInstance()
+ .inject(IDeviceIdleController.class.getName()).getIDeviceIdleController();
UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
@@ -200,9 +201,9 @@
return result;
}
}
-
WspTypeDecoder pduDecoder =
- TelephonyComponentFactory.getInstance().makeWspTypeDecoder(pdu);
+ TelephonyComponentFactory.getInstance().inject(WspTypeDecoder.class.getName())
+ .makeWspTypeDecoder(pdu);
/**
* Parse HeaderLen(unsigned integer).
diff --git a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
index 46d0243..fcea2d9 100644
--- a/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
+++ b/src/java/com/android/internal/telephony/cdma/CdmaInboundSmsHandler.java
@@ -286,8 +286,8 @@
// pass the user data portion of the PDU to the shared handler in SMSDispatcher
byte[] userData = new byte[pdu.length - index];
System.arraycopy(pdu, index, userData, 0, pdu.length - index);
-
- InboundSmsTracker tracker = TelephonyComponentFactory.getInstance().makeInboundSmsTracker(
+ InboundSmsTracker tracker = TelephonyComponentFactory.getInstance()
+ .inject(InboundSmsTracker.class.getName()).makeInboundSmsTracker(
userData, timestamp, destinationPort, true, address, dispAddr, referenceNumber,
segment, totalSegments, true, HexDump.toHexString(userData));
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcController.java b/src/java/com/android/internal/telephony/dataconnection/DcController.java
index 322b9c0..2f74ff0 100644
--- a/src/java/com/android/internal/telephony/dataconnection/DcController.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcController.java
@@ -451,7 +451,7 @@
// Cleanup connections that have changed
for (ApnContext apnContext : apnsToCleanup) {
- mDct.sendCleanUpConnection(true, apnContext);
+ mDct.cleanUpConnection(apnContext);
}
// Retry connections that have disappeared
diff --git a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
index b31da9b..ca85e33 100755
--- a/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
+++ b/src/java/com/android/internal/telephony/dataconnection/DcTracker.java
@@ -465,12 +465,6 @@
sendMessage(msg);
}
- /**
- * List of messages that are waiting to be posted, when data call disconnect
- * is complete
- */
- private ArrayList<Message> mDisconnectAllCompleteMsgList = new ArrayList<Message>();
-
private RegistrantList mAllDataDisconnectedRegistrants = new RegistrantList();
// member variables
@@ -517,10 +511,6 @@
// really a lower power mode")
private boolean mIsScreenOn = true;
- // Indicates if we found mvno-specific APNs in the full APN list.
- // used to determine if we can accept mno-specific APN for tethering.
- private boolean mMvnoMatched = false;
-
/** Allows the generation of unique Id's for DataConnection objects */
private AtomicInteger mUniqueIdGenerator = new AtomicInteger(0);
@@ -738,7 +728,7 @@
mProvisioningSpinner = null;
}
- cleanUpAllConnections(true, null);
+ cleanUpAllConnectionsInternal(true, null);
mIsDisposed = true;
mPhone.getContext().unregisterReceiver(mIntentReceiver);
@@ -793,14 +783,6 @@
private void onSetUserDataEnabled(boolean enabled) {
if (mDataEnabledSettings.isUserDataEnabled() != enabled) {
mDataEnabledSettings.setUserDataEnabled(enabled);
- if (!getDataRoamingEnabled() && mPhone.getServiceState().getDataRoaming()) {
- if (enabled) {
- notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
- } else {
- notifyOffApnsOfAvailability(Phone.REASON_DATA_DISABLED);
- }
- }
-
mPhone.notifyUserMobileDataStateChanged(enabled);
// TODO: We should register for DataEnabledSetting's data enabled/disabled event and
@@ -809,7 +791,7 @@
reevaluateDataConnections();
onTrySetupData(Phone.REASON_DATA_ENABLED);
} else {
- onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_DATA_SPECIFIC_DISABLED);
}
}
}
@@ -840,7 +822,7 @@
reevaluateDataConnections();
onTrySetupData(Phone.REASON_DATA_ENABLED);
} else {
- onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_DATA_SPECIFIC_DISABLED);
}
}
@@ -852,7 +834,7 @@
reevaluateDataConnections();
onTrySetupData(Phone.REASON_DATA_ENABLED);
} else {
- onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_DATA_SPECIFIC_DISABLED);
}
}
@@ -1516,17 +1498,33 @@
}
/**
- * If tearDown is true, this only tears down a CONNECTED session. Presently,
- * there is no mechanism for abandoning an CONNECTING session,
- * but would likely involve cancelling pending async requests or
- * setting a flag or new state to ignore them when they came in
- * @param tearDown true if the underlying DataConnection should be
- * disconnected.
+ * Clean up all data connections. Note this is just detach the APN context from the data
+ * connection. After all APN contexts are detached from the data connection, the data
+ * connection will be torn down.
+ *
+ * @param reason Reason for the clean up.
+ */
+ public void cleanUpAllConnections(String reason) {
+ log("cleanUpAllConnections");
+ Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
+ msg.obj = reason;
+ sendMessage(msg);
+ }
+
+ /**
+ * Clean up all data connections by detaching the APN contexts from the data connections, which
+ * eventually tearing down all data connections after all APN contexts are detached from the
+ * data connections.
+ *
+ * @param tearDown True if the underlying data connection should be disconnected when no
+ * APN context attached to the data connection. False if we only want to reset the data
+ * connection's state machine without requesting modem to tearing down the data connections.
+ *
* @param reason reason for the clean up.
* @return boolean - true if we did cleanup any connections, false if they
* were already all disconnected.
*/
- private boolean cleanUpAllConnections(boolean tearDown, String reason) {
+ private boolean cleanUpAllConnectionsInternal(boolean tearDown, String reason) {
if (DBG) log("cleanUpAllConnections: tearDown=" + tearDown + " reason=" + reason);
boolean didDisconnect = false;
boolean disableMeteredOnly = false;
@@ -1548,7 +1546,7 @@
if (apnContext.isDisconnected() == false) didDisconnect = true;
if (DBG) log("clean up metered ApnContext Type: " + apnContext.getApnType());
apnContext.setReason(reason);
- cleanUpConnection(tearDown, apnContext);
+ cleanUpConnectionInternal(tearDown, apnContext);
}
} else {
// Exclude the IMS APN from single DataConenction case.
@@ -1559,7 +1557,7 @@
// TODO - only do cleanup if not disconnected
if (apnContext.isDisconnected() == false) didDisconnect = true;
apnContext.setReason(reason);
- cleanUpConnection(tearDown, apnContext);
+ cleanUpConnectionInternal(tearDown, apnContext);
}
}
@@ -1569,9 +1567,8 @@
// TODO: Do we need mRequestedApnType?
mRequestedApnType = ApnSetting.TYPE_DEFAULT;
- log("cleanUpConnection: mDisconnectPendingCount = " + mDisconnectPendingCount);
+ log("cleanUpConnectionInternal: mDisconnectPendingCount = " + mDisconnectPendingCount);
if (tearDown && mDisconnectPendingCount == 0) {
- notifyDataDisconnectComplete();
notifyAllDataDisconnected();
}
@@ -1579,36 +1576,36 @@
}
/**
- * Cleanup all connections.
+ * Detach the APN context from the associated data connection. This data connection might be
+ * torn down if no other APN context is attached to it.
*
- * TODO: Cleanup only a specified connection passed as a parameter.
- * Also, make sure when you clean up a conn, if it is last apply
- * logic as though it is cleanupAllConnections
- *
- * @param cause for the clean up.
+ * @param apnContext The APN context to be detached
*/
- private void onCleanUpAllConnections(String cause) {
- cleanUpAllConnections(true, cause);
- }
-
- void sendCleanUpConnection(boolean tearDown, ApnContext apnContext) {
- if (DBG) log("sendCleanUpConnection: tearDown=" + tearDown + " apnContext=" + apnContext);
+ void cleanUpConnection(ApnContext apnContext) {
+ if (DBG) log("cleanUpConnection: apnContext=" + apnContext);
Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_CONNECTION);
- msg.arg1 = tearDown ? 1 : 0;
msg.arg2 = 0;
msg.obj = apnContext;
sendMessage(msg);
}
- private void cleanUpConnection(boolean tearDown, ApnContext apnContext) {
+ /**
+ * Detach the APN context from the associated data connection. This data connection might be
+ * torn down if no other APN context is attached to it.
+ *
+ * @param tearDown True if tearing down data connection when no other APN context attached.
+ * False to only reset the data connection's state machine.
+ * @param apnContext The APN context to be detached
+ */
+ private void cleanUpConnectionInternal(boolean tearDown, ApnContext apnContext) {
if (apnContext == null) {
- if (DBG) log("cleanUpConnection: apn context is null");
+ if (DBG) log("cleanUpConnectionInternal: apn context is null");
return;
}
DataConnection dataConnection = apnContext.getDataConnection();
- String str = "cleanUpConnection: tearDown=" + tearDown + " reason=" +
- apnContext.getReason();
+ String str = "cleanUpConnectionInternal: tearDown=" + tearDown + " reason="
+ + apnContext.getReason();
if (VDBG) log(str + " apnContext=" + apnContext);
apnContext.requestLog(str);
if (tearDown) {
@@ -1618,7 +1615,7 @@
apnContext.setState(DctConstants.State.IDLE);
if (!apnContext.isReady()) {
if (dataConnection != null) {
- str = "cleanUpConnection: teardown, disconnected, !ready";
+ str = "cleanUpConnectionInternal: teardown, disconnected, !ready";
if (DBG) log(str + " apnContext=" + apnContext);
apnContext.requestLog(str);
dataConnection.tearDown(apnContext, "", null);
@@ -1635,7 +1632,7 @@
// if (PhoneConstants.APN_TYPE_DUN.equals(PhoneConstants.APN_TYPE_DEFAULT)) {
if (teardownForDun()) {
if (DBG) {
- log("cleanUpConnection: disconnectAll DUN connection");
+ log("cleanUpConnectionInternal: disconnectAll DUN connection");
}
// we need to tear it down - we brought it up just for dun and
// other people are camped on it and now dun is done. We need
@@ -1645,12 +1642,11 @@
}
}
final int generation = apnContext.getConnectionGeneration();
- str = "cleanUpConnection: tearing down" + (disconnectAll ? " all" : "") +
- " using gen#" + generation;
+ str = "cleanUpConnectionInternal: tearing down"
+ + (disconnectAll ? " all" : "") + " using gen#" + generation;
if (DBG) log(str + "apnContext=" + apnContext);
apnContext.requestLog(str);
- Pair<ApnContext, Integer> pair =
- new Pair<ApnContext, Integer>(apnContext, generation);
+ Pair<ApnContext, Integer> pair = new Pair<>(apnContext, generation);
Message msg = obtainMessage(DctConstants.EVENT_DISCONNECT_DONE, pair);
if (disconnectAll) {
@@ -1666,7 +1662,7 @@
// apn is connected but no reference to the data connection.
// Should not be happen, but reset the state in case.
apnContext.setState(DctConstants.State.IDLE);
- apnContext.requestLog("cleanUpConnection: connected, bug no dc");
+ apnContext.requestLog("cleanUpConnectionInternal: connected, bug no dc");
mPhone.notifyDataConnection(apnContext.getReason(),
apnContext.getApnType());
}
@@ -1684,7 +1680,8 @@
if (dataConnection != null) {
cancelReconnectAlarm(apnContext);
}
- str = "cleanUpConnection: X tearDown=" + tearDown + " reason=" + apnContext.getReason();
+ str = "cleanUpConnectionInternal: X tearDown=" + tearDown + " reason="
+ + apnContext.getReason();
if (DBG) log(str + " apnContext=" + apnContext + " dc=" + apnContext.getDataConnection());
apnContext.requestLog(str);
}
@@ -1700,8 +1697,6 @@
return new ArrayList<ApnSetting>(0);
}
int bearer = mPhone.getServiceState().getRilDataRadioTechnology();
- IccRecords r = mIccRecords.get();
- String operator = (r != null) ? r.getOperatorNumeric() : "";
ArrayList<ApnSetting> dunCandidates = new ArrayList<ApnSetting>();
ArrayList<ApnSetting> retDunSettings = new ArrayList<ApnSetting>();
@@ -1729,16 +1724,7 @@
ServiceState.rilRadioTechnologyToNetworkType(bearer))) {
continue;
}
- if (dunSetting.getOperatorNumeric().equals(operator)) {
- if (dunSetting.hasMvnoParams()) {
- if (r != null && ApnSettingUtils.mvnoMatches(r, dunSetting.getMvnoType(),
- dunSetting.getMvnoMatchData())) {
- retDunSettings.add(dunSetting);
- }
- } else if (mMvnoMatched == false) {
- retDunSettings.add(dunSetting);
- }
- }
+ retDunSettings.add(dunSetting);
}
if (VDBG) log("fetchDunApns: dunSettings=" + retDunSettings);
@@ -1811,41 +1797,6 @@
(mAttached.get() == false || dcFailCause != DcFailCause.SIGNAL_LOST));
}
- private ArrayList<ApnSetting> createApnList(Cursor cursor) {
- ArrayList<ApnSetting> mnoApns = new ArrayList<ApnSetting>();
- ArrayList<ApnSetting> mvnoApns = new ArrayList<ApnSetting>();
- IccRecords r = mIccRecords.get();
-
- if (cursor.moveToFirst()) {
- do {
- ApnSetting apn = ApnSetting.makeApnSetting(cursor);
- if (apn == null) {
- continue;
- }
-
- if (apn.hasMvnoParams()) {
- if (r != null && ApnSettingUtils.mvnoMatches(r, apn.getMvnoType(),
- apn.getMvnoMatchData())) {
- mvnoApns.add(apn);
- }
- } else {
- mnoApns.add(apn);
- }
- } while (cursor.moveToNext());
- }
-
- ArrayList<ApnSetting> result;
- if (mvnoApns.isEmpty()) {
- result = mnoApns;
- mMvnoMatched = false;
- } else {
- result = mvnoApns;
- mMvnoMatched = true;
- }
- if (DBG) log("createApnList: X result=" + result);
- return result;
- }
-
private DataConnection findFreeDataConnection() {
for (DataConnection dataConnection : mDataConnections.values()) {
boolean inUse = false;
@@ -1924,7 +1875,7 @@
// Only lower priority calls left. Disconnect them all in this single PDP case
// so that we can bring up the requested higher priority call (once we receive
// response for deactivate request for the calls we are about to disconnect
- if (cleanUpAllConnections(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
+ if (cleanUpAllConnectionsInternal(true, Phone.REASON_SINGLE_PDN_ARBITRATION)) {
// If any call actually requested to be disconnected, means we can't
// bring up this connection yet as we need to wait for those data calls
// to be disconnected.
@@ -2123,7 +2074,7 @@
private void restartRadio() {
if (DBG) log("restartRadio: ************TURN OFF RADIO**************");
- cleanUpAllConnections(true, Phone.REASON_RADIO_TURNED_OFF);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_RADIO_TURNED_OFF);
mPhone.getServiceStateTracker().powerOffRadioSafely();
/* Note: no need to call setRadioPower(true). Assuming the desired
* radio power state is still ON (as tracked by ServiceStateTracker),
@@ -2229,15 +2180,10 @@
mDataEnabledSettings.setCarrierDataEnabled(enabled);
if (!enabled) {
- // Send otasp_sim_unprovisioned so that SuW is able to proceed and notify users
- mPhone.notifyOtaspChanged(TelephonyManager.OTASP_SIM_UNPROVISIONED);
// Tear down all metered apns
- cleanUpAllConnections(true, Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
+ cleanUpAllConnectionsInternal(true,
+ Phone.REASON_CARRIER_ACTION_DISABLE_METERED_APN);
} else {
- // Re-evaluate Otasp state
- int otaspState = mPhone.getServiceStateTracker().getOtasp();
- mPhone.notifyOtaspChanged(otaspState);
-
reevaluateDataConnections();
setupDataOnConnectableApns(Phone.REASON_DATA_ENABLED);
}
@@ -2247,7 +2193,7 @@
private void onSimNotReady() {
if (DBG) log("onSimNotReady");
- cleanUpAllConnections(true, Phone.REASON_SIM_NOT_READY);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_SIM_NOT_READY);
mAllApnSettings.clear();
mAutoAttachOnCreationConfig = false;
// Clear auto attach as modem is expected to do a new attach once SIM is ready
@@ -2277,7 +2223,7 @@
reevaluateDataConnections();
onTrySetupData(Phone.REASON_DATA_ENABLED);
} else {
- onCleanUpAllConnections(Phone.REASON_DATA_SPECIFIC_DISABLED);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_DATA_SPECIFIC_DISABLED);
}
}
}
@@ -2355,7 +2301,7 @@
}
apnContext.setEnabled(enabled);
apnContext.setDependencyMet(met);
- if (cleanup) cleanUpConnection(true, apnContext);
+ if (cleanup) cleanUpConnectionInternal(true, apnContext);
if (trySetup) {
apnContext.resetErrorCodeRetries();
trySetupData(apnContext);
@@ -2669,7 +2615,7 @@
// roaming, we need to tear down the data connection otherwise the user might be
// charged for data roaming usage.
if (DBG) log("onDataRoamingOnOrSettingsChanged: Tear down data connection on roaming.");
- cleanUpAllConnections(true, Phone.REASON_ROAMING_ON);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_ROAMING_ON);
notifyOffApnsOfAvailability(Phone.REASON_ROAMING_ON);
}
}
@@ -2707,7 +2653,7 @@
}
if (getOverallState() != DctConstants.State.IDLE) {
- cleanUpConnection(true, null);
+ cleanUpConnectionInternal(true, null);
}
}
@@ -2726,7 +2672,7 @@
log("We're on the simulator; assuming radio off is meaningless");
} else {
if (DBG) log("onRadioOffOrNotAvailable: is off and clean up all connections");
- cleanUpAllConnections(false, Phone.REASON_RADIO_TURNED_OFF);
+ cleanUpAllConnectionsInternal(false, Phone.REASON_RADIO_TURNED_OFF);
}
notifyOffApnsOfAvailability(null);
}
@@ -2958,7 +2904,7 @@
* to clean data connections.
*/
if (!mDataEnabledSettings.isInternalDataEnabled()) {
- cleanUpAllConnections(Phone.REASON_DATA_DISABLED);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_DATA_DISABLED);
}
}
@@ -3058,7 +3004,6 @@
}
if (mDisconnectPendingCount == 0) {
- notifyDataDisconnectComplete();
notifyAllDataDisconnected();
}
return;
@@ -3105,7 +3050,6 @@
if (mDisconnectPendingCount == 0) {
apnContext.setConcurrentVoiceAndDataAllowed(
mPhone.getServiceStateTracker().isConcurrentVoiceAndDataAllowed());
- notifyDataDisconnectComplete();
notifyAllDataDisconnected();
}
@@ -3158,7 +3102,7 @@
ApnContext apnContext = mApnContextsByType.get(apnType);
if (apnContext != null) {
apnContext.setReason(reason);
- cleanUpConnection(tearDown, apnContext);
+ cleanUpConnectionInternal(tearDown, apnContext);
}
}
@@ -3224,34 +3168,28 @@
* Data Connections and setup the preferredApn.
*/
private void createAllApnList() {
- mMvnoMatched = false;
mAllApnSettings.clear();
IccRecords r = mIccRecords.get();
String operator = (r != null) ? r.getOperatorNumeric() : "";
- if (operator != null) {
- String selection = Telephony.Carriers.NUMERIC + " = '" + operator + "'";
- // query only enabled apn.
- // carrier_enabled : 1 means enabled apn, 0 disabled apn.
- // selection += " and carrier_enabled = 1";
- if (DBG) log("createAllApnList: selection=" + selection);
- // ORDER BY Telephony.Carriers._ID ("_id")
- Cursor cursor = mPhone.getContext().getContentResolver().query(
- Uri.withAppendedPath(Telephony.Carriers.CONTENT_URI, "filtered"),
- null, selection, null, Telephony.Carriers._ID);
+ // ORDER BY Telephony.Carriers._ID ("_id")
+ Cursor cursor = mPhone.getContext().getContentResolver().query(
+ Uri.withAppendedPath(Telephony.Carriers.SIM_APN_LIST, "filtered/subId/"
+ + mPhone.getSubId()), null, null, null, Telephony.Carriers._ID);
- if (cursor != null) {
- if (cursor.getCount() > 0) {
- mAllApnSettings = createApnList(cursor);
- } else {
- if (DBG) log("createAllApnList: cursor count is 0");
- mApnSettingsInitializationLog.log("no APN in db for carrier: " + operator);
+ if (cursor != null) {
+ while (cursor.moveToNext()) {
+ ApnSetting apn = ApnSetting.makeApnSetting(cursor);
+ if (apn == null) {
+ continue;
}
- cursor.close();
- } else {
- if (DBG) log("createAllApnList: cursor is null");
- mApnSettingsInitializationLog.log("cursor is null for carrier: " + operator);
+ mAllApnSettings.add(apn);
}
+ cursor.close();
+ } else {
+ if (DBG) log("createAllApnList: cursor is null");
+ mApnSettingsInitializationLog.log("cursor is null for carrier, operator: "
+ + operator);
}
addEmergencyApnSetting();
@@ -3259,8 +3197,9 @@
dedupeApnSettings();
if (mAllApnSettings.isEmpty()) {
- if (DBG) log("createAllApnList: No APN found for carrier: " + operator);
- mApnSettingsInitializationLog.log("no APN found for carrier: " + operator);
+ log("createAllApnList: No APN found for carrier, operator: " + operator);
+ mApnSettingsInitializationLog.log("no APN found for carrier, operator: "
+ + operator);
mPreferredApn = null;
// TODO: What is the right behavior?
//notifyNoData(DataConnection.FailCause.MISSING_UNKNOWN_APN);
@@ -3613,7 +3552,7 @@
} else {
// TODO: Should all PDN states be checked to fail?
if (mState == DctConstants.State.FAILED) {
- cleanUpAllConnections(false, Phone.REASON_PS_RESTRICT_ENABLED);
+ cleanUpAllConnectionsInternal(false, Phone.REASON_PS_RESTRICT_ENABLED);
mReregisterOnReconnectFailure = false;
}
ApnContext apnContext = mApnContextsByType.get(ApnSetting.TYPE_DEFAULT);
@@ -3640,24 +3579,19 @@
break;
case DctConstants.EVENT_CLEAN_UP_CONNECTION:
- boolean tearDown = (msg.arg1 == 0) ? false : true;
- if (DBG) log("EVENT_CLEAN_UP_CONNECTION tearDown=" + tearDown);
- if (msg.obj instanceof ApnContext) {
- cleanUpConnection(tearDown, (ApnContext)msg.obj);
- } else {
- onCleanUpConnection(tearDown, msg.arg2, (String) msg.obj);
- }
+ if (DBG) log("EVENT_CLEAN_UP_CONNECTION");
+ cleanUpConnectionInternal(true, (ApnContext) msg.obj);
break;
case DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE: {
final boolean enabled = (msg.arg1 == DctConstants.ENABLED) ? true : false;
- onSetInternalDataEnabled(enabled, (Message) msg.obj);
+ onSetInternalDataEnabled(enabled);
break;
}
case DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS:
if ((msg.obj != null) && (msg.obj instanceof String == false)) {
msg.obj = null;
}
- onCleanUpAllConnections((String) msg.obj);
+ cleanUpAllConnectionsInternal(true, (String) msg.obj);
break;
case DctConstants.EVENT_DATA_RAT_CHANGED:
@@ -3824,7 +3758,7 @@
mIsProvisioning = false;
mProvisioningUrl = null;
stopProvisioningApnAlarm();
- sendCleanUpConnection(true, apnCtx);
+ cleanUpConnectionInternal(true, apnCtx);
} else {
if (DBG) {
log("EVENT_PROVISIONING_APN_ALARM: ignore stale tag,"
@@ -3959,6 +3893,11 @@
}
}
+ /**
+ * Update DcTracker.
+ *
+ * TODO: This should be cleaned up. DcTracker should listen to those events.
+ */
public void update() {
log("update sub = " + mPhone.getSubId());
log("update(): Active DDS, register for all events now!");
@@ -3966,33 +3905,9 @@
mAutoAttachOnCreation.set(false);
- ((GsmCdmaPhone)mPhone).updateCurrentCarrierInProvider();
+ mPhone.updateCurrentCarrierInProvider();
}
- public void cleanUpAllConnections(String cause) {
- cleanUpAllConnections(cause, null);
- }
-
- public void cleanUpAllConnections(String cause, Message disconnectAllCompleteMsg) {
- log("cleanUpAllConnections");
- if (disconnectAllCompleteMsg != null) {
- mDisconnectAllCompleteMsgList.add(disconnectAllCompleteMsg);
- }
-
- Message msg = obtainMessage(DctConstants.EVENT_CLEAN_UP_ALL_CONNECTIONS);
- msg.obj = cause;
- sendMessage(msg);
- }
-
- private void notifyDataDisconnectComplete() {
- log("notifyDataDisconnectComplete");
- for (Message m: mDisconnectAllCompleteMsgList) {
- m.sendToTarget();
- }
- mDisconnectAllCompleteMsgList.clear();
- }
-
-
private void notifyAllDataDisconnected() {
sEnableFailFastRefCounter = 0;
mFailFast = false;
@@ -4020,35 +3935,22 @@
mDataEnabledSettings.unregisterForDataEnabledChanged(h);
}
- private void onSetInternalDataEnabled(boolean enabled, Message onCompleteMsg) {
+ private void onSetInternalDataEnabled(boolean enabled) {
if (DBG) log("onSetInternalDataEnabled: enabled=" + enabled);
- boolean sendOnComplete = true;
-
mDataEnabledSettings.setInternalDataEnabled(enabled);
if (enabled) {
log("onSetInternalDataEnabled: changed to enabled, try to setup data call");
onTrySetupData(Phone.REASON_DATA_ENABLED);
} else {
- sendOnComplete = false;
log("onSetInternalDataEnabled: changed to disabled, cleanUpAllConnections");
- cleanUpAllConnections(Phone.REASON_DATA_DISABLED, onCompleteMsg);
- }
-
- if (sendOnComplete) {
- if (onCompleteMsg != null) {
- onCompleteMsg.sendToTarget();
- }
+ cleanUpAllConnectionsInternal(true, Phone.REASON_DATA_DISABLED);
}
}
public boolean setInternalDataEnabled(boolean enable) {
- return setInternalDataEnabled(enable, null);
- }
-
- public boolean setInternalDataEnabled(boolean enable, Message onCompleteMsg) {
if (DBG) log("setInternalDataEnabled(" + enable + ")");
- Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE, onCompleteMsg);
+ Message msg = obtainMessage(DctConstants.EVENT_SET_INTERNAL_DATA_ENABLE);
msg.arg1 = (enable ? DctConstants.ENABLED : DctConstants.DISABLED);
sendMessage(msg);
return true;
@@ -4258,7 +4160,7 @@
private void cleanUpConnectionsOnUpdatedApns(boolean tearDown, String reason) {
if (DBG) log("cleanUpConnectionsOnUpdatedApns: tearDown=" + tearDown);
if (mAllApnSettings.isEmpty()) {
- cleanUpAllConnections(tearDown, Phone.REASON_APN_CHANGED);
+ cleanUpAllConnectionsInternal(tearDown, Phone.REASON_APN_CHANGED);
} else {
int radioTech = mPhone.getServiceState().getRilDataRadioTechnology();
if (radioTech == ServiceState.RIL_RADIO_TECHNOLOGY_UNKNOWN) {
@@ -4284,7 +4186,7 @@
if (!apnContext.isDisconnected()) {
if (VDBG) log("cleanUpConnectionsOnUpdatedApns for " + apnContext);
apnContext.setReason(reason);
- cleanUpConnection(true, apnContext);
+ cleanUpConnectionInternal(true, apnContext);
}
}
}
@@ -4299,7 +4201,6 @@
if (DBG) log("mDisconnectPendingCount = " + mDisconnectPendingCount);
if (tearDown && mDisconnectPendingCount == 0) {
- notifyDataDisconnectComplete();
notifyAllDataDisconnected();
}
}
@@ -4519,7 +4420,7 @@
EventLog.writeEvent(EventLogTags.DATA_STALL_RECOVERY_CLEANUP,
mSentSinceLastRecv);
if (DBG) log("doRecovery() cleanup all connections");
- cleanUpAllConnections(Phone.REASON_PDP_RESET);
+ cleanUpAllConnectionsInternal(true, Phone.REASON_PDP_RESET);
putRecoveryAction(RecoveryAction.REREGISTER);
break;
case RecoveryAction.REREGISTER:
diff --git a/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
new file mode 100644
index 0000000..5425f2b
--- /dev/null
+++ b/src/java/com/android/internal/telephony/emergency/EmergencyNumberTracker.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright (C) 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.emergency;
+
+import android.os.AsyncResult;
+import android.os.Handler;
+import android.os.Message;
+import android.telephony.Rlog;
+import android.telephony.emergency.EmergencyNumber;
+import android.util.LocalLog;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.CommandsInterface;
+import com.android.internal.telephony.Phone;
+import com.android.internal.util.IndentingPrintWriter;
+import com.android.phone.ecc.nano.ProtobufEccData;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Emergency Number Tracker that handles update of emergency number list from RIL and emergency
+ * number database. This is multi-sim based and each Phone has a EmergencyNumberTracker.
+ */
+public class EmergencyNumberTracker extends Handler {
+ private static final String TAG = EmergencyNumberTracker.class.getSimpleName();
+
+ /** @hide */
+ public static boolean DBG = false;
+
+ private final CommandsInterface mCi;
+ private final Phone mPhone;
+ private List<EmergencyNumber> mEmergencyNumberListFromDatabase = new ArrayList<>();
+ private List<EmergencyNumber> mEmergencyNumberListFromRadio = new ArrayList<>();
+ private List<EmergencyNumber> mEmergencyNumberList = new ArrayList<>();
+
+ private final LocalLog mEmergencyNumberListDatabaseLocalLog = new LocalLog(20);
+ private final LocalLog mEmergencyNumberListRadioLocalLog = new LocalLog(20);
+ private final LocalLog mEmergencyNumberListLocalLog = new LocalLog(20);
+
+ /** Event indicating the update for the emergency number list from the radio. */
+ private static final int EVENT_UNSOL_EMERGENCY_NUMBER_LIST = 1;
+
+ // TODO EVENT_UPDATE_NETWORK_COUNTRY_ISO
+
+ public EmergencyNumberTracker(Phone phone, CommandsInterface ci) {
+ mPhone = phone;
+ mCi = ci;
+ // TODO cache Emergency Number List Database per country ISO;
+ // TODO register for Locale Tracker Country ISO Change
+ mCi.registerForEmergencyNumberList(this, EVENT_UNSOL_EMERGENCY_NUMBER_LIST, null);
+ }
+
+ /**
+ * Message handler for updating emergency number list from RIL, updating emergency number list
+ * from database if the country ISO is changed, and notifying the change of emergency number
+ * list.
+ *
+ * @param msg The message
+ */
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_UNSOL_EMERGENCY_NUMBER_LIST:
+ AsyncResult ar = (AsyncResult) msg.obj;
+ if (ar.result == null) {
+ loge("EVENT_UNSOL_EMERGENCY_NUMBER_LIST: Result from RIL is null.");
+ } else if ((ar.result != null) && (ar.exception == null)) {
+ updateAndNotifyEmergencyNumberList((List<EmergencyNumber>) ar.result);
+ } else {
+ loge("EVENT_UNSOL_EMERGENCY_NUMBER_LIST: Exception from RIL : "
+ + ar.exception);
+ }
+ break;
+ }
+ }
+
+ private void updateAndNotifyEmergencyNumberList(
+ List<EmergencyNumber> emergencyNumberListRadio) {
+ Collections.sort(emergencyNumberListRadio);
+ logd("updateAndNotifyEmergencyNumberList(): receiving " + emergencyNumberListRadio);
+
+ if (!emergencyNumberListRadio.equals(mEmergencyNumberListFromRadio)) {
+ try {
+ mEmergencyNumberListFromRadio = emergencyNumberListRadio;
+ if (!DBG) {
+ mEmergencyNumberListRadioLocalLog.log("updateRadioEmergencyNumberList:"
+ + emergencyNumberListRadio);
+ }
+ List<EmergencyNumber> emergencyNumberListMergedWithDatabase =
+ constructEmergencyNumberListWithDatabase();
+ mEmergencyNumberList = emergencyNumberListMergedWithDatabase;
+ if (!DBG) {
+ mEmergencyNumberListLocalLog.log("updateEmergencyNumberList:"
+ + emergencyNumberListMergedWithDatabase);
+ }
+ notifyEmergencyNumberList();
+ } catch (NullPointerException ex) {
+ loge("updateAndNotifyEmergencyNumberList() Phone already destroyed: " + ex
+ + "EmergencyNumberList not notified");
+ }
+ }
+ }
+
+ private void notifyEmergencyNumberList() {
+ List<EmergencyNumber> emergencyNumberListToNotify = getEmergencyNumberList();
+ mPhone.notifyEmergencyNumberList(emergencyNumberListToNotify);
+ logd("notifyEmergencyNumberList():" + emergencyNumberListToNotify);
+ }
+
+ private List<EmergencyNumber> constructEmergencyNumberListWithDatabase() {
+ List<EmergencyNumber> emergencyNumberListRadioAndDatabase = mEmergencyNumberListFromRadio;
+ // TODO integrate with emergency number database
+ // TODO sorting
+ return emergencyNumberListRadioAndDatabase;
+ }
+
+ public List<EmergencyNumber> getEmergencyNumberList() {
+ return new ArrayList<>(mEmergencyNumberList);
+ }
+
+ @VisibleForTesting
+ public List<EmergencyNumber> getRadioEmergencyNumberList() {
+ return new ArrayList<>(mEmergencyNumberListFromRadio);
+ }
+
+ private static void logd(String str) {
+ Rlog.d(TAG, str);
+ }
+
+ private static void loge(String str) {
+ Rlog.e(TAG, str);
+ }
+
+ /**
+ * Dump Emergency Number List info in the tracking
+ *
+ * @param fd FileDescriptor
+ * @param pw PrintWriter
+ * @param args args
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ");
+ ipw.println("mEmergencyNumberListDatabaseLocalLog:");
+ ipw.increaseIndent();
+ mEmergencyNumberListDatabaseLocalLog.dump(fd, pw, args);
+ ipw.decreaseIndent();
+ ipw.println(" - - - - - - - -");
+
+ ipw.println("mEmergencyNumberListRadioLocalLog:");
+ ipw.increaseIndent();
+ mEmergencyNumberListRadioLocalLog.dump(fd, pw, args);
+ ipw.decreaseIndent();
+ ipw.println(" - - - - - - - -");
+
+ ipw.println("mEmergencyNumberListLocalLog:");
+ ipw.increaseIndent();
+ mEmergencyNumberListLocalLog.dump(fd, pw, args);
+ ipw.decreaseIndent();
+
+ ipw.flush();
+ }
+}
diff --git a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
index ea5f671..ab39212 100644
--- a/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
+++ b/src/java/com/android/internal/telephony/imsphone/ImsPhone.java
@@ -256,8 +256,11 @@
// setting the multiendpoint listener on the external call tracker. So we need to ensure
// the external call tracker is available first to avoid potential timing issues.
mExternalCallTracker =
- TelephonyComponentFactory.getInstance().makeImsExternalCallTracker(this);
- mCT = TelephonyComponentFactory.getInstance().makeImsPhoneCallTracker(this);
+ TelephonyComponentFactory.getInstance()
+ .inject(ImsExternalCallTracker.class.getName())
+ .makeImsExternalCallTracker(this);
+ mCT = TelephonyComponentFactory.getInstance().inject(ImsPhoneCallTracker.class.getName())
+ .makeImsPhoneCallTracker(this);
mCT.registerPhoneStateListener(mExternalCallTracker);
mExternalCallTracker.setCallPuller(mCT);
diff --git a/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java b/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
index 8001eb6..f8d519c 100644
--- a/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/ModemPowerMetrics.java
@@ -60,9 +60,16 @@
m.rxTimeMs = stats.getRxTimeMs();
long[] t = stats.getTxTimeMs();
m.txTimeMs = new long[t.length];
- for (int i = 0; i < t.length; i++) {
- m.txTimeMs[i] = t[i];
- }
+ System.arraycopy(t, 0, m.txTimeMs, 0, t.length);
+ m.numBytesTx = stats.getNumBytesTx();
+ m.numPacketsRx = stats.getNumPacketsRx();
+ m.numBytesRx = stats.getNumBytesRx();
+ long[] tr = stats.getTimeInRatMs();
+ m.timeInRatMs = new long[tr.length];
+ System.arraycopy(tr, 0, m.timeInRatMs, 0, tr.length);
+ long[] trx = stats.getTimeInRxSignalStrengthLevelMs();
+ m.timeInRxSignalStrengthLevelMs = new long[trx.length];
+ System.arraycopy(trx, 0, m.timeInRxSignalStrengthLevelMs, 0, trx.length);
}
return m;
}
diff --git a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
index c01ea78..97a6817 100644
--- a/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
+++ b/src/java/com/android/internal/telephony/metrics/TelephonyMetrics.java
@@ -433,14 +433,22 @@
pw.println("Power log duration (battery time) (ms): " + s.loggingDurationMs);
pw.println("Energy consumed by modem (mAh): " + s.energyConsumedMah);
pw.println("Number of packets sent (tx): " + s.numPacketsTx);
- pw.println("Amount of time kernel is active because of cellular data (ms): " +
- s.cellularKernelActiveTimeMs);
- pw.println("Amount of time spent in very poor rx signal level (ms): " +
- s.timeInVeryPoorRxSignalLevelMs);
+ pw.println("Number of bytes sent (tx): " + s.numBytesTx);
+ pw.println("Number of packets received (rx): " + s.numPacketsRx);
+ pw.println("Number of bytes received (rx): " + s.numBytesRx);
+ pw.println("Amount of time kernel is active because of cellular data (ms): "
+ + s.cellularKernelActiveTimeMs);
+ pw.println("Amount of time spent in very poor rx signal level (ms): "
+ + s.timeInVeryPoorRxSignalLevelMs);
pw.println("Amount of time modem is in sleep (ms): " + s.sleepTimeMs);
pw.println("Amount of time modem is in idle (ms): " + s.idleTimeMs);
pw.println("Amount of time modem is in rx (ms): " + s.rxTimeMs);
pw.println("Amount of time modem is in tx (ms): " + Arrays.toString(s.txTimeMs));
+ pw.println("Amount of time phone spent in various Radio Access Technologies (ms): "
+ + Arrays.toString(s.timeInRatMs));
+ pw.println("Amount of time phone spent in various cellular "
+ + "rx signal strength levels (ms): "
+ + Arrays.toString(s.timeInRxSignalStrengthLevelMs));
pw.decreaseIndent();
}
diff --git a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
index 4460489..5cb130b 100644
--- a/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
+++ b/src/java/com/android/internal/telephony/test/SimulatedCommandsVerifier.java
@@ -1422,6 +1422,14 @@
}
@Override
+ public void registerForEmergencyNumberList(Handler h, int what, Object obj) {
+ }
+
+ @Override
+ public void unregisterForEmergencyNumberList(Handler h) {
+ }
+
+ @Override
public void startNattKeepalive(
int contextId, KeepalivePacketData packetData, int intervalMillis, Message result) {
}
diff --git a/src/java/com/android/internal/telephony/uicc/UiccCard.java b/src/java/com/android/internal/telephony/uicc/UiccCard.java
index aae7874..2cf19f9 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccCard.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccCard.java
@@ -85,7 +85,8 @@
if (mCardState != CardState.CARDSTATE_ABSENT) {
if (mUiccProfile == null) {
- mUiccProfile = TelephonyComponentFactory.getInstance().makeUiccProfile(
+ mUiccProfile = TelephonyComponentFactory.getInstance()
+ .inject(UiccProfile.class.getName()).makeUiccProfile(
mContext, mCi, ics, mPhoneId, this, mLock);
} else {
mUiccProfile.update(mContext, mCi, ics);
diff --git a/src/java/com/android/internal/telephony/uicc/UiccProfile.java b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
index ce4a5ef..7215f51 100644
--- a/src/java/com/android/internal/telephony/uicc/UiccProfile.java
+++ b/src/java/com/android/internal/telephony/uicc/UiccProfile.java
@@ -824,6 +824,16 @@
}
@Override
+ public boolean isEmptyProfile() {
+ // If there's no UiccCardApplication, it's an empty profile.
+ // Empty profile is a valid case of eSIM (default boot profile).
+ for (UiccCardApplication app : mUiccApplications) {
+ if (app != null) return false;
+ }
+ return true;
+ }
+
+ @Override
public void setIccLockEnabled(boolean enabled, String password, Message onComplete) {
synchronized (mLock) {
if (mUiccApplication != null) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
index b2ee494..c604cf0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CellularNetworkServiceTest.java
@@ -157,7 +157,7 @@
expectedState = new NetworkRegistrationState(
domain, AccessNetworkConstants.TransportType.WWAN, voiceRegState,
ServiceState.rilRadioTechnologyToNetworkType(voiceRadioTech), reasonForDenial,
- false, availableServices, null, maxDataCalls, false, false);
+ false, availableServices, null, maxDataCalls, false, false, false);
try {
verify(mCallback, times(1)).onGetNetworkRegistrationStateComplete(
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
index 1f883b8..1f2124b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DeviceStateMonitorTest.java
@@ -20,6 +20,7 @@
import static com.android.internal.telephony.TelephonyTestUtils.waitForMs;
+import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.times;
@@ -33,14 +34,14 @@
import android.os.HandlerThread;
import android.os.Message;
import android.support.test.filters.FlakyTest;
+import android.test.suitebuilder.annotation.MediumTest;
import org.junit.After;
import org.junit.Before;
-import org.junit.Ignore;
+import org.junit.Test;
import java.util.ArrayList;
-@Ignore
public class DeviceStateMonitorTest extends TelephonyTest {
private DeviceStateMonitor mDSM;
@@ -132,4 +133,41 @@
verify(mSimulatedCommandsVerifier, times(1)).setUnsolResponseFilter(eq(-1),
nullable(Message.class));
}
+
+ private void sendStates(int screenState, int chargingState, int wifiState) {
+ setReady(false);
+ mDSM.obtainMessage(
+ DeviceStateMonitor.EVENT_SCREEN_STATE_CHANGED, screenState, 0).sendToTarget();
+ mDSM.obtainMessage(
+ DeviceStateMonitor.EVENT_CHARGING_STATE_CHANGED, chargingState, 0).sendToTarget();
+ mDSM.obtainMessage(
+ DeviceStateMonitor.EVENT_WIFI_CONNECTION_CHANGED, wifiState, 0).sendToTarget();
+ mDSM.post(() -> setReady(true));
+ waitUntilReady();
+ }
+
+ @Test
+ @MediumTest
+ public void testWifi() throws Exception {
+ // screen off
+ sendStates(0, 0, 0);
+ assertEquals(
+ DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
+ // screen off, but charging
+ sendStates(0, 1, 0);
+ assertEquals(
+ DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
+ // screen on, no wifi
+ sendStates(1, 0, 0);
+ assertEquals(
+ DeviceStateMonitor.CELL_INFO_INTERVAL_SHORT_MS, mDSM.computeCellInfoMinInterval());
+ // screen on, but on wifi
+ sendStates(1, 0, 1);
+ assertEquals(
+ DeviceStateMonitor.CELL_INFO_INTERVAL_LONG_MS, mDSM.computeCellInfoMinInterval());
+ // screen on, charging
+ sendStates(1, 1, 0);
+ assertEquals(
+ DeviceStateMonitor.CELL_INFO_INTERVAL_SHORT_MS, mDSM.computeCellInfoMinInterval());
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
index 16e0656..c8524a9 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTest.java
@@ -291,7 +291,7 @@
NetworkRegistrationState wwanDataRegState = new NetworkRegistrationState(
NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
- 0, 0, 0, false, null, null, 0, false, false);
+ 0, 0, 0, false, null, null, 0, false, false, false);
NetworkRegistrationState wlanRegState = new NetworkRegistrationState(
NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WLAN,
@@ -313,7 +313,7 @@
wwanDataRegState = new NetworkRegistrationState(
NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN,
- 0, 0, 0, true, null, null, 0, false, false);
+ 0, 0, 0, true, null, null, 0, false, false, false);
ss.addNetworkRegistrationState(wwanDataRegState);
assertEquals(ss.getNetworkRegistrationStates(NetworkRegistrationState.DOMAIN_PS,
AccessNetworkConstants.TransportType.WWAN), wwanDataRegState);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 091d6dd..2fa4d3f 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -1673,7 +1673,7 @@
private void changeRegState(int state, CellIdentity cid, int voiceRat, int dataRat) {
NetworkRegistrationState dataResult = new NetworkRegistrationState(
- 0, 0, state, dataRat, 0, false, null, cid, 1, false, false);
+ 0, 0, state, dataRat, 0, false, null, cid, 1, false, false, false);
sst.mPollingContext[0] = 2;
// update data reg state to be in service
sst.sendMessage(sst.obtainMessage(ServiceStateTracker.EVENT_POLL_STATE_GPRS,
@@ -1762,7 +1762,7 @@
private void sendRegStateUpdateForLteCellId(CellIdentityLte cellId) {
NetworkRegistrationState dataResult = new NetworkRegistrationState(
2, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId, 1,
- false, false);
+ false, false, false);
NetworkRegistrationState voiceResult = new NetworkRegistrationState(
1, 1, 1, TelephonyManager.NETWORK_TYPE_LTE, 0, false, null, cellId,
false, 0, 0, 0);
@@ -1826,7 +1826,7 @@
testPhyChanBandwidthRatchetedOnPhyChanBandwidth();
NetworkRegistrationState dataResult = new NetworkRegistrationState(
2, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null, 1, false,
- false);
+ false, false);
NetworkRegistrationState voiceResult = new NetworkRegistrationState(
1, 1, 0, TelephonyManager.NETWORK_TYPE_UNKNOWN, 0, false, null, null,
false, 0, 0, 0);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
index 8e124fa..61b0077 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SubscriptionControllerTest.java
@@ -469,6 +469,54 @@
assertNotEquals(groupId, newGroupId);
}
+ @Test
+ @SmallTest
+ public void testDisabledSubscriptionGroup() throws Exception {
+ registerMockTelephonyRegistry();
+
+ testInsertSim();
+ // Adding a second profile and mark as embedded.
+ mSubscriptionControllerUT.addSubInfoRecord("test2", 0);
+
+ ContentValues values = new ContentValues();
+ values.put(SubscriptionManager.IS_EMBEDDED, 1);
+ values.put(SubscriptionManager.IS_OPPORTUNISTIC, 1);
+ mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+ SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 2, null);
+ mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+ verify(mTelephonyRegisteryMock, times(1))
+ .notifyOpportunisticSubscriptionInfoChanged();
+
+ // Set sub 1 and 2 into same group.
+ int[] subIdList = new int[] {1, 2};
+ String groupId = mSubscriptionControllerUT.setSubscriptionGroup(
+ subIdList, mContext.getOpPackageName());
+ assertNotEquals(null, groupId);
+
+ verify(mTelephonyRegisteryMock, times(2))
+ .notifyOpportunisticSubscriptionInfoChanged();
+ List<SubscriptionInfo> opptSubList = mSubscriptionControllerUT
+ .getOpportunisticSubscriptions(mCallingPackage);
+ assertEquals(1, opptSubList.size());
+ assertEquals(2, opptSubList.get(0).getSubscriptionId());
+ assertEquals(false, opptSubList.get(0).isGroupDisabled());
+
+ // Unplug SIM 1. This should trigger subscription controller disabling sub 2.
+ values = new ContentValues();
+ values.put(SubscriptionManager.SIM_SLOT_INDEX, -1);
+ mFakeTelephonyProvider.update(SubscriptionManager.CONTENT_URI, values,
+ SubscriptionManager.UNIQUE_KEY_SUBSCRIPTION_ID + "=" + 1, null);
+ mSubscriptionControllerUT.refreshCachedActiveSubscriptionInfoList();
+
+ verify(mTelephonyRegisteryMock, times(3))
+ .notifyOpportunisticSubscriptionInfoChanged();
+ opptSubList = mSubscriptionControllerUT.getOpportunisticSubscriptions(mCallingPackage);
+ assertEquals(1, opptSubList.size());
+ assertEquals(2, opptSubList.get(0).getSubscriptionId());
+ assertEquals(true, opptSubList.get(0).isGroupDisabled());
+ }
+
private void registerMockTelephonyRegistry() {
mServiceManagerMockedServices.put("telephony.registry", mTelephonyRegisteryMock);
doReturn(mTelephonyRegisteryMock).when(mTelephonyRegisteryMock)
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index 0642e31..2517d22 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.nullable;
import static org.mockito.Mockito.anyInt;
@@ -61,6 +62,7 @@
import com.android.internal.telephony.cdma.EriManager;
import com.android.internal.telephony.dataconnection.DcTracker;
import com.android.internal.telephony.dataconnection.TransportManager;
+import com.android.internal.telephony.emergency.EmergencyNumberTracker;
import com.android.internal.telephony.imsphone.ImsExternalCallTracker;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.imsphone.ImsPhoneCallTracker;
@@ -104,6 +106,8 @@
@Mock
protected ServiceStateTracker mSST;
@Mock
+ protected EmergencyNumberTracker mEmergencyNumberTracker;
+ @Mock
protected GsmCdmaCallTracker mCT;
@Mock
protected ImsPhoneCallTracker mImsCT;
@@ -336,9 +340,13 @@
mPackageManager = mContext.getPackageManager();
//mTelephonyComponentFactory
+ doReturn(mTelephonyComponentFactory).when(mTelephonyComponentFactory).inject(anyString());
doReturn(mSST).when(mTelephonyComponentFactory)
.makeServiceStateTracker(nullable(GsmCdmaPhone.class),
nullable(CommandsInterface.class));
+ doReturn(mEmergencyNumberTracker).when(mTelephonyComponentFactory)
+ .makeEmergencyNumberTracker(nullable(Phone.class),
+ nullable(CommandsInterface.class));
doReturn(mUiccProfile).when(mTelephonyComponentFactory)
.makeUiccProfile(nullable(Context.class), nullable(CommandsInterface.class),
nullable(IccCardStatus.class), anyInt(), nullable(UiccCard.class),
@@ -390,6 +398,7 @@
doReturn(PhoneConstants.PHONE_TYPE_GSM).when(mPhone).getPhoneType();
doReturn(mCT).when(mPhone).getCallTracker();
doReturn(mSST).when(mPhone).getServiceStateTracker();
+ doReturn(mEmergencyNumberTracker).when(mPhone).getEmergencyNumberTracker();
doReturn(mCarrierSignalAgent).when(mPhone).getCarrierSignalAgent();
doReturn(mCarrierActionAgent).when(mPhone).getCarrierActionAgent();
doReturn(mAppSmsManager).when(mPhone).getAppSmsManager();
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 1645af9..12c87e0 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/dataconnection/DcTrackerTest.java
@@ -98,8 +98,6 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
public class DcTrackerTest extends TelephonyTest {
@@ -132,6 +130,7 @@
private static final Uri PREFERAPN_URI = Uri.parse(
Telephony.Carriers.CONTENT_URI + "/preferapn");
private static final int DATA_ENABLED_CHANGED = 0;
+ private static final String FAKE_PLMN = "44010";
@Mock
ISub mIsub;
@@ -208,20 +207,13 @@
logd(" sortOrder = " + sortOrder);
if (uri.compareTo(Telephony.Carriers.CONTENT_URI) == 0
- || uri.compareTo(Uri.withAppendedPath(
- Telephony.Carriers.CONTENT_URI, "filtered")) == 0) {
- if (projection == null && selectionArgs == null && selection != null) {
+ || uri.toString().startsWith(Uri.withAppendedPath(
+ Telephony.Carriers.CONTENT_URI, "filtered").toString())
+ || uri.toString().startsWith(Uri.withAppendedPath(
+ Telephony.Carriers.SIM_APN_LIST, "filtered").toString())) {
+ if (projection == null) {
- Pattern pattern = Pattern.compile("^numeric = '([0-9]*)'");
- Matcher matcher = pattern.matcher(selection);
- if (!matcher.find()) {
- logd("Cannot find MCC/MNC from " + selection);
- return null;
- }
-
- String plmn = matcher.group(1);
-
- logd("Query '" + plmn + "' APN settings");
+ logd("Query '" + FAKE_PLMN + "' APN settings");
MatrixCursor mc = new MatrixCursor(
new String[]{Telephony.Carriers._ID, Telephony.Carriers.NUMERIC,
Telephony.Carriers.NAME, Telephony.Carriers.APN,
@@ -248,7 +240,7 @@
mc.addRow(new Object[]{
2163, // id
- plmn, // numeric
+ FAKE_PLMN, // numeric
"sp-mode", // name
FAKE_APN1, // apn
"", // proxy
@@ -280,7 +272,7 @@
mc.addRow(new Object[]{
2164, // id
- plmn, // numeric
+ FAKE_PLMN, // numeric
"mopera U", // name
FAKE_APN2, // apn
"", // proxy
@@ -312,7 +304,7 @@
mc.addRow(new Object[]{
2165, // id
- plmn, // numeric
+ FAKE_PLMN, // numeric
"b-mobile for Nexus", // name
FAKE_APN3, // apn
"", // proxy
@@ -344,7 +336,7 @@
mc.addRow(new Object[]{
2166, // id
- plmn, // numeric
+ FAKE_PLMN, // numeric
"sp-mode ehrpd", // name
FAKE_APN4, // apn
"", // proxy
@@ -376,7 +368,7 @@
mc.addRow(new Object[]{
2166, // id
- plmn, // numeric
+ FAKE_PLMN, // numeric
"b-mobile for Nexus", // name
FAKE_APN5, // apn
"", // proxy
@@ -437,7 +429,6 @@
doReturn("fake.action_attached").when(mPhone).getActionAttached();
doReturn(ServiceState.RIL_RADIO_TECHNOLOGY_LTE).when(mServiceState)
.getRilDataRadioTechnology();
- doReturn("44010").when(mSimRecords).getOperatorNumeric();
mContextFixture.putStringArrayResource(com.android.internal.R.array.networkAttributes,
sNetworkAttributes);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
new file mode 100644
index 0000000..11936f5
--- /dev/null
+++ b/tests/telephonytests/src/com/android/internal/telephony/emergency/EmergencyNumberTrackerTest.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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.emergency;
+
+import static org.junit.Assert.assertEquals;
+
+import android.os.AsyncResult;
+import android.os.HandlerThread;
+import android.telephony.emergency.EmergencyNumber;
+
+import com.android.internal.telephony.TelephonyTest;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tests for EmergencyNumberTracker.java
+ */
+public class EmergencyNumberTrackerTest extends TelephonyTest {
+
+ private EmergencyNumberTracker mEmergencyNumberTrackerMock;
+ private List<EmergencyNumber> mEmergencyNumberListTestSample = new ArrayList<>();
+ private static final long TIMEOUT_MS = 500;
+
+ private class EmergencyNumberTrackerTestHandler extends HandlerThread {
+ private EmergencyNumberTrackerTestHandler(String name) {
+ super(name);
+ }
+ @Override
+ public void onLooperPrepared() {
+ mEmergencyNumberTrackerMock = new EmergencyNumberTracker(mPhone, mSimulatedCommands);
+ mEmergencyNumberTrackerMock.DBG = true;
+ setReady(true);
+ }
+ }
+
+ private EmergencyNumberTrackerTestHandler mHandlerThread;
+
+ @Before
+ public void setUp() throws Exception {
+ logd("EmergencyNumberTrackerTest +Setup!");
+ super.setUp("EmergencyNumberTrackerTest");
+ initializeEmergencyNumberListTestSamples();
+ mHandlerThread = new EmergencyNumberTrackerTestHandler("EmergencyNumberTrackerTestHandler");
+ mHandlerThread.start();
+ waitUntilReady();
+ logd("EmergencyNumberTrackerTest -Setup!");
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ mHandlerThread.quit();
+ mHandlerThread.join();
+ super.tearDown();
+ }
+
+ private void initializeEmergencyNumberListTestSamples() {
+ EmergencyNumber emergencyNumberForTest = new EmergencyNumber("119", "jp",
+ EmergencyNumber.EMERGENCY_SERVICE_CATEGORY_FIRE_BRIGADE,
+ EmergencyNumber.EMERGENCY_NUMBER_SOURCE_NETWORK_SIGNALING);
+ mEmergencyNumberListTestSample.add(emergencyNumberForTest);
+ }
+
+ private void sendEmergencyNumberListFromRadio() {
+ mEmergencyNumberTrackerMock.sendMessage(
+ mEmergencyNumberTrackerMock.obtainMessage(
+ 1 /* EVENT_UNSOL_EMERGENCY_NUMBER_LIST */,
+ new AsyncResult(null, mEmergencyNumberListTestSample, null)));
+ waitForHandlerAction(mEmergencyNumberTrackerMock, TIMEOUT_MS);
+ }
+
+ @Test
+ public void testEmergencyNumberListFromRadio() throws Exception {
+ sendEmergencyNumberListFromRadio();
+ assertEquals(mEmergencyNumberListTestSample,
+ mEmergencyNumberTrackerMock.getRadioEmergencyNumberList());
+ }
+}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
index df5552a..19906bd 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/mocks/TelephonyRegistryMock.java
@@ -28,6 +28,7 @@
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.SubscriptionManager;
+import android.telephony.emergency.EmergencyNumber;
import com.android.internal.telephony.IOnSubscriptionsChangedListener;
import com.android.internal.telephony.IPhoneStateListener;
@@ -361,6 +362,11 @@
}
@Override
+ public void notifyEmergencyNumberList(List<EmergencyNumber> emergencyNumberList) {
+ throw new RuntimeException("Not implemented");
+ }
+
+ @Override
public void notifyPreciseCallState(int ringingCallState, int foregroundCallState,
int backgroundCallState) {
throw new RuntimeException("Not implemented");