Merge "Feature flagging for Apn Setting Field API" into main
diff --git a/Android.bp b/Android.bp
index 301343c..121236a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -106,6 +106,7 @@
"net-utils-framework-common",
"telephony-protos",
"modules-utils-build_system",
+ "modules-utils-fastxmlserializer",
"modules-utils-statemachine",
],
diff --git a/OWNERS b/OWNERS
index 35f2818..7e57200 100644
--- a/OWNERS
+++ b/OWNERS
@@ -17,6 +17,5 @@
tnd@google.com
xiaotonj@google.com
-
-
-
+# Domain Selection code is co-owned, adding additional owners for this code
+per-file EmergencyStateTracker*=hwangoo@google.com,forestchoi@google.com,avinashmp@google.com,mkoon@google.com,seheele@google.com
diff --git a/flags/messaging.aconfig b/flags/messaging.aconfig
index 3c20d69..1ba89ba 100644
--- a/flags/messaging.aconfig
+++ b/flags/messaging.aconfig
@@ -13,3 +13,10 @@
description: "This flag controls AP domain selection support for normal/emergency SMS."
bug: "262804071"
}
+
+flag {
+ name: "mms_disabled_error"
+ namespace: "telephony"
+ description: "This flag controls the support of the new MMS error code MMS_ERROR_MMS_DISABLED."
+ bug: "305062594"
+}
\ No newline at end of file
diff --git a/flags/misc.aconfig b/flags/misc.aconfig
index 87acccc..afe6980 100644
--- a/flags/misc.aconfig
+++ b/flags/misc.aconfig
@@ -16,8 +16,22 @@
}
flag {
+ name: "stop_spamming_emergency_notification"
+ namespace: "telephony"
+ description: "When set, the no wifi emergency calling availability notif will have a do not ask again button"
+ bug: "275225402"
+}
+
+flag {
name: "enable_wps_check_api_flag"
namespace: "telephony"
description: "Enable system api isWpsCallNumber. Its an utility api to check if the dialed number is for Wireless Priority Service call."
bug: "304272356"
+}
+
+flag {
+ name: "ensure_access_to_call_settings_is_restricted"
+ namespace: "telephony"
+ description: "Check if access to mobile network configs restricted before displaying call options"
+ bug: "309655251"
}
\ No newline at end of file
diff --git a/proto/src/persist_atoms.proto b/proto/src/persist_atoms.proto
index 993aa4d..537f824 100644
--- a/proto/src/persist_atoms.proto
+++ b/proto/src/persist_atoms.proto
@@ -677,4 +677,7 @@
optional bool is_ims_registered = 3;
optional int32 cellular_service_state = 4;
optional int32 count = 5;
+ optional bool is_multi_sim = 6;
+ optional int32 recommending_handover_type = 7;
+ optional bool is_satellite_allowed_in_current_location = 8;
}
diff --git a/src/java/com/android/internal/telephony/BaseCommands.java b/src/java/com/android/internal/telephony/BaseCommands.java
index 4ec1f71..3f3d297 100644
--- a/src/java/com/android/internal/telephony/BaseCommands.java
+++ b/src/java/com/android/internal/telephony/BaseCommands.java
@@ -118,6 +118,7 @@
protected RegistrantList mConnectionSetupFailureRegistrants = new RegistrantList();
protected RegistrantList mNotifyAnbrRegistrants = new RegistrantList();
protected RegistrantList mTriggerImsDeregistrationRegistrants = new RegistrantList();
+ protected RegistrantList mImeiInfoRegistrants = new RegistrantList();
@UnsupportedAppUsage
protected Registrant mGsmSmsRegistrant;
@@ -1174,4 +1175,12 @@
public void unregisterForTriggerImsDeregistration(Handler h) {
mTriggerImsDeregistrationRegistrants.remove(h);
}
+
+ /**
+ * Register to listen for the changes in the primary IMEI with respect to the sim slot.
+ */
+ @Override
+ public void registerForImeiMappingChanged(Handler h, int what, Object obj) {
+ mImeiInfoRegistrants.add(h, what, obj);
+ }
}
diff --git a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
index 1fd7485..6b99b56 100644
--- a/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/CarrierServiceStateTracker.java
@@ -16,6 +16,7 @@
package com.android.internal.telephony;
+import android.annotation.NonNull;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
@@ -42,6 +43,7 @@
import android.telephony.TelephonyManager.NetworkTypeBitMask;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.util.ArrayUtils;
import com.android.internal.telephony.util.NotificationChannelController;
import com.android.telephony.Rlog;
@@ -85,6 +87,7 @@
private long mAllowedNetworkType = -1;
private AllowedNetworkTypesListener mAllowedNetworkTypesListener;
private TelephonyManager mTelephonyManager;
+ @NonNull private final FeatureFlags mFeatureFlags;
/**
* The listener for allowed network types changed
@@ -105,7 +108,9 @@
}
}
- public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst) {
+ public CarrierServiceStateTracker(Phone phone, ServiceStateTracker sst,
+ @NonNull FeatureFlags featureFlags) {
+ mFeatureFlags = featureFlags;
this.mPhone = phone;
this.mSST = sst;
mTelephonyManager = mPhone.getContext().getSystemService(
@@ -165,11 +170,13 @@
mAllowedNetworkTypesListener = new AllowedNetworkTypesListener();
registerAllowedNetworkTypesListener();
- // register a receiver for notification actions
- mPhone.getContext().registerReceiver(
- mActionReceiver,
- new IntentFilter(ACTION_NEVER_ASK_AGAIN),
- Context.RECEIVER_NOT_EXPORTED);
+ if (mFeatureFlags.stopSpammingEmergencyNotification()) {
+ // register a receiver for notification actions
+ mPhone.getContext().registerReceiver(
+ mActionReceiver,
+ new IntentFilter(ACTION_NEVER_ASK_AGAIN),
+ Context.RECEIVER_NOT_EXPORTED);
+ }
}
/**
@@ -402,7 +409,8 @@
return;
}
- if (shouldSilenceEmrgNetNotif(notificationType, context)) {
+ if (mFeatureFlags.stopSpammingEmergencyNotification()
+ && shouldSilenceEmrgNetNotif(notificationType, context)) {
Rlog.i(LOG_TAG, "sendNotification: silencing NOTIFICATION_EMERGENCY_NETWORK");
return;
}
@@ -681,13 +689,22 @@
com.android.internal.R.string.EmergencyCallWarningTitle);
CharSequence details = res.getText(
com.android.internal.R.string.EmergencyCallWarningSummary);
- return new Notification.Builder(context)
- .setContentTitle(title)
- .setStyle(new Notification.BigTextStyle().bigText(details))
- .setContentText(details)
- .setOngoing(true)
- .setActions(createDoNotShowAgainAction(context))
- .setChannelId(NotificationChannelController.CHANNEL_ID_WFC);
+ if (mFeatureFlags.stopSpammingEmergencyNotification()) {
+ return new Notification.Builder(context)
+ .setContentTitle(title)
+ .setStyle(new Notification.BigTextStyle().bigText(details))
+ .setContentText(details)
+ .setOngoing(true)
+ .setActions(createDoNotShowAgainAction(context))
+ .setChannelId(NotificationChannelController.CHANNEL_ID_WFC);
+ } else {
+ return new Notification.Builder(context)
+ .setContentTitle(title)
+ .setStyle(new Notification.BigTextStyle().bigText(details))
+ .setContentText(details)
+ .setOngoing(true)
+ .setChannelId(NotificationChannelController.CHANNEL_ID_WFC);
+ }
}
/**
diff --git a/src/java/com/android/internal/telephony/CommandsInterface.java b/src/java/com/android/internal/telephony/CommandsInterface.java
index 71c2001..4b977ff 100644
--- a/src/java/com/android/internal/telephony/CommandsInterface.java
+++ b/src/java/com/android/internal/telephony/CommandsInterface.java
@@ -1735,6 +1735,12 @@
public void getImei(Message response);
/**
+ * Register to listen for the changes in the primary IMEI with respect to the sim slot.
+ */
+
+ public void registerForImeiMappingChanged(Handler h, int what, Object obj);
+
+ /**
* Request the device MDN / H_SID / H_NID / MIN.
* "response" is const char **
* [0] is MDN if CDMA subscription is available
@@ -2891,4 +2897,19 @@
* @param result Callback message to receive the result.
*/
default void isN1ModeEnabled(Message result) {}
+
+ /**
+ * Enables or disables cellular identifier disclosure transparency.
+ *
+ * @param enable {@code true} to enable, {@code false} to disable.
+ * @param result Callback message to receive the result.
+ */
+ default void setCellularIdentifierTransparencyEnabled(boolean enable, Message result) {}
+
+ /**
+ * Check whether cellular identifier transparency.
+ *
+ * @param result Callback message to receive the result.
+ */
+ default void isCellularIdentifierTransparencyEnabled(Message result) {}
}
\ No newline at end of file
diff --git a/src/java/com/android/internal/telephony/GsmCdmaPhone.java b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
index 52d5580..d912187 100644
--- a/src/java/com/android/internal/telephony/GsmCdmaPhone.java
+++ b/src/java/com/android/internal/telephony/GsmCdmaPhone.java
@@ -354,7 +354,7 @@
mSignalStrengthController = mTelephonyComponentFactory.inject(
SignalStrengthController.class.getName()).makeSignalStrengthController(this);
mSST = mTelephonyComponentFactory.inject(ServiceStateTracker.class.getName())
- .makeServiceStateTracker(this, this.mCi);
+ .makeServiceStateTracker(this, this.mCi, featureFlags);
mEmergencyNumberTracker = mTelephonyComponentFactory
.inject(EmergencyNumberTracker.class.getName()).makeEmergencyNumberTracker(
this, this.mCi);
@@ -514,6 +514,7 @@
mCDM = new CarrierKeyDownloadManager(this, mFeatureFlags);
mCIM = new CarrierInfoManager();
+ mCi.registerForImeiMappingChanged(this, EVENT_IMEI_MAPPING_CHANGED, null);
initializeCarrierApps();
}
@@ -3170,19 +3171,7 @@
}
break;
case EVENT_GET_DEVICE_IMEI_DONE :
- ar = (AsyncResult)msg.obj;
- if (ar.exception != null || ar.result == null) {
- loge("Exception received : " + ar.exception);
- break;
- }
- ImeiInfo imeiInfo = (ImeiInfo) ar.result;
- if (!TextUtils.isEmpty(imeiInfo.imei)) {
- mImeiType = imeiInfo.type;
- mImei = imeiInfo.imei;
- mImeiSv = imeiInfo.svn;
- } else {
- // TODO Report telephony anomaly
- }
+ parseImeiInfo(msg);
break;
case EVENT_GET_DEVICE_IDENTITY_DONE:{
ar = (AsyncResult)msg.obj;
@@ -3668,11 +3657,33 @@
rsp.sendToTarget();
}
break;
+
+ case EVENT_IMEI_MAPPING_CHANGED:
+ logd("EVENT_GET_DEVICE_IMEI_CHANGE_DONE phoneId = " + getPhoneId());
+ parseImeiInfo(msg);
+ break;
+
default:
super.handleMessage(msg);
}
}
+ private void parseImeiInfo(Message msg) {
+ AsyncResult ar = (AsyncResult)msg.obj;
+ if (ar.exception != null || ar.result == null) {
+ loge("parseImeiInfo :: Exception received : " + ar.exception);
+ return;
+ }
+ ImeiInfo imeiInfo = (ImeiInfo) ar.result;
+ if (!TextUtils.isEmpty(imeiInfo.imei)) {
+ mImeiType = imeiInfo.type;
+ mImei = imeiInfo.imei;
+ mImeiSv = imeiInfo.svn;
+ } else {
+ loge("parseImeiInfo :: IMEI value is empty");
+ }
+ }
+
/**
* Check if a different SIM is inserted at this slot from the last time. Storing last subId
* in SharedPreference for now to detect SIM change.
diff --git a/src/java/com/android/internal/telephony/ModemIndication.java b/src/java/com/android/internal/telephony/ModemIndication.java
index 0ee40bb..3893c6a 100644
--- a/src/java/com/android/internal/telephony/ModemIndication.java
+++ b/src/java/com/android/internal/telephony/ModemIndication.java
@@ -19,12 +19,14 @@
import static android.telephony.TelephonyManager.HAL_SERVICE_MODEM;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_IMEI_MAPPING_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RADIO_CAPABILITY;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RESPONSE_RADIO_STATE_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_RIL_CONNECTED;
import android.hardware.radio.modem.IRadioModemIndication;
+import android.hardware.radio.modem.ImeiInfo;
import android.os.AsyncResult;
import java.util.ArrayList;
@@ -132,4 +134,18 @@
public int getInterfaceVersion() {
return IRadioModemIndication.VERSION;
}
+
+ /**
+ * Indicates when there is a change in the IMEI with respect to the sim slot.
+ *
+ * @param imeiInfo IMEI information
+ */
+ public void onImeiMappingChanged(int indicationType, ImeiInfo imeiInfo) {
+ mRil.processIndication(HAL_SERVICE_MODEM, indicationType);
+
+ if (mRil.isLogOrTrace()) {
+ mRil.unsljLogMore(RIL_UNSOL_IMEI_MAPPING_CHANGED, "ImeiMappingChanged");
+ }
+ mRil.notifyRegistrantsImeiMappingChanged(imeiInfo);
+ }
}
diff --git a/src/java/com/android/internal/telephony/NetworkIndication.java b/src/java/com/android/internal/telephony/NetworkIndication.java
index 6025273..dc3fbf1 100644
--- a/src/java/com/android/internal/telephony/NetworkIndication.java
+++ b/src/java/com/android/internal/telephony/NetworkIndication.java
@@ -33,6 +33,7 @@
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SIGNAL_STRENGTH;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_SUPP_SVC_NOTIFICATION;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_VOICE_RADIO_TECH_CHANGED;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_CELLULAR_IDENTIFIER_DISCLOSED;
import android.annotation.ElapsedRealtimeLong;
import android.hardware.radio.network.IRadioNetworkIndication;
@@ -421,6 +422,22 @@
new AsyncResult(null, response, null));
}
+ /**
+ * Cellular identifier disclosure events
+ * @param indicationType Type of radio indication
+ * @param identifierDisclsoure the result of the Emergency Network Scan
+ */
+ public void cellularIdentifierDisclosed(int indicationType,
+ android.hardware.radio.network.CellularIdentifierDisclosure identifierDisclsoure) {
+ mRil.processIndication(HAL_SERVICE_NETWORK, indicationType);
+
+ if (mRil.isLogOrTrace()) {
+ mRil.unsljLogRet(RIL_UNSOL_CELLULAR_IDENTIFIER_DISCLOSED, identifierDisclsoure);
+ }
+
+ // TODO (b/276752426) notify registrants of identifier disclosure
+ }
+
@Override
public String getInterfaceHash() {
return IRadioNetworkIndication.HASH;
diff --git a/src/java/com/android/internal/telephony/NetworkResponse.java b/src/java/com/android/internal/telephony/NetworkResponse.java
index f26022e..e4e2b1b 100644
--- a/src/java/com/android/internal/telephony/NetworkResponse.java
+++ b/src/java/com/android/internal/telephony/NetworkResponse.java
@@ -504,6 +504,30 @@
RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo);
}
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error
+ */
+ public void setCellularIdentifierTransparencyEnabledResponse(RadioResponseInfo responseInfo) {
+ RadioResponse.responseVoid(HAL_SERVICE_NETWORK, mRil, responseInfo);
+ }
+
+ /**
+ * @param responseInfo Response info struct containing response type, serial no. and error.
+ * @param isEnabled Indicates whether cellular identifier disclosure transparency from the modem
+ * is enabled.
+ */
+ public void isCellularIdentifierTransparencyEnabledResponse(RadioResponseInfo responseInfo,
+ boolean isEnabled) {
+ RILRequest rr = mRil.processResponse(HAL_SERVICE_NETWORK, responseInfo);
+
+ if (rr != null) {
+ if (responseInfo.error == RadioError.NONE) {
+ RadioResponse.sendMessageResponse(rr.mResult, isEnabled);
+ }
+ mRil.processResponseDone(rr, responseInfo, isEnabled);
+ }
+ }
+
@Override
public String getInterfaceHash() {
return IRadioNetworkResponse.HASH;
diff --git a/src/java/com/android/internal/telephony/Phone.java b/src/java/com/android/internal/telephony/Phone.java
index 50cf844..72d0622 100644
--- a/src/java/com/android/internal/telephony/Phone.java
+++ b/src/java/com/android/internal/telephony/Phone.java
@@ -253,8 +253,8 @@
protected static final int EVENT_TRIGGER_NOTIFY_ANBR = 68;
protected static final int EVENT_GET_N1_MODE_ENABLED_DONE = 69;
protected static final int EVENT_SET_N1_MODE_ENABLED_DONE = 70;
-
- protected static final int EVENT_LAST = EVENT_SET_N1_MODE_ENABLED_DONE;
+ protected static final int EVENT_IMEI_MAPPING_CHANGED = 71;
+ protected static final int EVENT_LAST = EVENT_IMEI_MAPPING_CHANGED;
// For shared prefs.
private static final String GSM_ROAMING_LIST_OVERRIDE_PREFIX = "gsm_roaming_list_";
diff --git a/src/java/com/android/internal/telephony/PhoneFactory.java b/src/java/com/android/internal/telephony/PhoneFactory.java
index a796368..625a937 100644
--- a/src/java/com/android/internal/telephony/PhoneFactory.java
+++ b/src/java/com/android/internal/telephony/PhoneFactory.java
@@ -62,6 +62,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
@@ -521,6 +522,27 @@
return sMetricsCollector;
}
+ /**
+ * Print all feature flag configurations that Telephony is using for debugging purposes.
+ */
+ private static void reflectAndPrintFlagConfigs(IndentingPrintWriter pw) {
+
+ try {
+ // Look away, a forbidden technique (reflection) is being used to allow us to get
+ // all flag configs without having to add them manually to this method.
+ Method[] methods = FeatureFlags.class.getMethods();
+ if (methods.length == 0) {
+ pw.println("NONE");
+ return;
+ }
+ for (Method m : methods) {
+ pw.println(m.getName() + "-> " + m.invoke(sFeatureFlags));
+ }
+ } catch (Exception e) {
+ pw.println("[ERROR]");
+ }
+ }
+
public static void dump(FileDescriptor fd, PrintWriter printwriter, String[] args) {
IndentingPrintWriter pw = new IndentingPrintWriter(printwriter, " ");
pw.println("PhoneFactory:");
@@ -613,8 +635,15 @@
} catch (Exception e) {
e.printStackTrace();
}
-
pw.flush();
pw.decreaseIndent();
+
+ pw.println("++++++++++++++++++++++++++++++++");
+ pw.println("Flag Configurations:");
+ pw.increaseIndent();
+ reflectAndPrintFlagConfigs(pw);
+ pw.flush();
+ pw.decreaseIndent();
+ pw.println("++++++++++++++++++++++++++++++++");
}
}
diff --git a/src/java/com/android/internal/telephony/RIL.java b/src/java/com/android/internal/telephony/RIL.java
index 7e8bfe8..56cb808 100644
--- a/src/java/com/android/internal/telephony/RIL.java
+++ b/src/java/com/android/internal/telephony/RIL.java
@@ -36,6 +36,7 @@
import android.hardware.radio.V1_0.RadioIndicationType;
import android.hardware.radio.V1_0.RadioResponseInfo;
import android.hardware.radio.V1_0.RadioResponseType;
+import android.hardware.radio.modem.ImeiInfo;
import android.net.KeepalivePacketData;
import android.net.LinkProperties;
import android.os.AsyncResult;
@@ -5078,6 +5079,61 @@
});
}
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void setCellularIdentifierTransparencyEnabled(boolean enable, Message result) {
+ RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
+ if (!canMakeRequest(
+ "setCellularIdentifierDisclosedEnabled",
+ networkProxy,
+ result,
+ RADIO_HAL_VERSION_2_2)) {
+ return;
+ }
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_SET_CELLULAR_IDENTIFIER_DISCLOSED_ENABLED, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest)
+ + " enable=" + enable);
+ }
+
+ radioServiceInvokeHelper(
+ HAL_SERVICE_NETWORK, rr, "setCellularIdentifierDisclosedEnabled", () -> {
+ networkProxy.setCellularIdentifierTransparencyEnabled(rr.mSerial, enable);
+ });
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void isCellularIdentifierTransparencyEnabled(Message result) {
+ RadioNetworkProxy networkProxy = getRadioServiceProxy(RadioNetworkProxy.class);
+ if (!canMakeRequest(
+ "isCellularIdentifierDisclosedEnabled",
+ networkProxy,
+ result,
+ RADIO_HAL_VERSION_2_2)) {
+ return;
+ }
+
+ RILRequest rr = obtainRequest(RIL_REQUEST_IS_CELLULAR_IDENTIFIER_DISCLOSED_ENABLED, result,
+ mRILDefaultWorkSource);
+
+ if (RILJ_LOGD) {
+ riljLog(rr.serialString() + "> " + RILUtils.requestToString(rr.mRequest));
+ }
+
+ radioServiceInvokeHelper(
+ HAL_SERVICE_NETWORK, rr, "isCellularIdentifierDisclosedEnabled", () -> {
+ networkProxy.isCellularIdentifierTransparencyEnabled(rr.mSerial);
+ });
+ }
+
//***** Private Methods
/**
* This is a helper function to be called when an indication callback is called for any radio
@@ -5255,7 +5311,7 @@
* @param responseInfo RadioResponseInfo received in the callback
* @param ret object to be returned to request sender
*/
- @VisibleForTesting
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PROTECTED)
public void processResponseDone(RILRequest rr, RadioResponseInfo responseInfo, Object ret) {
processResponseDoneInternal(rr, responseInfo.error, responseInfo.type, ret);
}
@@ -5785,6 +5841,13 @@
}
}
+ void notifyRegistrantsImeiMappingChanged(ImeiInfo imeiInfo) {
+ if (mImeiInfoRegistrants != null) {
+ mImeiInfoRegistrants.notifyRegistrants(
+ new AsyncResult(null, imeiInfo, null));
+ }
+ }
+
@UnsupportedAppUsage
void riljLog(String msg) {
Rlog.d(RILJ_LOG_TAG, msg + (" [PHONE" + mPhoneId + "]"));
diff --git a/src/java/com/android/internal/telephony/RILUtils.java b/src/java/com/android/internal/telephony/RILUtils.java
index c2c29f8..cb5684f 100644
--- a/src/java/com/android/internal/telephony/RILUtils.java
+++ b/src/java/com/android/internal/telephony/RILUtils.java
@@ -241,6 +241,7 @@
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_EXIT_EMERGENCY_CALLBACK_MODE;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_HARDWARE_CONFIG_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_ICC_SLOT_STATUS;
+import static com.android.internal.telephony.RILConstants.RIL_UNSOL_IMEI_MAPPING_CHANGED;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_KEEPALIVE_STATUS;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_LCEDATA_RECV;
import static com.android.internal.telephony.RILConstants.RIL_UNSOL_MODEM_RESTART;
@@ -5269,6 +5270,8 @@
return "UNSOL_NOTIFY_ANBR";
case RIL_UNSOL_TRIGGER_IMS_DEREGISTRATION:
return "UNSOL_TRIGGER_IMS_DEREGISTRATION";
+ case RIL_UNSOL_IMEI_MAPPING_CHANGED:
+ return "UNSOL_IMEI_MAPPING_CHANGED";
default:
return "<unknown response " + response + ">";
}
diff --git a/src/java/com/android/internal/telephony/RadioNetworkProxy.java b/src/java/com/android/internal/telephony/RadioNetworkProxy.java
index 5a56d23..fc308ca 100644
--- a/src/java/com/android/internal/telephony/RadioNetworkProxy.java
+++ b/src/java/com/android/internal/telephony/RadioNetworkProxy.java
@@ -921,4 +921,32 @@
}
// Only supported on AIDL.
}
+
+ /**
+ * Enables or disables cellular identifier disclosure transparency.
+ *
+ * @param serial Serial number of request.
+ * @param enable Indicates whether to enable disclosure transparency or not.
+ */
+ public void setCellularIdentifierTransparencyEnabled(int serial, boolean enable)
+ throws RemoteException {
+ if (isEmpty()) return;
+ if (isAidl()) {
+ mNetworkProxy.setCellularIdentifierTransparencyEnabled(serial, enable);
+ }
+ // Only supported on AIDL.
+ }
+
+ /**
+ * Checks whether cellular identifier transparency disclosure is enabled.
+ *
+ * @param serial Serial number of request.
+ */
+ public void isCellularIdentifierTransparencyEnabled(int serial) throws RemoteException {
+ if (isEmpty()) return;
+ if (isAidl()) {
+ mNetworkProxy.isCellularIdentifierTransparencyEnabled(serial);
+ }
+ // Only supported on AIDL.
+ }
}
diff --git a/src/java/com/android/internal/telephony/ServiceStateTracker.java b/src/java/com/android/internal/telephony/ServiceStateTracker.java
index 14f71bd..01d6e4c 100644
--- a/src/java/com/android/internal/telephony/ServiceStateTracker.java
+++ b/src/java/com/android/internal/telephony/ServiceStateTracker.java
@@ -94,6 +94,7 @@
import com.android.internal.telephony.data.AccessNetworksManager.AccessNetworksManagerCallback;
import com.android.internal.telephony.data.DataNetwork;
import com.android.internal.telephony.data.DataNetworkController.DataNetworkControllerCallback;
+import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.imsphone.ImsPhone;
import com.android.internal.telephony.metrics.RadioPowerStateStats;
import com.android.internal.telephony.metrics.ServiceStateStats;
@@ -625,7 +626,8 @@
*/
private AccessNetworksManagerCallback mAccessNetworksManagerCallback = null;
- public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
+ public ServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci,
+ FeatureFlags featureFlags) {
mNitzState = TelephonyComponentFactory.getInstance()
.inject(NitzStateMachine.class.getName())
.makeNitzStateMachine(phone);
@@ -710,7 +712,7 @@
mCi.setOnRestrictedStateChanged(this, EVENT_RESTRICTED_STATE_CHANGED, null);
updatePhoneType();
- mCSST = new CarrierServiceStateTracker(phone, this);
+ mCSST = new CarrierServiceStateTracker(phone, this, featureFlags);
registerForNetworkAttached(mCSST,
CarrierServiceStateTracker.CARRIER_EVENT_VOICE_REGISTRATION, null);
@@ -1946,16 +1948,15 @@
err = ((CommandException)(ar.exception)).getCommandError();
}
- if (mCi.getRadioState() != TelephonyManager.RADIO_POWER_ON) {
- log("handlePollStateResult: Invalid response due to radio off or unavailable. "
- + "Set ServiceState to out of service.");
- pollStateInternal(false);
- return;
- }
-
if (err == CommandException.Error.RADIO_NOT_AVAILABLE) {
- loge("handlePollStateResult: RIL returned RADIO_NOT_AVAILABLE when radio is on.");
- cancelPollState();
+ loge("handlePollStateResult: RIL returned RADIO_NOT_AVAILABLE.");
+ if (mCi.getRadioState() == TelephonyManager.RADIO_POWER_ON) {
+ cancelPollState();
+ } else {
+ handlePollStateInternalForRadioOffOrUnavailable(
+ mCi.getRadioState() == TelephonyManager.RADIO_POWER_OFF);
+ pollStateDone();
+ }
return;
}
@@ -3312,42 +3313,17 @@
private void pollStateInternal(boolean modemTriggered) {
mPollingContext = new int[1];
- NetworkRegistrationInfo nri;
log("pollState: modemTriggered=" + modemTriggered + ", radioState=" + mCi.getRadioState());
switch (mCi.getRadioState()) {
case TelephonyManager.RADIO_POWER_UNAVAILABLE:
- // Preserve the IWLAN registration state, because that should not be affected by
- // radio availability.
- nri = mNewSS.getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS,
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
- mNewSS.setOutOfService(false);
- // Add the IWLAN registration info back to service state.
- if (nri != null) {
- mNewSS.addNetworkRegistrationInfo(nri);
- }
- mPhone.getSignalStrengthController().setSignalStrengthDefaultValues();
- mLastNitzData = null;
- mNitzState.handleNetworkUnavailable();
+ handlePollStateInternalForRadioOffOrUnavailable(false);
pollStateDone();
break;
case TelephonyManager.RADIO_POWER_OFF:
- // Preserve the IWLAN registration state, because that should not be affected by
- // radio availability.
- nri = mNewSS.getNetworkRegistrationInfo(
- NetworkRegistrationInfo.DOMAIN_PS,
- AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
- mNewSS.setOutOfService(true);
- // Add the IWLAN registration info back to service state.
- if (nri != null) {
- mNewSS.addNetworkRegistrationInfo(nri);
- }
- mPhone.getSignalStrengthController().setSignalStrengthDefaultValues();
- mLastNitzData = null;
- mNitzState.handleNetworkUnavailable();
+ handlePollStateInternalForRadioOffOrUnavailable(true);
// Don't poll when device is shutting down or the poll was not modemTriggered
// (they sent us new radio data) and the current network is not IWLAN
if (mDeviceShuttingDown ||
@@ -3391,6 +3367,21 @@
}
}
+ private void handlePollStateInternalForRadioOffOrUnavailable(boolean radioOff) {
+ // Preserve the IWLAN registration state, which should not be affected by radio availability
+ NetworkRegistrationInfo nri = mNewSS.getNetworkRegistrationInfo(
+ NetworkRegistrationInfo.DOMAIN_PS,
+ AccessNetworkConstants.TRANSPORT_TYPE_WLAN);
+ mNewSS.setOutOfService(radioOff);
+ // Add the IWLAN registration info back to service state.
+ if (nri != null) {
+ mNewSS.addNetworkRegistrationInfo(nri);
+ }
+ mPhone.getSignalStrengthController().setSignalStrengthDefaultValues();
+ mLastNitzData = null;
+ mNitzState.handleNetworkUnavailable();
+ }
+
/**
* Get the highest-priority CellIdentity for a provided ServiceState.
*
diff --git a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
index 6e3e911..0f074a9 100644
--- a/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
+++ b/src/java/com/android/internal/telephony/TelephonyComponentFactory.java
@@ -288,8 +288,9 @@
return new SmsUsageMonitor(context);
}
- public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci) {
- return new ServiceStateTracker(phone, ci);
+ public ServiceStateTracker makeServiceStateTracker(GsmCdmaPhone phone, CommandsInterface ci,
+ @NonNull FeatureFlags featureFlags) {
+ return new ServiceStateTracker(phone, ci, featureFlags);
}
/**
diff --git a/src/java/com/android/internal/telephony/data/DataConfigManager.java b/src/java/com/android/internal/telephony/data/DataConfigManager.java
index 39e7325..ea7b1da 100644
--- a/src/java/com/android/internal/telephony/data/DataConfigManager.java
+++ b/src/java/com/android/internal/telephony/data/DataConfigManager.java
@@ -984,6 +984,7 @@
DATA_CONFIG_NETWORK_TYPE_EHRPD,
DATA_CONFIG_NETWORK_TYPE_IDEN,
DATA_CONFIG_NETWORK_TYPE_LTE,
+ DATA_CONFIG_NETWORK_TYPE_LTE_CA,
DATA_CONFIG_NETWORK_TYPE_HSPAP,
DATA_CONFIG_NETWORK_TYPE_GSM,
DATA_CONFIG_NETWORK_TYPE_TD_SCDMA,
diff --git a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
index bd7ce2a..8c1aae3 100644
--- a/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
+++ b/src/java/com/android/internal/telephony/metrics/MetricsCollector.java
@@ -1336,7 +1336,10 @@
stats.countOfTimerStarted,
stats.isImsRegistered,
stats.cellularServiceState,
- stats.count);
+ stats.count,
+ stats.isMultiSim,
+ stats.recommendingHandoverType,
+ stats.isSatelliteAllowedInCurrentLocation);
}
/** Returns all phones in {@link PhoneFactory}, or an empty array if phones not made yet. */
diff --git a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
index 1da0c46..d5d041a 100644
--- a/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
+++ b/src/java/com/android/internal/telephony/metrics/PersistAtomsStorage.java
@@ -2070,7 +2070,9 @@
if (stats.isDisplaySosMessageSent == key.isDisplaySosMessageSent
&& stats.countOfTimerStarted == key.countOfTimerStarted
&& stats.isImsRegistered == key.isImsRegistered
- && stats.cellularServiceState == key.cellularServiceState) {
+ && stats.cellularServiceState == key.cellularServiceState
+ && stats.isMultiSim == key.isMultiSim
+ && stats.recommendingHandoverType == key.recommendingHandoverType) {
return stats;
}
}
diff --git a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
index 7ff370c..55eee1a 100644
--- a/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
+++ b/src/java/com/android/internal/telephony/metrics/SatelliteStats.java
@@ -732,12 +732,19 @@
private final int mCountOfTimerStarted;
private final boolean mIsImsRegistered;
private final int mCellularServiceState;
+ private final boolean mIsMultiSim;
+ private final int mRecommendingHandoverType;
+ private final boolean mIsSatelliteAllowedInCurrentLocation;
private SatelliteSosMessageRecommenderParams(Builder builder) {
this.mIsDisplaySosMessageSent = builder.mIsDisplaySosMessageSent;
this.mCountOfTimerStarted = builder.mCountOfTimerStarted;
this.mIsImsRegistered = builder.mIsImsRegistered;
this.mCellularServiceState = builder.mCellularServiceState;
+ this.mIsMultiSim = builder.mIsMultiSim;
+ this.mRecommendingHandoverType = builder.mRecommendingHandoverType;
+ this.mIsSatelliteAllowedInCurrentLocation =
+ builder.mIsSatelliteAllowedInCurrentLocation;
}
public boolean isDisplaySosMessageSent() {
@@ -756,6 +763,18 @@
return mCellularServiceState;
}
+ public boolean isMultiSim() {
+ return mIsMultiSim;
+ }
+
+ public int getRecommendingHandoverType() {
+ return mRecommendingHandoverType;
+ }
+
+ public boolean isSatelliteAllowedInCurrentLocation() {
+ return mIsSatelliteAllowedInCurrentLocation;
+ }
+
/**
* A builder class to create {@link SatelliteProvisionParams} data structure class
*/
@@ -764,6 +783,10 @@
private int mCountOfTimerStarted = -1;
private boolean mIsImsRegistered = false;
private int mCellularServiceState = -1;
+ private boolean mIsMultiSim = false;
+ private int mRecommendingHandoverType = -1;
+ private boolean mIsSatelliteAllowedInCurrentLocation = false;
+
/**
* Sets resultCode value of {@link SatelliteSosMessageRecommender} atom
@@ -803,6 +826,34 @@
}
/**
+ * Sets isMultiSim value of {@link SatelliteSosMessageRecommender} atom
+ * then returns Builder class
+ */
+ public Builder setIsMultiSim(boolean isMultiSim) {
+ this.mIsMultiSim = isMultiSim;
+ return this;
+ }
+
+ /**
+ * Sets recommendingHandoverType value of {@link SatelliteSosMessageRecommender} atom
+ * then returns Builder class
+ */
+ public Builder setRecommendingHandoverType(int recommendingHandoverType) {
+ this.mRecommendingHandoverType = recommendingHandoverType;
+ return this;
+ }
+
+ /**
+ * Sets isSatelliteAllowedInCurrentLocation value of
+ * {@link SatelliteSosMessageRecommender} atom then returns Builder class.
+ */
+ public Builder setIsSatelliteAllowedInCurrentLocation(
+ boolean satelliteAllowedInCurrentLocation) {
+ mIsSatelliteAllowedInCurrentLocation = satelliteAllowedInCurrentLocation;
+ return this;
+ }
+
+ /**
* Returns SosMessageRecommenderParams, which contains whole component of
* {@link SatelliteSosMessageRecommenderParams} atom
*/
@@ -818,7 +869,11 @@
+ "isDisplaySosMessageSent=" + mIsDisplaySosMessageSent
+ ", countOfTimerStarted=" + mCountOfTimerStarted
+ ", isImsRegistered=" + mIsImsRegistered
- + ", cellularServiceState=" + mCellularServiceState + ")";
+ + ", cellularServiceState=" + mCellularServiceState
+ + ", isMultiSim=" + mIsMultiSim
+ + ", recommendingHandoverType=" + mRecommendingHandoverType
+ + ", isSatelliteAllowedInCurrentLocation="
+ + mIsSatelliteAllowedInCurrentLocation + ")";
}
}
@@ -899,6 +954,9 @@
proto.countOfTimerStarted = param.getCountOfTimerStarted();
proto.isImsRegistered = param.isImsRegistered();
proto.cellularServiceState = param.getCellularServiceState();
+ proto.isMultiSim = param.isMultiSim();
+ proto.recommendingHandoverType = param.getRecommendingHandoverType();
+ proto.isSatelliteAllowedInCurrentLocation = param.isSatelliteAllowedInCurrentLocation();
proto.count = 1;
mAtomsStorage.addSatelliteSosMessageRecommenderStats(proto);
}
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramController.java b/src/java/com/android/internal/telephony/satellite/DatagramController.java
index 32acdcf..0c68d4b 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramController.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramController.java
@@ -46,6 +46,7 @@
@NonNull private final PointingAppController mPointingAppController;
@NonNull private final DatagramDispatcher mDatagramDispatcher;
@NonNull private final DatagramReceiver mDatagramReceiver;
+
public static final long MAX_DATAGRAM_ID = (long) Math.pow(2, 16);
public static final int ROUNDING_UNIT = 10;
public static final long SATELLITE_ALIGN_TIMEOUT = TimeUnit.SECONDS.toMillis(30);
@@ -403,6 +404,18 @@
}
}
+ /**
+ * This API can be used by only CTS to override the cached value for the device overlay config
+ * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
+ * outgoing satellite datagrams should be sent to modem in demo mode.
+ *
+ * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
+ * satellite modem or not.
+ */
+ void setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) {
+ mDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
+ }
+
private static void logd(@NonNull String log) {
Rlog.d(TAG, log);
}
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
index 6ccc3e6..ddd0a69 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramDispatcher.java
@@ -17,12 +17,14 @@
package com.android.internal.telephony.satellite;
import static android.telephony.satellite.SatelliteManager.SATELLITE_MODEM_STATE_CONNECTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
import static com.android.internal.telephony.satellite.DatagramController.ROUNDING_UNIT;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
+import android.content.res.Resources;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Looper;
@@ -32,6 +34,7 @@
import android.telephony.satellite.SatelliteDatagram;
import android.telephony.satellite.SatelliteManager;
+import com.android.internal.R;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
@@ -41,6 +44,7 @@
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Consumer;
@@ -66,6 +70,8 @@
private static AtomicLong mNextDatagramId = new AtomicLong(0);
+ private AtomicBoolean mShouldSendDatagramToModemInDemoMode = null;
+
private final Object mLock = new Object();
@GuardedBy("mLock")
@@ -190,9 +196,14 @@
(SendSatelliteDatagramArgument) request.argument;
onCompleted = obtainMessage(EVENT_SEND_SATELLITE_DATAGRAM_DONE, request);
- SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram,
- argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
- argument.needFullScreenPointingUI, onCompleted);
+ if (mIsDemoMode && !shouldSendDatagramToModemInDemoMode()) {
+ AsyncResult.forMessage(onCompleted, SATELLITE_RESULT_SUCCESS, null);
+ onCompleted.sendToTarget();
+ } else {
+ SatelliteModemInterface.getInstance().sendSatelliteDatagram(argument.datagram,
+ argument.datagramType == SatelliteManager.DATAGRAM_TYPE_SOS_MESSAGE,
+ argument.needFullScreenPointingUI, onCompleted);
+ }
break;
}
case EVENT_SEND_SATELLITE_DATAGRAM_DONE: {
@@ -621,6 +632,50 @@
}
}
+ private boolean shouldSendDatagramToModemInDemoMode() {
+ if (mShouldSendDatagramToModemInDemoMode != null) {
+ return mShouldSendDatagramToModemInDemoMode.get();
+ }
+
+ try {
+ mShouldSendDatagramToModemInDemoMode = new AtomicBoolean(
+ mContext.getResources().getBoolean(
+ R.bool.config_send_satellite_datagram_to_modem_in_demo_mode));
+ return mShouldSendDatagramToModemInDemoMode.get();
+
+ } catch (Resources.NotFoundException ex) {
+ loge("shouldSendDatagramToModemInDemoMode: id= "
+ + R.bool.config_send_satellite_datagram_to_modem_in_demo_mode + ", ex=" + ex);
+ return false;
+ }
+ }
+
+ /**
+ * This API can be used by only CTS to override the cached value for the device overlay config
+ * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
+ * outgoing satellite datagrams should be sent to modem in demo mode.
+ *
+ * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
+ * satellite modem or not. If it is null, the cache will be cleared.
+ */
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected void setShouldSendDatagramToModemInDemoMode(
+ @Nullable Boolean shouldSendToModemInDemoMode) {
+ logd("setShouldSendDatagramToModemInDemoMode(" + (shouldSendToModemInDemoMode == null
+ ? "null" : shouldSendToModemInDemoMode) + ")");
+
+ if (shouldSendToModemInDemoMode == null) {
+ mShouldSendDatagramToModemInDemoMode = null;
+ } else {
+ if (mShouldSendDatagramToModemInDemoMode == null) {
+ mShouldSendDatagramToModemInDemoMode = new AtomicBoolean(
+ shouldSendToModemInDemoMode);
+ } else {
+ mShouldSendDatagramToModemInDemoMode.set(shouldSendToModemInDemoMode);
+ }
+ }
+ }
+
private static void logd(@NonNull String log) {
Rlog.d(TAG, log);
}
diff --git a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
index fd04779..695a563 100644
--- a/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
+++ b/src/java/com/android/internal/telephony/satellite/DatagramReceiver.java
@@ -496,7 +496,7 @@
*/
@SatelliteManager.SatelliteResult public int registerForSatelliteDatagram(int subId,
@NonNull ISatelliteDatagramCallback callback) {
- if (!SatelliteController.getInstance().isSatelliteSupported()) {
+ if (!SatelliteController.getInstance().isSatelliteSupportedViaOem()) {
return SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteController.java b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
index 5148ecb..af4081a 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteController.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteController.java
@@ -16,9 +16,14 @@
package com.android.internal.telephony.satellite;
+import static android.telephony.CarrierConfigManager.KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
import static android.telephony.SubscriptionManager.SATELLITE_ATTACH_ENABLED_FOR_CARRIER;
import static android.telephony.SubscriptionManager.isValidSubscriptionId;
import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
+import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
import static android.telephony.satellite.SatelliteManager.KEY_NTN_SIGNAL_STRENGTH;
import static android.telephony.satellite.SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_USER;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
@@ -51,13 +56,16 @@
import android.os.PersistableBundle;
import android.os.RemoteException;
import android.os.ResultReceiver;
+import android.os.SystemClock;
import android.os.SystemProperties;
import android.provider.Settings;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
+import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import android.telephony.satellite.INtnSignalStrengthCallback;
+import android.telephony.satellite.ISatelliteCapabilitiesCallback;
import android.telephony.satellite.ISatelliteDatagramCallback;
import android.telephony.satellite.ISatelliteProvisionStateCallback;
import android.telephony.satellite.ISatelliteStateCallback;
@@ -68,6 +76,7 @@
import android.telephony.satellite.SatelliteManager;
import android.util.Log;
import android.util.SparseArray;
+import android.util.SparseBooleanArray;
import android.uwb.UwbManager;
import com.android.internal.R;
@@ -77,6 +86,7 @@
import com.android.internal.telephony.DeviceStateMonitor;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
import com.android.internal.telephony.satellite.metrics.ProvisionMetricsStats;
@@ -111,6 +121,7 @@
/** Value to pass for the setting key SATELLITE_MODE_ENABLED, enabled = 1, disabled = 0 */
public static final int SATELLITE_MODE_ENABLED_TRUE = 1;
public static final int SATELLITE_MODE_ENABLED_FALSE = 0;
+ public static final int INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE = -1;
/** Message codes used in handleMessage() */
//TODO: Move the Commands and events related to position updates to PointingAppController
@@ -146,8 +157,10 @@
private static final int CMD_REQUEST_NTN_SIGNAL_STRENGTH = 32;
private static final int EVENT_REQUEST_NTN_SIGNAL_STRENGTH_DONE = 33;
private static final int EVENT_NTN_SIGNAL_STRENGTH_CHANGED = 34;
- private static final int CMD_START_SENDING_NTN_SIGNAL_STRENGTH = 35;
- private static final int EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING = 36;
+ private static final int CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING = 35;
+ private static final int EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE = 36;
+ private static final int EVENT_SERVICE_STATE_CHANGED = 37;
+ private static final int EVENT_SATELLITE_CAPABILITIES_CHANGED = 38;
@NonNull private static SatelliteController sInstance;
@NonNull private final Context mContext;
@@ -159,12 +172,12 @@
@NonNull private final ProvisionMetricsStats mProvisionMetricsStats;
@NonNull private final SubscriptionManagerService mSubscriptionManagerService;
private final CommandsInterface mCi;
- private ContentResolver mContentResolver = null;
+ private ContentResolver mContentResolver;
private final DeviceStateMonitor mDSM;
private final Object mRadioStateLock = new Object();
- /** Flags to indicate whether the resepective radio is enabled */
+ /** Flags to indicate whether the respective radio is enabled */
@GuardedBy("mRadioStateLock")
private boolean mBTStateEnabled = false;
@GuardedBy("mRadioStateLock")
@@ -199,6 +212,8 @@
private final AtomicBoolean mRegisteredForSatelliteModemStateChangedWithSatelliteService =
new AtomicBoolean(false);
private final AtomicBoolean mRegisteredForNtnSignalStrengthChanged = new AtomicBoolean(false);
+ private final AtomicBoolean mRegisteredForSatelliteCapabilitiesChanged =
+ new AtomicBoolean(false);
/**
* Map key: subId, value: callback to get error code of the provision request.
*/
@@ -216,6 +231,12 @@
*/
private final ConcurrentHashMap<IBinder, INtnSignalStrengthCallback>
mNtnSignalStrengthChangedListeners = new ConcurrentHashMap<>();
+ /**
+ * Map key: binder of the callback, value: callback to receive satellite capabilities changed
+ * events.
+ */
+ private final ConcurrentHashMap<IBinder, ISatelliteCapabilitiesCallback>
+ mSatelliteCapabilitiesChangedListeners = new ConcurrentHashMap<>();
private final Object mIsSatelliteSupportedLock = new Object();
@GuardedBy("mIsSatelliteSupportedLock")
private Boolean mIsSatelliteSupported = null;
@@ -261,6 +282,32 @@
@NonNull private final Map<Integer, Boolean> mIsSatelliteAttachEnabledForCarrierArrayPerSub =
new HashMap<>();
@NonNull private final FeatureFlags mFeatureFlags;
+ @NonNull private final Object mSatelliteConnectedLock = new Object();
+ /** Key: Subscription ID; Value: Last satellite connected time */
+ @GuardedBy("mSatelliteConnectedLock")
+ @NonNull private final SparseArray<Long> mLastSatelliteDisconnectedTimesMillis =
+ new SparseArray<>();
+ /**
+ * Key: Subscription ID; Value: {@code true} if satellite was just connected,
+ * {@code false} otherwise.
+ */
+ @GuardedBy("mSatelliteConnectedLock")
+ @NonNull private final SparseBooleanArray
+ mWasSatelliteConnectedViaCarrier = new SparseBooleanArray();
+
+ @GuardedBy("mSatelliteConnectedLock")
+ @NonNull private final SparseBooleanArray
+ mIsSatelliteConnectedViaCarrierHysteresisTimeExpired = new SparseBooleanArray();
+
+ /**
+ * This is used for testing only. When mEnforcedEmergencyCallToSatelliteHandoverType is valid,
+ * Telephony will ignore the IMS registration status and cellular availability, and always send
+ * the connection event EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
+ */
+ private int mEnforcedEmergencyCallToSatelliteHandoverType =
+ INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+ private int mDelayInSendingEventDisplayEmergencyMessage = 0;
+
/**
* @return The singleton instance of SatelliteController.
*/
@@ -332,6 +379,7 @@
registerForSatelliteProvisionStateChanged();
registerForPendingDatagramCount();
registerForSatelliteModemStateChanged();
+ registerForServiceStateChanged();
mContentResolver = mContext.getContentResolver();
mCarrierConfigManager = mContext.getSystemService(CarrierConfigManager.class);
@@ -356,7 +404,7 @@
handleCarrierConfigChanged(slotIndex, subId, carrierId, specificCarrierId);
mCarrierConfigManager.registerCarrierConfigChangeListener(
new HandlerExecutor(new Handler(looper)), mCarrierConfigChangeListener);
- mDSM.registerForSignalStrengthReportDecision(this, CMD_START_SENDING_NTN_SIGNAL_STRENGTH,
+ mDSM.registerForSignalStrengthReportDecision(this, CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING,
null);
}
@@ -1133,16 +1181,16 @@
break;
}
- case CMD_START_SENDING_NTN_SIGNAL_STRENGTH: {
+ case CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: {
ar = (AsyncResult) msg.obj;
boolean shouldReport = (boolean) ar.result;
- logd("CMD_START_SENDING_NTN_SIGNAL_STRENGTH: shouldReport=" + shouldReport);
+ logd("CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING: shouldReport=" + shouldReport);
request = new SatelliteControllerHandlerRequest(shouldReport,
SatelliteServiceUtils.getPhone());
if (SATELLITE_RESULT_SUCCESS != evaluateOemSatelliteRequestAllowed(true)) {
return;
}
- onCompleted = obtainMessage(EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING,
+ onCompleted = obtainMessage(EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE,
request);
if (shouldReport) {
mSatelliteModemInterface.startSendingNtnSignalStrength(onCompleted);
@@ -1152,11 +1200,11 @@
break;
}
- case EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING: {
+ case EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE: {
ar = (AsyncResult) msg.obj;
request = (SatelliteControllerHandlerRequest) ar.userObj;
int errorCode = SatelliteServiceUtils.getSatelliteError(ar,
- "EVENT_UPDATE_SIGNAL_STRENGTH_REPORTING");
+ "EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE");
if (errorCode != SATELLITE_RESULT_SUCCESS) {
loge(((boolean) request.argument ? "startSendingNtnSignalStrength"
: "stopSendingNtnSignalStrength") + "returns " + errorCode);
@@ -1164,6 +1212,21 @@
break;
}
+ case EVENT_SERVICE_STATE_CHANGED: {
+ handleEventServiceStateChanged();
+ break;
+ }
+
+ case EVENT_SATELLITE_CAPABILITIES_CHANGED: {
+ ar = (AsyncResult) msg.obj;
+ if (ar.result == null) {
+ loge("EVENT_SATELLITE_CAPABILITIES_CHANGED: result is null");
+ } else {
+ handleEventSatelliteCapabilitiesChanged((SatelliteCapabilities) ar.result);
+ }
+ break;
+ }
+
default:
Log.w(TAG, "SatelliteControllerHandler: unexpected message code: " +
msg.what);
@@ -1475,7 +1538,7 @@
return null;
}
- Boolean satelliteProvisioned = isSatelliteProvisioned();
+ Boolean satelliteProvisioned = isSatelliteViaOemProvisioned();
if (satelliteProvisioned != null && satelliteProvisioned) {
result.accept(SATELLITE_RESULT_SUCCESS);
return null;
@@ -1515,7 +1578,7 @@
return;
}
- Boolean satelliteProvisioned = isSatelliteProvisioned();
+ Boolean satelliteProvisioned = isSatelliteViaOemProvisioned();
if (satelliteProvisioned == null) {
result.accept(SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE);
return;
@@ -1929,7 +1992,7 @@
/**
* Registers for NTN signal strength changed from satellite modem.
*
- * @param subId The subId of the subscription to request for.
+ * @param subId The id of the subscription to request for.
* @param callback The callback to handle the non-terrestrial network signal strength changed
* event.
*
@@ -1950,7 +2013,8 @@
* Unregisters for NTN signal strength changed from satellite modem.
* If callback was not registered before, the request will be ignored.
*
- * @param subId The subId of the subscription to unregister for provision state changed.
+ * @param subId The id of the subscription to unregister for listening NTN signal strength
+ * changed event.
* @param callback The callback that was passed to
* {@link #registerForNtnSignalStrengthChanged(int, INtnSignalStrengthCallback)}
*/
@@ -1965,6 +2029,44 @@
}
/**
+ * Registers for satellite capabilities change event from the satellite service.
+ *
+ * @param subId The id of the subscription to request for.
+ * @param callback The callback to handle the satellite capabilities changed event.
+ *
+ * @return The {@link SatelliteManager.SatelliteResult} result of the operation.
+ */
+ @SatelliteManager.SatelliteResult public int registerForSatelliteCapabilitiesChanged(
+ int subId, @NonNull ISatelliteCapabilitiesCallback callback) {
+ if (DBG) logd("registerForSatelliteCapabilitiesChanged()");
+
+ int error = evaluateOemSatelliteRequestAllowed(true);
+ if (error != SATELLITE_RESULT_SUCCESS) return error;
+
+ mSatelliteCapabilitiesChangedListeners.put(callback.asBinder(), callback);
+ return SATELLITE_RESULT_SUCCESS;
+ }
+
+ /**
+ * Unregisters for satellite capabilities change event from the satellite service.
+ * If callback was not registered before, the request will be ignored.
+ *
+ * @param subId The id of the subscription to unregister for listening satellite capabilities
+ * changed event.
+ * @param callback The callback that was passed to
+ * {@link #registerForSatelliteCapabilitiesChanged(int, ISatelliteCapabilitiesCallback)}
+ */
+ public void unregisterForSatelliteCapabilitiesChanged(
+ int subId, @NonNull ISatelliteCapabilitiesCallback callback) {
+ if (DBG) logd("unregisterForSatelliteCapabilitiesChanged()");
+
+ int error = evaluateOemSatelliteRequestAllowed(true);
+ if (error == SATELLITE_RESULT_SUCCESS) {
+ mSatelliteCapabilitiesChangedListeners.remove(callback.asBinder());
+ }
+ }
+
+ /**
* This API can be used by only CTS to update satellite vendor service package name.
*
* @param servicePackageName The package name of the satellite vendor service.
@@ -2072,6 +2174,53 @@
}
/**
+ * This API can be used in only testing to override connectivity status in monitoring emergency
+ * calls and sending EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
+ *
+ * @param handoverType The type of handover from emergency call to satellite messaging. Use one
+ * of the following values to enable the override:
+ * 0 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
+ * 1 - EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911
+ * To disable the override, use -1 for handoverType.
+ * @param delaySeconds The event EVENT_DISPLAY_EMERGENCY_MESSAGE will be sent to Dialer
+ * delaySeconds after the emergency call starts.
+ * @return {@code true} if the handover type is set successfully, {@code false} otherwise.
+ */
+ public boolean setEmergencyCallToSatelliteHandoverType(int handoverType, int delaySeconds) {
+ if (!isMockModemAllowed()) {
+ loge("setEmergencyCallToSatelliteHandoverType: mock modem not allowed");
+ return false;
+ }
+ if (isHandoverTypeValid(handoverType)) {
+ mEnforcedEmergencyCallToSatelliteHandoverType = handoverType;
+ mDelayInSendingEventDisplayEmergencyMessage = delaySeconds > 0 ? delaySeconds : 0;
+ } else {
+ mEnforcedEmergencyCallToSatelliteHandoverType =
+ INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+ mDelayInSendingEventDisplayEmergencyMessage = 0;
+ }
+ return true;
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected int getEnforcedEmergencyCallToSatelliteHandoverType() {
+ return mEnforcedEmergencyCallToSatelliteHandoverType;
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
+ protected int getDelayInSendingEventDisplayEmergencyMessage() {
+ return mDelayInSendingEventDisplayEmergencyMessage;
+ }
+
+ private boolean isHandoverTypeValid(int handoverType) {
+ if (handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS
+ || handoverType == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
* This function is used by {@link SatelliteModemInterface} to notify
* {@link SatelliteController} that the satellite vendor service was just connected.
* <p>
@@ -2132,14 +2281,15 @@
}
/**
- * @return {@code true} is satellite is supported on the device, {@code false} otherwise.
+ * @return {@code true} if satellite is supported via OEM on the device,
+ * {@code false} otherwise.
*/
- public boolean isSatelliteSupported() {
+ public boolean isSatelliteSupportedViaOem() {
if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
logd("isSatelliteSupported: oemEnabledSatelliteFlag is disabled");
return false;
}
- Boolean supported = isSatelliteSupportedInternal();
+ Boolean supported = isSatelliteSupportedViaOemInternal();
return (supported != null ? supported : false);
}
@@ -2218,10 +2368,92 @@
}
/**
+ * @return {@code true} if satellite is supported via carrier by any subscription on the device,
+ * {@code false} otherwise.
+ */
+ public boolean isSatelliteSupportedViaCarrier() {
+ if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+ logd("isSatelliteSupportedViaCarrier: carrierEnabledSatelliteFlag is disabled");
+ return false;
+ }
+ for (Phone phone : PhoneFactory.getPhones()) {
+ if (isSatelliteSupportedViaCarrier(phone.getSubId())) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return {@code true} if any subscription on the device is connected to satellite,
+ * {@code false} otherwise.
+ */
+ private boolean isUsingNonTerrestrialNetworkViaCarrier() {
+ if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+ logd("isUsingNonTerrestrialNetwork: carrierEnabledSatelliteFlag is disabled");
+ return false;
+ }
+ for (Phone phone : PhoneFactory.getPhones()) {
+ ServiceState serviceState = phone.getServiceState();
+ if (serviceState != null && serviceState.isUsingNonTerrestrialNetwork()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * @return {@code true} if the device is connected to satellite via any carrier within the
+ * {@link CarrierConfigManager#KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT}
+ * duration, {@code false} otherwise.
+ */
+ public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() {
+ if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+ logd("isSatelliteConnectedViaCarrierWithinHysteresisTime: carrierEnabledSatelliteFlag"
+ + " is disabled");
+ return false;
+ }
+ if (isUsingNonTerrestrialNetworkViaCarrier()) {
+ return true;
+ }
+ for (Phone phone : PhoneFactory.getPhones()) {
+ if (isSatelliteSupportedViaCarrier(phone.getSubId())) {
+ synchronized (mSatelliteConnectedLock) {
+ Boolean isHysteresisTimeExpired =
+ mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.get(
+ phone.getSubId());
+ if (isHysteresisTimeExpired != null && isHysteresisTimeExpired) {
+ continue;
+ }
+
+ Long lastDisconnectedTime =
+ mLastSatelliteDisconnectedTimesMillis.get(phone.getSubId());
+ long satelliteConnectionHysteresisTime =
+ getSatelliteConnectionHysteresisTimeMillis(phone.getSubId());
+ if (lastDisconnectedTime != null
+ && (getElapsedRealtime() - lastDisconnectedTime)
+ <= satelliteConnectionHysteresisTime) {
+ return true;
+ } else {
+ mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put(
+ phone.getSubId(), true);
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected long getElapsedRealtime() {
+ return SystemClock.elapsedRealtime();
+ }
+
+ /**
* If we have not successfully queried the satellite modem for its satellite service support,
* we will retry the query one more time. Otherwise, we will return the cached result.
*/
- private Boolean isSatelliteSupportedInternal() {
+ private Boolean isSatelliteSupportedViaOemInternal() {
synchronized (mIsSatelliteSupportedLock) {
if (mIsSatelliteSupported != null) {
/* We have already successfully queried the satellite modem. */
@@ -2352,7 +2584,7 @@
* @return true if satellite is provisioned on the given subscription else return false.
*/
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
- protected Boolean isSatelliteProvisioned() {
+ protected Boolean isSatelliteViaOemProvisioned() {
synchronized (mIsSatelliteProvisionedLock) {
if (mIsSatelliteProvisioned != null) {
return mIsSatelliteProvisioned;
@@ -2410,6 +2642,7 @@
registerForPendingDatagramCount();
registerForSatelliteModemStateChanged();
registerForNtnSignalStrengthChanged();
+ registerForSatelliteCapabilitiesChanged();
requestIsSatelliteProvisioned(SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
new ResultReceiver(this) {
@@ -2493,6 +2726,21 @@
}
}
+ private void registerForSatelliteCapabilitiesChanged() {
+ if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+ logd("registerForSatelliteCapabilitiesChanged: oemEnabledSatelliteFlag is disabled");
+ return;
+ }
+
+ if (mSatelliteModemInterface.isSatelliteServiceSupported()) {
+ if (!mRegisteredForSatelliteCapabilitiesChanged.get()) {
+ mSatelliteModemInterface.registerForSatelliteCapabilitiesChanged(
+ this, EVENT_SATELLITE_CAPABILITIES_CHANGED, null);
+ mRegisteredForSatelliteCapabilitiesChanged.set(true);
+ }
+ }
+ }
+
private void handleEventSatelliteProvisionStateChanged(boolean provisioned) {
logd("handleSatelliteProvisionStateChangedEvent: provisioned=" + provisioned);
@@ -2575,6 +2823,31 @@
});
}
+ private void handleEventSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) {
+ logd("handleEventSatelliteCapabilitiesChanged()");
+ if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+ logd("handleEventSatelliteCapabilitiesChanged: oemEnabledSatelliteFlag is disabled");
+ return;
+ }
+
+ synchronized (mSatelliteCapabilitiesLock) {
+ mSatelliteCapabilities = capabilities;
+ }
+
+ List<ISatelliteCapabilitiesCallback> deadCallersList = new ArrayList<>();
+ mSatelliteCapabilitiesChangedListeners.values().forEach(listener -> {
+ try {
+ listener.onSatelliteCapabilitiesChanged(capabilities);
+ } catch (RemoteException e) {
+ logd("handleEventSatelliteCapabilitiesChanged RemoteException: " + e);
+ deadCallersList.add(listener);
+ }
+ });
+ deadCallersList.forEach(listener -> {
+ mSatelliteCapabilitiesChangedListeners.remove(listener.asBinder());
+ });
+ }
+
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
protected void setSettingsKeyForSatelliteMode(int val) {
logd("setSettingsKeyForSatelliteMode val: " + val);
@@ -2724,16 +2997,16 @@
mCarrierConfigArray.put(subId, config);
}
return SatelliteServiceUtils.parseSupportedSatelliteServices(
- config.getPersistableBundle(CarrierConfigManager
- .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
+ config.getPersistableBundle(
+ KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE));
}
}
@NonNull private PersistableBundle getConfigForSubId(int subId) {
PersistableBundle config = mCarrierConfigManager.getConfigForSubId(subId,
- CarrierConfigManager
- .KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
- CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
+ KEY_CARRIER_SUPPORTED_SATELLITE_SERVICES_PER_PROVIDER_BUNDLE,
+ KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+ KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT);
if (config == null || config.isEmpty()) {
config = CarrierConfigManager.getDefaultConfig();
}
@@ -2799,10 +3072,9 @@
return strArray;
}
- private boolean isSatelliteSupportedForCarrier(int subId) {
+ private boolean isSatelliteSupportedViaCarrier(int subId) {
return getConfigForSubId(subId)
- .getBoolean(CarrierConfigManager
- .KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
+ .getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL);
}
/**
@@ -2951,7 +3223,7 @@
+ "SetSatelliteAttachEnableForCarrier error code =" + errorCode);
}
- if (!isSatelliteSupportedForCarrier(subId)) {
+ if (!isSatelliteSupportedViaCarrier(subId)) {
logd("Satellite for carrier is not supported. Only user setting is stored");
callback.accept(SATELLITE_RESULT_SUCCESS);
return;
@@ -2991,7 +3263,7 @@
return SatelliteManager.SATELLITE_RESULT_REQUEST_NOT_SUPPORTED;
}
- Boolean satelliteSupported = isSatelliteSupportedInternal();
+ Boolean satelliteSupported = isSatelliteSupportedViaOemInternal();
if (satelliteSupported == null) {
return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
}
@@ -3000,7 +3272,7 @@
}
if (isProvisionRequired) {
- Boolean satelliteProvisioned = isSatelliteProvisioned();
+ Boolean satelliteProvisioned = isSatelliteViaOemProvisioned();
if (satelliteProvisioned == null) {
return SatelliteManager.SATELLITE_RESULT_INVALID_TELEPHONY_STATE;
}
@@ -3036,6 +3308,81 @@
.reportSessionMetrics();
}
+ private void registerForServiceStateChanged() {
+ if (!mFeatureFlags.carrierEnabledSatelliteFlag()) {
+ return;
+ }
+ for (Phone phone : PhoneFactory.getPhones()) {
+ phone.registerForServiceStateChanged(this, EVENT_SERVICE_STATE_CHANGED, null);
+ }
+ }
+
+ private void handleEventServiceStateChanged() {
+ handleServiceStateForSatelliteConnectionViaCarrier();
+ }
+
+ private void handleServiceStateForSatelliteConnectionViaCarrier() {
+ for (Phone phone : PhoneFactory.getPhones()) {
+ ServiceState serviceState = phone.getServiceState();
+ if (serviceState != null) {
+ synchronized (mSatelliteConnectedLock) {
+ if (serviceState.isUsingNonTerrestrialNetwork()) {
+ mWasSatelliteConnectedViaCarrier.put(phone.getSubId(), true);
+ mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put(
+ phone.getSubId(), false);
+ } else {
+ Boolean connected = mWasSatelliteConnectedViaCarrier.get(phone.getSubId());
+ if (connected != null && connected) {
+ // The device just got disconnected from a satellite network.
+ mLastSatelliteDisconnectedTimesMillis.put(
+ phone.getSubId(), getElapsedRealtime());
+ mIsSatelliteConnectedViaCarrierHysteresisTimeExpired.put(
+ phone.getSubId(), false);
+ }
+ mWasSatelliteConnectedViaCarrier.put(phone.getSubId(), false);
+ }
+ }
+ }
+ }
+ }
+
+ private long getSatelliteConnectionHysteresisTimeMillis(int subId) {
+ synchronized (mCarrierConfigArrayLock) {
+ PersistableBundle config = mCarrierConfigArray.get(subId);
+ if (config == null) {
+ config = getConfigForSubId(subId);
+ mCarrierConfigArray.put(subId, config);
+ }
+ return (config.getInt(
+ KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT) * 1000L);
+ }
+ }
+
+ /**
+ * This API can be used by only CTS to override the cached value for the device overlay config
+ * value : config_send_satellite_datagram_to_modem_in_demo_mode, which determines whether
+ * outgoing satellite datagrams should be sent to modem in demo mode.
+ *
+ * @param shouldSendToModemInDemoMode Whether send datagram in demo mode should be sent to
+ * satellite modem or not.
+ *
+ * @return {@code true} if the operation is successful, {@code false} otherwise.
+ */
+ public boolean setShouldSendDatagramToModemInDemoMode(boolean shouldSendToModemInDemoMode) {
+ if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+ logd("setShouldSendDatagramToModemInDemoMode: oemEnabledSatelliteFlag is disabled");
+ return false;
+ }
+
+ if (!isMockModemAllowed()) {
+ logd("setShouldSendDatagramToModemInDemoMode: mock modem not allowed.");
+ return false;
+ }
+
+ mDatagramController.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
+ return true;
+ }
+
private static void logd(@NonNull String log) {
Rlog.d(TAG, log);
}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
index dc6ea13..3d629db 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteModemInterface.java
@@ -91,6 +91,8 @@
new RegistrantList();
@NonNull private final RegistrantList mNtnSignalStrengthChangedRegistrants =
new RegistrantList();
+ @NonNull private final RegistrantList mSatelliteCapabilitiesChangedRegistrants =
+ new RegistrantList();
@NonNull private final ISatelliteListener mListener = new ISatelliteListener.Stub() {
@Override
@@ -145,7 +147,14 @@
public void onNtnSignalStrengthChanged(
android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) {
mNtnSignalStrengthChangedRegistrants.notifyResult(
- SatelliteServiceUtils.fromModemInterface(ntnSignalStrength));
+ SatelliteServiceUtils.fromNtnSignalStrength(ntnSignalStrength));
+ }
+
+ @Override
+ public void onSatelliteCapabilitiesChanged(
+ android.telephony.satellite.stub.SatelliteCapabilities satelliteCapabilities) {
+ mSatelliteCapabilitiesChangedRegistrants.notifyResult(
+ SatelliteServiceUtils.fromSatelliteCapabilities(satelliteCapabilities));
}
};
@@ -473,6 +482,27 @@
}
/**
+ * Registers for satellite capabilities changed.
+ *
+ * @param h Handler for notification message.
+ * @param what User-defined message code.
+ * @param obj User object.
+ */
+ public void registerForSatelliteCapabilitiesChanged(
+ @NonNull Handler h, int what, @Nullable Object obj) {
+ mSatelliteCapabilitiesChangedRegistrants.add(h, what, obj);
+ }
+
+ /**
+ * Unregisters for satellite capabilities changed.
+ *
+ * @param h Handler to be removed from the registrant list.
+ */
+ public void unregisterForSatelliteCapabilitiesChanged(@NonNull Handler h) {
+ mSatelliteCapabilitiesChangedRegistrants.remove(h);
+ }
+
+ /**
* Request to enable or disable the satellite service listening mode.
* Listening mode allows the satellite service to listen for incoming pages.
*
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
index 9bf82d1..f40880b 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommender.java
@@ -16,16 +16,31 @@
package com.android.internal.telephony.satellite;
+import static android.telephony.ServiceState.STATE_EMERGENCY_ONLY;
+import static android.telephony.ServiceState.STATE_IN_SERVICE;
+import static android.telephony.ServiceState.STATE_OUT_OF_SERVICE;
+import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT;
+import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_SUCCESS;
+import static com.android.internal.telephony.satellite.SatelliteController.INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+
import android.annotation.NonNull;
-import android.os.AsyncResult;
+import android.annotation.Nullable;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.res.Resources;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.ResultReceiver;
+import android.os.SystemProperties;
import android.provider.DeviceConfig;
import android.telecom.Connection;
import android.telephony.Rlog;
@@ -36,16 +51,20 @@
import android.telephony.ims.ImsRegistrationAttributes;
import android.telephony.ims.RegistrationManager;
import android.telephony.satellite.ISatelliteProvisionStateCallback;
+import android.text.TextUtils;
import android.util.Pair;
+import android.util.SparseArray;
import com.android.ims.ImsException;
import com.android.ims.ImsManager;
+import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
+import com.android.internal.telephony.SmsApplication;
import com.android.internal.telephony.metrics.SatelliteStats;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
/**
@@ -56,74 +75,48 @@
*/
public class SatelliteSOSMessageRecommender extends Handler {
private static final String TAG = "SatelliteSOSMessageRecommender";
-
- /**
- * Device config for the timeout duration in milliseconds to determine whether to recommend
- * Dialer to show the SOS button to users.
- * <p>
- * The timer is started when there is an ongoing emergency call, and the IMS is not registered,
- * and cellular service is not available. When the timer expires, SatelliteSOSMessageRecommender
- * will send the event EVENT_DISPLAY_SOS_MESSAGE to Dialer, which will then prompt user to
- * switch to using satellite SOS messaging.
- */
- public static final String EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS =
- "emergency_call_to_sos_msg_hysteresis_timeout_millis";
- /**
- * The default value of {@link #EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS} when it is
- * not provided in the device config.
- */
- public static final long DEFAULT_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 20000;
-
+ private static final String ALLOW_MOCK_MODEM_PROPERTY = "persist.radio.allow_mock_modem";
+ private static final String BOOT_ALLOW_MOCK_MODEM_PROPERTY = "ro.boot.radio.allow_mock_modem";
private static final int EVENT_EMERGENCY_CALL_STARTED = 1;
- protected static final int EVENT_CELLULAR_SERVICE_STATE_CHANGED = 2;
- private static final int EVENT_IMS_REGISTRATION_STATE_CHANGED = 3;
- protected static final int EVENT_TIME_OUT = 4;
- private static final int EVENT_SATELLITE_PROVISIONED_STATE_CHANGED = 5;
- private static final int EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED = 6;
+ protected static final int EVENT_SERVICE_STATE_CHANGED = 2;
+ protected static final int EVENT_TIME_OUT = 3;
+ private static final int EVENT_SATELLITE_PROVISIONED_STATE_CHANGED = 4;
+ private static final int EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED = 5;
+ private static final int CMD_SEND_EVENT_DISPLAY_EMERGENCY_MESSAGE_FORCEFULLY = 6;
+ @NonNull private final Context mContext;
@NonNull
private final SatelliteController mSatelliteController;
private ImsManager mImsManager;
private Connection mEmergencyConnection = null;
- /* The phone used for emergency call */
- private Phone mPhone = null;
private final ISatelliteProvisionStateCallback mISatelliteProvisionStateCallback;
- @ServiceState.RegState
- private AtomicInteger mCellularServiceState = new AtomicInteger();
- private AtomicBoolean mIsImsRegistered = new AtomicBoolean();
+ /** Key: Phone ID; Value: IMS RegistrationCallback */
+ private SparseArray<RegistrationManager.RegistrationCallback>
+ mImsRegistrationCallbacks = new SparseArray<>();
private AtomicBoolean mIsSatelliteAllowedInCurrentLocation = new AtomicBoolean();
private final ResultReceiver mReceiverForRequestIsSatelliteAllowedForCurrentLocation;
private final long mTimeoutMillis;
+ private final AtomicBoolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime =
+ new AtomicBoolean(false);
protected int mCountOfTimerStarted = 0;
- private RegistrationManager.RegistrationCallback mImsRegistrationCallback =
- new RegistrationManager.RegistrationCallback() {
- @Override
- public void onRegistered(ImsRegistrationAttributes attributes) {
- sendMessage(obtainMessage(EVENT_IMS_REGISTRATION_STATE_CHANGED, true));
- }
-
- @Override
- public void onUnregistered(ImsReasonInfo info) {
- sendMessage(obtainMessage(EVENT_IMS_REGISTRATION_STATE_CHANGED, false));
- }
- };
-
/**
* Create an instance of SatelliteSOSMessageRecommender.
*
+ * @param context The Context for the SatelliteSOSMessageRecommender.
* @param looper The looper used with the handler of this class.
*/
- public SatelliteSOSMessageRecommender(@NonNull Looper looper) {
- this(looper, SatelliteController.getInstance(), null,
- getEmergencyCallToSosMsgHysteresisTimeoutMillis());
+ public SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper) {
+ this(context, looper, SatelliteController.getInstance(), null,
+ getEmergencyCallWaitForConnectionTimeoutMillis(context));
}
/**
* Create an instance of SatelliteSOSMessageRecommender. This constructor should be used in
* only unit tests.
*
+ * @param context The Context for the SatelliteSOSMessageRecommender.
* @param looper The looper used with the handler of this class.
* @param satelliteController The SatelliteController singleton instance.
* @param imsManager The ImsManager instance associated with the phone, which is used for making
@@ -131,10 +124,11 @@
* @param timeoutMillis The timeout duration of the timer.
*/
@VisibleForTesting
- protected SatelliteSOSMessageRecommender(@NonNull Looper looper,
+ protected SatelliteSOSMessageRecommender(@NonNull Context context, @NonNull Looper looper,
@NonNull SatelliteController satelliteController, ImsManager imsManager,
long timeoutMillis) {
super(looper);
+ mContext = context;
mSatelliteController = satelliteController;
mImsManager = imsManager;
mTimeoutMillis = timeoutMillis;
@@ -176,7 +170,7 @@
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case EVENT_EMERGENCY_CALL_STARTED:
- handleEmergencyCallStartedEvent((Pair<Connection, Phone>) msg.obj);
+ handleEmergencyCallStartedEvent((Connection) msg.obj);
break;
case EVENT_TIME_OUT:
handleTimeoutEvent();
@@ -187,12 +181,11 @@
case EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED:
handleEmergencyCallConnectionStateChangedEvent((Pair<String, Integer>) msg.obj);
break;
- case EVENT_IMS_REGISTRATION_STATE_CHANGED:
- handleImsRegistrationStateChangedEvent((boolean) msg.obj);
+ case EVENT_SERVICE_STATE_CHANGED:
+ handleStateChangedEventForHysteresisTimer();
break;
- case EVENT_CELLULAR_SERVICE_STATE_CHANGED:
- AsyncResult ar = (AsyncResult) msg.obj;
- handleCellularServiceStateChangedEvent((ServiceState) ar.result);
+ case CMD_SEND_EVENT_DISPLAY_EMERGENCY_MESSAGE_FORCEFULLY:
+ handleCmdSendEventDisplayEmergencyMessageForcefully((Connection) msg.obj);
break;
default:
logd("handleMessage: unexpected message code: " + msg.what);
@@ -205,15 +198,23 @@
*
* @param connection The connection created by TelephonyConnectionService for the emergency
* call.
- * @param phone The phone used for the emergency call.
*/
- public void onEmergencyCallStarted(@NonNull Connection connection, @NonNull Phone phone) {
- if (!mSatelliteController.isSatelliteSupported()) {
+ public void onEmergencyCallStarted(@NonNull Connection connection) {
+ if (!mSatelliteController.isSatelliteSupportedViaOem()
+ && !mSatelliteController.isSatelliteSupportedViaCarrier()) {
logd("onEmergencyCallStarted: satellite is not supported");
return;
}
- Pair<Connection, Phone> argument = new Pair<>(connection, phone);
- sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_STARTED, argument));
+
+ /**
+ * Right now, assume that the device is connected to satellite via carrier within hysteresis
+ * time. However, this might not be correct when the monitoring timer expires. Thus, we
+ * should do this check now so that we have higher chance of sending the event
+ * EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
+ */
+ mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set(
+ mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+ sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_STARTED, connection));
}
/**
@@ -225,7 +226,8 @@
*/
public void onEmergencyCallConnectionStateChanged(
String callId, @Connection.ConnectionState int state) {
- if (!mSatelliteController.isSatelliteSupported()) {
+ if (!mSatelliteController.isSatelliteSupportedViaOem()
+ && !mSatelliteController.isSatelliteSupportedViaCarrier()) {
logd("onEmergencyCallConnectionStateChanged: satellite is not supported");
return;
}
@@ -233,21 +235,23 @@
sendMessage(obtainMessage(EVENT_EMERGENCY_CALL_CONNECTION_STATE_CHANGED, argument));
}
- private void handleEmergencyCallStartedEvent(@NonNull Pair<Connection, Phone> arg) {
- mSatelliteController.requestIsSatelliteCommunicationAllowedForCurrentLocation(
- SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
- mReceiverForRequestIsSatelliteAllowedForCurrentLocation);
- if (mPhone != null) {
- logd("handleEmergencyCallStartedEvent: new emergency call started while there is "
- + " an ongoing call");
- unregisterForInterestedStateChangedEvents(mPhone);
+ @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
+ protected ComponentName getDefaultSmsApp() {
+ return SmsApplication.getDefaultSmsApplication(mContext, false);
+ }
+
+ private void handleEmergencyCallStartedEvent(@NonNull Connection connection) {
+ if (sendEventDisplayEmergencyMessageForcefully(connection)) {
+ return;
}
- mPhone = arg.second;
- mEmergencyConnection = arg.first;
- mCellularServiceState.set(mPhone.getServiceState().getState());
- mIsImsRegistered.set(mPhone.isImsRegistered());
- handleStateChangedEventForHysteresisTimer();
- registerForInterestedStateChangedEvents(mPhone);
+ if (mEmergencyConnection == null) {
+ mSatelliteController.requestIsSatelliteCommunicationAllowedForCurrentLocation(
+ SubscriptionManager.DEFAULT_SUBSCRIPTION_ID,
+ mReceiverForRequestIsSatelliteAllowedForCurrentLocation);
+ handleStateChangedEventForHysteresisTimer();
+ registerForInterestedStateChangedEvents();
+ }
+ mEmergencyConnection = connection;
}
private void handleSatelliteProvisionStateChangedEvent(boolean provisioned) {
@@ -257,20 +261,49 @@
}
private void handleTimeoutEvent() {
+ /**
+ * The device might be connected to satellite after the emergency call started. Thus, we
+ * need to do this check again so that we will have higher chance of sending the event
+ * EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer.
+ */
+ updateSatelliteViaCarrierAvailability();
+
boolean isDialerNotified = false;
- if (!mIsImsRegistered.get() && !isCellularAvailable()
+ if (!isImsRegistered() && !isCellularAvailable()
&& mIsSatelliteAllowedInCurrentLocation.get()
- && mSatelliteController.isSatelliteProvisioned()
+ && (isSatelliteViaOemAvailable() || isSatelliteViaCarrierAvailable())
&& shouldTrackCall(mEmergencyConnection.getState())) {
- logd("handleTimeoutEvent: Sending EVENT_DISPLAY_SOS_MESSAGE to Dialer...");
- mEmergencyConnection.sendConnectionEvent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE,
- null);
+ logd("handleTimeoutEvent: Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer");
+ Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
+ mEmergencyConnection.sendConnectionEvent(
+ TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
isDialerNotified = true;
+
}
+ logd("handleTimeoutEvent: isImsRegistered=" + isImsRegistered()
+ + ", isCellularAvailable=" + isCellularAvailable()
+ + ", mIsSatelliteAllowedInCurrentLocation="
+ + mIsSatelliteAllowedInCurrentLocation.get()
+ + ", shouldTrackCall=" + shouldTrackCall(mEmergencyConnection.getState()));
reportEsosRecommenderDecision(isDialerNotified);
cleanUpResources();
}
+ private void updateSatelliteViaCarrierAvailability() {
+ if (!mIsSatelliteConnectedViaCarrierWithinHysteresisTime.get()) {
+ mIsSatelliteConnectedViaCarrierWithinHysteresisTime.set(
+ mSatelliteController.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+ }
+ }
+
+ private boolean isSatelliteViaOemAvailable() {
+ return mSatelliteController.isSatelliteViaOemProvisioned();
+ }
+
+ private boolean isSatelliteViaCarrierAvailable() {
+ return mIsSatelliteConnectedViaCarrierWithinHysteresisTime.get();
+ }
+
private void handleEmergencyCallConnectionStateChangedEvent(
@NonNull Pair<String, Integer> arg) {
if (mEmergencyConnection == null) {
@@ -299,78 +332,117 @@
}
}
- private void handleImsRegistrationStateChangedEvent(boolean registered) {
- if (registered != mIsImsRegistered.get()) {
- mIsImsRegistered.set(registered);
- handleStateChangedEventForHysteresisTimer();
- }
- }
-
- private void handleCellularServiceStateChangedEvent(@NonNull ServiceState serviceState) {
- int state = serviceState.getState();
- if (mCellularServiceState.get() != state) {
- mCellularServiceState.set(state);
- handleStateChangedEventForHysteresisTimer();
- }
- }
-
private void reportEsosRecommenderDecision(boolean isDialerNotified) {
SatelliteStats.getInstance().onSatelliteSosMessageRecommender(
new SatelliteStats.SatelliteSosMessageRecommenderParams.Builder()
.setDisplaySosMessageSent(isDialerNotified)
.setCountOfTimerStarted(mCountOfTimerStarted)
- .setImsRegistered(mIsImsRegistered.get())
- .setCellularServiceState(mCellularServiceState.get())
+ .setImsRegistered(isImsRegistered())
+ .setCellularServiceState(getBestCellularServiceState())
+ .setIsMultiSim(isMultiSim())
+ .setRecommendingHandoverType(getEmergencyCallToSatelliteHandoverType())
+ .setIsSatelliteAllowedInCurrentLocation(
+ mIsSatelliteAllowedInCurrentLocation.get())
.build());
}
private void cleanUpResources() {
stopTimer();
- if (mPhone != null) {
- unregisterForInterestedStateChangedEvents(mPhone);
- mPhone = null;
+ if (mEmergencyConnection != null) {
+ unregisterForInterestedStateChangedEvents();
}
mEmergencyConnection = null;
mCountOfTimerStarted = 0;
}
- private void registerForInterestedStateChangedEvents(@NonNull Phone phone) {
+ private void registerForInterestedStateChangedEvents() {
mSatelliteController.registerForSatelliteProvisionStateChanged(
SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback);
- phone.registerForServiceStateChanged(this, EVENT_CELLULAR_SERVICE_STATE_CHANGED, null);
- registerForImsRegistrationStateChanged(phone);
+ for (Phone phone : PhoneFactory.getPhones()) {
+ phone.registerForServiceStateChanged(
+ this, EVENT_SERVICE_STATE_CHANGED, null);
+ registerForImsRegistrationStateChanged(phone);
+ }
}
private void registerForImsRegistrationStateChanged(@NonNull Phone phone) {
ImsManager imsManager = (mImsManager != null) ? mImsManager : ImsManager.getInstance(
phone.getContext(), phone.getPhoneId());
try {
- imsManager.addRegistrationCallback(mImsRegistrationCallback, this::post);
+ imsManager.addRegistrationCallback(
+ getOrCreateImsRegistrationCallback(phone.getPhoneId()), this::post);
} catch (ImsException ex) {
loge("registerForImsRegistrationStateChanged: ex=" + ex);
}
}
- private void unregisterForInterestedStateChangedEvents(@NonNull Phone phone) {
+ private void unregisterForInterestedStateChangedEvents() {
mSatelliteController.unregisterForSatelliteProvisionStateChanged(
SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, mISatelliteProvisionStateCallback);
- phone.unregisterForServiceStateChanged(this);
- unregisterForImsRegistrationStateChanged(phone);
+ for (Phone phone : PhoneFactory.getPhones()) {
+ phone.unregisterForServiceStateChanged(this);
+ unregisterForImsRegistrationStateChanged(phone);
+ }
}
private void unregisterForImsRegistrationStateChanged(@NonNull Phone phone) {
- ImsManager imsManager = (mImsManager != null) ? mImsManager : ImsManager.getInstance(
- phone.getContext(), phone.getPhoneId());
- imsManager.removeRegistrationListener(mImsRegistrationCallback);
+ if (mImsRegistrationCallbacks.contains(phone.getPhoneId())) {
+ ImsManager imsManager =
+ (mImsManager != null) ? mImsManager : ImsManager.getInstance(
+ phone.getContext(), phone.getPhoneId());
+ imsManager.removeRegistrationListener(
+ mImsRegistrationCallbacks.get(phone.getPhoneId()));
+ } else {
+ loge("Phone ID=" + phone.getPhoneId() + " was not registered with ImsManager");
+ }
}
private boolean isCellularAvailable() {
- return (mCellularServiceState.get() == ServiceState.STATE_IN_SERVICE
- || mCellularServiceState.get() == ServiceState.STATE_EMERGENCY_ONLY);
+ for (Phone phone : PhoneFactory.getPhones()) {
+ ServiceState serviceState = phone.getServiceState();
+ if (serviceState != null) {
+ int state = serviceState.getState();
+ if ((state == STATE_IN_SERVICE || state == STATE_EMERGENCY_ONLY)
+ && !serviceState.isUsingNonTerrestrialNetwork()) {
+ return true;
+ }
+ }
+ }
+ return false;
}
- private void handleStateChangedEventForHysteresisTimer() {
- if (!mIsImsRegistered.get() && !isCellularAvailable()) {
+ /**
+ * @return {@link ServiceState#STATE_IN_SERVICE} if any subscription is in this state; else
+ * {@link ServiceState#STATE_EMERGENCY_ONLY} if any subscription is in this state; else
+ * {@link ServiceState#STATE_OUT_OF_SERVICE}.
+ */
+ private int getBestCellularServiceState() {
+ boolean isStateOutOfService = true;
+ for (Phone phone : PhoneFactory.getPhones()) {
+ ServiceState serviceState = phone.getServiceState();
+ if (serviceState != null) {
+ int state = serviceState.getState();
+ if (!serviceState.isUsingNonTerrestrialNetwork()) {
+ if ((state == STATE_IN_SERVICE)) {
+ return STATE_IN_SERVICE;
+ } else if (state == STATE_EMERGENCY_ONLY) {
+ isStateOutOfService = false;
+ }
+ }
+ }
+ }
+ return isStateOutOfService ? STATE_OUT_OF_SERVICE : STATE_EMERGENCY_ONLY;
+ }
+
+ private boolean isImsRegistered() {
+ for (Phone phone : PhoneFactory.getPhones()) {
+ if (phone.isImsRegistered()) return true;
+ }
+ return false;
+ }
+
+ private synchronized void handleStateChangedEventForHysteresisTimer() {
+ if (!isImsRegistered() && !isCellularAvailable()) {
startTimer();
} else {
stopTimer();
@@ -389,10 +461,61 @@
removeMessages(EVENT_TIME_OUT);
}
- private static long getEmergencyCallToSosMsgHysteresisTimeoutMillis() {
- return DeviceConfig.getLong(DeviceConfig.NAMESPACE_TELEPHONY,
- EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS,
- DEFAULT_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+ private static long getEmergencyCallWaitForConnectionTimeoutMillis(@NonNull Context context) {
+ return context.getResources().getInteger(
+ R.integer.config_emergency_call_wait_for_connection_timeout_millis);
+ }
+
+ /**
+ * @return The Pair(PackageName, ClassName) of the oem-enabled satellite handover app.
+ */
+ @NonNull
+ private static Pair<String, String> getOemEnabledSatelliteHandoverAppFromOverlayConfig(
+ @NonNull Context context) {
+ String app = null;
+ try {
+ app = context.getResources().getString(
+ R.string.config_oem_enabled_satellite_sos_handover_app);
+ } catch (Resources.NotFoundException ex) {
+ loge("getOemEnabledSatelliteHandoverAppFromOverlayConfig: ex=" + ex);
+ }
+ if (TextUtils.isEmpty(app) && isMockModemAllowed()) {
+ logd("getOemEnabledSatelliteHandoverAppFromOverlayConfig: Read "
+ + "config_oem_enabled_satellite_sos_handover_app from device config");
+ app = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY,
+ "config_oem_enabled_satellite_sos_handover_app", "");
+ }
+ if (TextUtils.isEmpty(app)) return new Pair<>("", "");
+
+ String[] appComponent = app.split(";");
+ if (appComponent.length == 2) {
+ return new Pair<>(appComponent[0], appComponent[1]);
+ } else {
+ loge("getOemEnabledSatelliteHandoverAppFromOverlayConfig: invalid configured app="
+ + app);
+ }
+ return new Pair<>("", "");
+ }
+
+
+ @Nullable
+ private static String getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(
+ @NonNull Context context) {
+ String action;
+ try {
+ action = context.getResources().getString(
+ R.string.config_satellite_emergency_handover_intent_action);
+ } catch (Resources.NotFoundException ex) {
+ loge("getSatelliteEmergencyHandoverIntentFilterActionFromOverlayConfig: ex=" + ex);
+ action = null;
+ }
+ if (TextUtils.isEmpty(action) && isMockModemAllowed()) {
+ logd("getSatelliteEmergencyHandoverIntentActionFromOverlayConfig: Read "
+ + "config_satellite_emergency_handover_intent_action from device config");
+ action = DeviceConfig.getString(DeviceConfig.NAMESPACE_TELEPHONY,
+ "config_satellite_emergency_handover_intent_action", null);
+ }
+ return action;
}
private boolean shouldTrackCall(int connectionState) {
@@ -405,6 +528,110 @@
&& connectionState != Connection.STATE_DISCONNECTED);
}
+ @NonNull
+ private RegistrationManager.RegistrationCallback getOrCreateImsRegistrationCallback(
+ int phoneId) {
+ RegistrationManager.RegistrationCallback callback =
+ mImsRegistrationCallbacks.get(phoneId);
+ if (callback == null) {
+ callback = new RegistrationManager.RegistrationCallback() {
+ @Override
+ public void onRegistered(ImsRegistrationAttributes attributes) {
+ sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED));
+ }
+
+ @Override
+ public void onUnregistered(ImsReasonInfo info) {
+ sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED));
+ }
+ };
+ mImsRegistrationCallbacks.put(phoneId, callback);
+ }
+ return callback;
+ }
+
+ @NonNull private Bundle createExtraBundleForEventDisplayEmergencyMessage() {
+ int handoverType = EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+ Pair<String, String> oemSatelliteMessagingApp =
+ getOemEnabledSatelliteHandoverAppFromOverlayConfig(mContext);
+ String packageName = oemSatelliteMessagingApp.first;
+ String className = oemSatelliteMessagingApp.second;
+ String action = getSatelliteEmergencyHandoverIntentActionFromOverlayConfig(mContext);
+
+ if (isSatelliteViaCarrierAvailable()
+ || isEmergencyCallToSatelliteHandoverTypeT911Enforced()) {
+ ComponentName defaultSmsAppComponent = getDefaultSmsApp();
+ handoverType = EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
+ packageName = defaultSmsAppComponent.getPackageName();
+ className = defaultSmsAppComponent.getClassName();
+ }
+ logd("EVENT_DISPLAY_EMERGENCY_MESSAGE: handoverType=" + handoverType + ", packageName="
+ + packageName + ", className=" + className + ", action=" + action);
+
+ Bundle result = new Bundle();
+ result.putInt(EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE, handoverType);
+ if (!TextUtils.isEmpty(packageName) && !TextUtils.isEmpty(className)) {
+ result.putParcelable(EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT,
+ createHandoverAppLaunchPendingIntent(packageName, className, action));
+ }
+ return result;
+ }
+
+ @NonNull private PendingIntent createHandoverAppLaunchPendingIntent(
+ @NonNull String packageName, @NonNull String className, @Nullable String action) {
+ Intent intent = new Intent(action);
+ intent.setComponent(new ComponentName(packageName, className));
+ return PendingIntent.getActivity(mContext, 0, intent,
+ PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_IMMUTABLE);
+ }
+
+ private boolean isEmergencyCallToSatelliteHandoverTypeT911Enforced() {
+ return (mSatelliteController.getEnforcedEmergencyCallToSatelliteHandoverType()
+ == EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911);
+ }
+
+ private boolean sendEventDisplayEmergencyMessageForcefully(@NonNull Connection connection) {
+ if (mSatelliteController.getEnforcedEmergencyCallToSatelliteHandoverType()
+ == INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE) {
+ return false;
+ }
+
+ long delaySeconds = mSatelliteController.getDelayInSendingEventDisplayEmergencyMessage();
+ sendMessageDelayed(
+ obtainMessage(CMD_SEND_EVENT_DISPLAY_EMERGENCY_MESSAGE_FORCEFULLY, connection),
+ delaySeconds * 1000);
+ return true;
+ }
+
+ private void handleCmdSendEventDisplayEmergencyMessageForcefully(
+ @NonNull Connection connection) {
+ logd("Sent EVENT_DISPLAY_EMERGENCY_MESSAGE to Dialer forcefully.");
+ Bundle extras = createExtraBundleForEventDisplayEmergencyMessage();
+ connection.sendConnectionEvent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, extras);
+ }
+
+ private boolean isMultiSim() {
+ TelephonyManager telephonyManager = mContext.getSystemService(TelephonyManager.class);
+ if (telephonyManager == null) {
+ loge("isMultiSim: telephonyManager is null");
+ return false;
+ }
+ return telephonyManager.isMultiSimEnabled();
+ }
+
+ private int getEmergencyCallToSatelliteHandoverType() {
+ if (isSatelliteViaCarrierAvailable()) {
+ return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
+ } else {
+ return EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+ }
+ }
+
+ private static boolean isMockModemAllowed() {
+ return (SystemProperties.getBoolean(ALLOW_MOCK_MODEM_PROPERTY, false)
+ || SystemProperties.getBoolean(BOOT_ALLOW_MOCK_MODEM_PROPERTY, false));
+ }
+
private static void logd(@NonNull String log) {
Rlog.d(TAG, log);
}
diff --git a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
index b42c7d4..0e6f706 100644
--- a/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
+++ b/src/java/com/android/internal/telephony/satellite/SatelliteServiceUtils.java
@@ -217,7 +217,7 @@
* @param ntnSignalStrength The non-terrestrial signal strength from the satellite service.
* @return The converted non-terrestrial signal strength for the framework.
*/
- @Nullable public static NtnSignalStrength fromModemInterface(
+ @Nullable public static NtnSignalStrength fromNtnSignalStrength(
android.telephony.satellite.stub.NtnSignalStrength ntnSignalStrength) {
return new NtnSignalStrength(ntnSignalStrength.signalStrengthLevel);
}
diff --git a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
index 8146983..1bf866b 100644
--- a/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
+++ b/src/java/com/android/internal/telephony/subscription/SubscriptionManagerService.java
@@ -1161,7 +1161,16 @@
builder.setDisplayName(nickName);
builder.setDisplayNameSource(SubscriptionManager.NAME_SOURCE_CARRIER);
}
- builder.setProfileClass(embeddedProfile.getProfileClass());
+
+ if (android.os.Build.isDebuggable() &&
+ SystemProperties.getInt("telephony.test.bootstrap_cid", -2)
+ == carrierId) {
+ // Force set as provisioning profile for test purpose
+ log("Hardcording as bootstrap subscription for cid=" + carrierId);
+ builder.setProfileClass(SimInfo.PROFILE_CLASS_PROVISIONING);
+ } else {
+ builder.setProfileClass(embeddedProfile.getProfileClass());
+ }
builder.setPortIndex(getPortIndex(embeddedProfile.getIccid()));
CarrierIdentifier cid = embeddedProfile.getCarrierIdentifier();
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
index 80167d6..2df688d 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsFeatureTest.java
@@ -48,7 +48,7 @@
@RunWith(AndroidJUnit4.class)
public class ImsFeatureTest {
// Public for Mockito testing
- public class CapabilityCallback extends IImsCapabilityCallback.Stub {
+ public static class CapabilityCallback extends IImsCapabilityCallback.Stub {
@Override
public void onQueryCapabilityConfiguration(int capability, int radioTech, boolean enabled)
diff --git a/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java b/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java
index 337e296..df53374 100644
--- a/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java
+++ b/tests/telephonytests/src/android/telephony/ims/ImsMmTelManagerTests.java
@@ -41,7 +41,7 @@
ITelephony mMockTelephonyInterface;
BinderCacheManager<ITelephony> mBinderCache;
- public class LocalCallback extends ImsMmTelManager.RegistrationCallback {
+ public static class LocalCallback extends ImsMmTelManager.RegistrationCallback {
int mRegResult = -1;
@Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
index 2302128..7345022 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/CarrierServiceStateTrackerTest.java
@@ -88,7 +88,7 @@
// Capture listener to emulate the carrier config change notification used later
ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener> listenerArgumentCaptor =
ArgumentCaptor.forClass(CarrierConfigManager.CarrierConfigChangeListener.class);
- mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST);
+ mCarrierSST = new CarrierServiceStateTracker(mPhone, mSST, mFeatureFlags);
verify(mCarrierConfigManager).registerCarrierConfigChangeListener(any(),
listenerArgumentCaptor.capture());
mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(0);
@@ -285,6 +285,7 @@
@Test
@SmallTest
public void testEmergencyNotificationBehaviorWhenSilenced() {
+ when(mFeatureFlags.stopSpammingEmergencyNotification()).thenReturn(true);
logd(LOG_TAG + ":testEmergencyNotificationBehaviorWhenSilenced()");
sendMessageOnHandler(CarrierServiceStateTracker.NOTIFICATION_EMERGENCY_NETWORK);
@@ -312,7 +313,8 @@
public void testNotificationMapWhenDeviceIsWatch() {
doReturn(true).when(mPackageManager).hasSystemFeature(PackageManager.FEATURE_WATCH);
- CarrierServiceStateTracker tracker = new CarrierServiceStateTracker(mPhone, mSST);
+ CarrierServiceStateTracker tracker = new CarrierServiceStateTracker(mPhone, mSST,
+ mFeatureFlags);
assertTrue(tracker.getNotificationTypeMap().isEmpty());
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
index 3c8db99..2dac867 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ContextFixture.java
@@ -108,7 +108,7 @@
* Controls a test {@link Context} as would be provided by the Android framework to an
* {@code Activity}, {@code Service} or other system-instantiated component.
*
- * Contains Fake<Component> classes like FakeContext for components that require complex and
+ * Contains {@code Fake<Component>} classes like FakeContext for components that require complex and
* reusable stubbing. Others can be mocked using Mockito functions in tests or constructor/public
* methods of this class.
*/
@@ -117,7 +117,6 @@
public static final String PERMISSION_ENABLE_ALL = "android.permission.STUB_PERMISSION";
public static class FakeContentProvider extends MockContentProvider {
- private String[] mColumns = {"name", "value"};
private HashMap<String, String> mKeyValuePairs = new HashMap<String, String>();
private int mNumKeyValuePairs = 0;
private HashMap<String, String> mFlags = new HashMap<>();
@@ -747,18 +746,14 @@
doAnswer(new Answer<List<ResolveInfo>>() {
@Override
public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
- return doQueryIntentServices(
- (Intent) invocation.getArguments()[0],
- (Integer) invocation.getArguments()[1]);
+ return doQueryIntentServices((Intent) invocation.getArguments()[0]);
}
}).when(mPackageManager).queryIntentServices((Intent) any(), anyInt());
doAnswer(new Answer<List<ResolveInfo>>() {
@Override
public List<ResolveInfo> answer(InvocationOnMock invocation) throws Throwable {
- return doQueryIntentServices(
- (Intent) invocation.getArguments()[0],
- (Integer) invocation.getArguments()[1]);
+ return doQueryIntentServices((Intent) invocation.getArguments()[0]);
}
}).when(mPackageManager).queryIntentServicesAsUser((Intent) any(), anyInt(), any());
@@ -766,6 +761,7 @@
doReturn(mPackageInfo).when(mPackageManager).getPackageInfo(nullable(String.class),
anyInt());
} catch (NameNotFoundException e) {
+ Log.d(TAG, "NameNotFoundException: e=" + e);
}
doAnswer((Answer<Boolean>)
@@ -775,7 +771,7 @@
try {
doReturn(mResources).when(mPackageManager).getResourcesForApplication(anyString());
} catch (NameNotFoundException ex) {
- Log.d(TAG, "NameNotFoundException: " + ex);
+ Log.d(TAG, "NameNotFoundException: ex=" + ex);
}
doReturn(mBundle).when(mCarrierConfigManager).getConfigForSubId(anyInt());
@@ -851,7 +847,7 @@
mMockBindingFailureForPackage.add(packageName);
}
- private List<ResolveInfo> doQueryIntentServices(Intent intent, int flags) {
+ private List<ResolveInfo> doQueryIntentServices(Intent intent) {
List<ResolveInfo> result = new ArrayList<ResolveInfo>();
for (ComponentName componentName : mComponentNamesByAction.get(intent.getAction())) {
ResolveInfo resolveInfo = new ResolveInfo();
diff --git a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
index 8dd350f..8eb2de6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/DisplayInfoControllerTest.java
@@ -91,7 +91,7 @@
ArgumentCaptor<CarrierConfigManager.CarrierConfigChangeListener>
listenerArgumentCaptor = ArgumentCaptor.forClass(
CarrierConfigManager.CarrierConfigChangeListener.class);
- mSst = new ServiceStateTracker(mPhone, mSimulatedCommands);
+ mSst = new ServiceStateTracker(mPhone, mSimulatedCommands, mFeatureFlags);
verify(mCarrierConfigManager, atLeast(2)).registerCarrierConfigChangeListener(any(),
listenerArgumentCaptor.capture());
mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(1);
diff --git a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
index 5aa474e..2563fdf 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/GsmCdmaPhoneTest.java
@@ -2734,4 +2734,31 @@
verify(mSimulatedCommandsVerifier).getNetworkSelectionMode(any(Message.class));
verify(mSimulatedCommandsVerifier).setNetworkSelectionModeAutomatic(any(Message.class));
}
+
+ /**
+ * Verify the ImeiMappingChange and EVENT_GET_DEVICE_IMEI_CHANGE_DONE are handled properly.
+ */
+ @Test
+ public void testChangeInPrimaryImei() {
+ // Initially assign the primaryImei and test it.
+ Message message = mPhoneUT.obtainMessage(Phone.EVENT_GET_DEVICE_IMEI_DONE);
+ ImeiInfo imeiInfo = new ImeiInfo();
+ imeiInfo.imei = FAKE_IMEI;
+ imeiInfo.svn = FAKE_IMEISV;
+ imeiInfo.type = ImeiInfo.ImeiType.PRIMARY;
+ AsyncResult.forMessage(message, imeiInfo, null);
+ mPhoneUT.handleMessage(message);
+ assertEquals(Phone.IMEI_TYPE_PRIMARY, mPhoneUT.getImeiType());
+ assertEquals(FAKE_IMEI, mPhoneUT.getImei());
+
+ // Now update the same one to secondary and check whether it is reflecting or not.
+ message = mPhoneUT.obtainMessage(Phone.EVENT_IMEI_MAPPING_CHANGED);
+ imeiInfo.imei = FAKE_IMEI;
+ imeiInfo.svn = FAKE_IMEISV;
+ imeiInfo.type = ImeiInfo.ImeiType.SECONDARY;
+ AsyncResult.forMessage(message, imeiInfo, null);
+ mPhoneUT.handleMessage(message);
+ assertEquals(Phone.IMEI_TYPE_SECONDARY, mPhoneUT.getImeiType());
+ assertEquals(FAKE_IMEI, mPhoneUT.getImei());
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
index 0b25c55..9e067a2 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/ServiceStateTrackerTest.java
@@ -201,7 +201,7 @@
listenerArgumentCaptor =
ArgumentCaptor.forClass(
CarrierConfigManager.CarrierConfigChangeListener.class);
- sst = new ServiceStateTracker(mPhone, mSimulatedCommands);
+ sst = new ServiceStateTracker(mPhone, mSimulatedCommands, mFeatureFlags);
verify(mCarrierConfigManager, atLeast(3)).registerCarrierConfigChangeListener(any(),
listenerArgumentCaptor.capture());
mCarrierConfigChangeListener = listenerArgumentCaptor.getAllValues().get(2);
@@ -2065,6 +2065,79 @@
}
@Test
+ public void testPollStateExceptionRadioPowerOn() {
+ assertEquals(TelephonyManager.RADIO_POWER_ON, mSimulatedCommands.getRadioState());
+ assertEquals(ServiceState.STATE_IN_SERVICE, sst.getServiceState().getState());
+ assertEquals(ServiceState.STATE_IN_SERVICE,
+ sst.getServiceState().getDataRegistrationState());
+
+ sst.mPollingContext[0] = 1;
+ sst.sendMessage(sst.obtainMessage(
+ ServiceStateTracker.EVENT_POLL_STATE_OPERATOR,
+ new AsyncResult(sst.mPollingContext, null,
+ new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE))));
+ waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+
+ assertEquals(ServiceState.STATE_IN_SERVICE, sst.getServiceState().getState());
+ assertEquals(ServiceState.STATE_IN_SERVICE,
+ sst.getServiceState().getDataRegistrationState());
+ assertEquals(0, sst.mPollingContext[0]);
+ }
+
+ @Test
+ public void testPollStateExceptionRadioPowerOff() {
+ // Turn off radio first.
+ sst.setRadioPower(false);
+ waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+ assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState());
+ assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getState());
+ assertEquals(ServiceState.STATE_POWER_OFF,
+ sst.getServiceState().getDataRegistrationState());
+ // Override service state
+ sst.getServiceState().setVoiceRegState(ServiceState.STATE_IN_SERVICE);
+ sst.getServiceState().setDataRegState(ServiceState.STATE_IN_SERVICE);
+
+ sst.mPollingContext[0] = 1;
+ sst.sendMessage(sst.obtainMessage(
+ ServiceStateTracker.EVENT_POLL_STATE_OPERATOR,
+ new AsyncResult(sst.mPollingContext, null,
+ new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE))));
+ waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+
+ assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getVoiceRegState());
+ assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getDataRegState());
+ assertEquals(1, sst.mPollingContext[0]);
+ }
+
+ @Test
+ public void testPollStateExceptionRadioPowerOffOnIwlan() {
+ // Turn off radio first.
+ sst.setRadioPower(false);
+ waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+ assertEquals(TelephonyManager.RADIO_POWER_OFF, mSimulatedCommands.getRadioState());
+ assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getState());
+ assertEquals(ServiceState.STATE_POWER_OFF,
+ sst.getServiceState().getDataRegistrationState());
+ // Override service state
+ sst.getServiceState().setVoiceRegState(ServiceState.STATE_IN_SERVICE);
+ sst.getServiceState().setDataRegState(ServiceState.STATE_IN_SERVICE);
+ // Override to IWLAN
+ sst.mSS.setRilDataRadioTechnology(ServiceState.RIL_RADIO_TECHNOLOGY_IWLAN);
+
+ sst.mPollingContext[0] = 1;
+ sst.sendMessage(sst.obtainMessage(
+ ServiceStateTracker.EVENT_POLL_STATE_OPERATOR,
+ new AsyncResult(sst.mPollingContext, null,
+ new CommandException(CommandException.Error.RADIO_NOT_AVAILABLE))));
+ waitForLastHandlerAction(mSSTTestHandler.getThreadHandler());
+
+ assertNull(null, sst.getServiceState().getOperatorAlpha());
+ assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getVoiceRegState());
+ assertEquals(ServiceState.STATE_POWER_OFF, sst.getServiceState().getDataRegState());
+ assertEquals(1, sst.mPollingContext[0]);
+ }
+
+ @Test
public void testCSEmergencyRegistrationState() throws Exception {
CellIdentityGsm cellIdentity =
new CellIdentityGsm(0, 1, 900, 5, "001", "01", "test", "tst",
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
index 95a6154..39c0cac 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommands.java
@@ -1014,7 +1014,6 @@
@VisibleForTesting
public int getGetOperatorCallCount() {
- final int count = mGetOperatorCallCount.get();
return mGetOperatorCallCount.get();
}
@@ -1153,7 +1152,7 @@
"fd00:976a:c305:1d::8 fd00:976a:c202:1d::7 fd00:976a:c305:1d::5"));
mSetupDataCallResult.mtu = 1440;
} catch (Exception e) {
-
+ Rlog.e(LOG_TAG, "setupDataCall: e=" + e);
}
}
@@ -1993,7 +1992,7 @@
if (!mShouldReturnCellInfo) return;
if (mCellInfoList == null) {
- ArrayList<CellInfo> mCellInfoList = new ArrayList();
+ mCellInfoList = new ArrayList();
mCellInfoList.add(getCellInfoGsm());
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
index 4858e91..6fc5616 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/SimulatedCommandsVerifier.java
@@ -1475,4 +1475,12 @@
@Override
public void cancelHandover(Message result, int callId) {
}
+
+ /**
+ * Register to listen for the changes in the primary IMEI with respect to the sim slot.
+ */
+ @Override
+ public void registerForImeiMappingChanged(Handler h, int what, Object obj) {
+
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
index c613155..23a7ee6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/TelephonyTest.java
@@ -64,6 +64,7 @@
import android.os.RegistrantList;
import android.os.ServiceManager;
import android.os.StrictMode;
+import android.os.SystemClock;
import android.os.UserManager;
import android.permission.LegacyPermissionManager;
import android.provider.BlockedNumberContract;
@@ -148,8 +149,6 @@
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
@@ -300,7 +299,7 @@
protected Context mContext;
protected FakeBlockedNumberContentProvider mFakeBlockedNumberContentProvider;
private final ContentProvider mContentProvider = spy(new ContextFixture.FakeContentProvider());
- private Object mLock = new Object();
+ private final Object mLock = new Object();
private boolean mReady;
protected HashMap<String, IBinder> mServiceManagerMockedServices = new HashMap<>();
protected Phone[] mPhones;
@@ -314,9 +313,9 @@
private final HashMap<InstanceKey, Object> mOldInstances = new HashMap<>();
- private final LinkedList<InstanceKey> mInstanceKeys = new LinkedList<>();
+ private final List<InstanceKey> mInstanceKeys = new ArrayList<>();
- private class InstanceKey {
+ private static class InstanceKey {
public final Class mClass;
public final String mInstName;
public final Object mObj;
@@ -333,7 +332,7 @@
@Override
public boolean equals(Object obj) {
- if (obj == null || obj.getClass() != getClass()) {
+ if (obj == null || !(obj instanceof InstanceKey)) {
return false;
}
@@ -345,15 +344,18 @@
protected void waitUntilReady() {
synchronized (mLock) {
- if (!mReady) {
+ long now = SystemClock.elapsedRealtime();
+ long deadline = now + MAX_INIT_WAIT_MS;
+ while (!mReady && now < deadline) {
try {
mLock.wait(MAX_INIT_WAIT_MS);
- } catch (InterruptedException ie) {
+ } catch (Exception e) {
+ fail("Telephony tests failed to initialize: e=" + e);
}
-
- if (!mReady) {
- fail("Telephony tests failed to initialize");
- }
+ now = SystemClock.elapsedRealtime();
+ }
+ if (!mReady) {
+ fail("Telephony tests failed to initialize");
}
}
}
@@ -392,10 +394,8 @@
}
protected synchronized void restoreInstances() throws Exception {
- Iterator<InstanceKey> it = mInstanceKeys.descendingIterator();
-
- while (it.hasNext()) {
- InstanceKey key = it.next();
+ for (int i = mInstanceKeys.size() - 1; i >= 0; i--) {
+ InstanceKey key = mInstanceKeys.get(i);
Field field = key.mClass.getDeclaredField(key.mInstName);
field.setAccessible(true);
field.set(key.mObj, mOldInstances.get(key));
@@ -578,7 +578,7 @@
doReturn(mTelephonyComponentFactory).when(mTelephonyComponentFactory).inject(anyString());
doReturn(mSST).when(mTelephonyComponentFactory)
.makeServiceStateTracker(nullable(GsmCdmaPhone.class),
- nullable(CommandsInterface.class));
+ nullable(CommandsInterface.class), nullable(FeatureFlags.class));
doReturn(mEmergencyNumberTracker).when(mTelephonyComponentFactory)
.makeEmergencyNumberTracker(nullable(Phone.class),
nullable(CommandsInterface.class));
@@ -710,7 +710,7 @@
doReturn(mSimRecords).when(mUiccProfile).getIccRecords();
doAnswer(new Answer<IccRecords>() {
public IccRecords answer(InvocationOnMock invocation) {
- return (mPhone.isPhoneTypeGsm()) ? mSimRecords : mRuimRecords;
+ return mSimRecords;
}
}).when(mUiccProfile).getIccRecords();
@@ -920,7 +920,9 @@
}
if (mContext != null) {
SharedPreferences sharedPreferences = mContext.getSharedPreferences((String) null, 0);
- sharedPreferences.edit().clear().commit();
+ if (sharedPreferences != null) {
+ sharedPreferences.edit().clear().commit();
+ }
}
restoreInstances();
TelephonyManager.enableServiceHandleCaching();
@@ -944,7 +946,6 @@
mContextFixture = null;
mContext = null;
mFakeBlockedNumberContentProvider = null;
- mLock = null;
mServiceManagerMockedServices.clear();
mServiceManagerMockedServices = null;
mPhone = null;
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
index aa24c46..0cbb0f6 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/PersistAtomsStorageTest.java
@@ -1034,6 +1034,9 @@
mSatelliteSosMessageRecommender1.isImsRegistered = false;
mSatelliteSosMessageRecommender1.cellularServiceState =
TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE;
+ mSatelliteSosMessageRecommender1.isMultiSim = true;
+ mSatelliteSosMessageRecommender1.recommendingHandoverType = 1;
+ mSatelliteSosMessageRecommender1.isSatelliteAllowedInCurrentLocation = true;
mSatelliteSosMessageRecommender1.count = 1;
mSatelliteSosMessageRecommender2 = new SatelliteSosMessageRecommender();
@@ -1042,6 +1045,9 @@
mSatelliteSosMessageRecommender2.isImsRegistered = true;
mSatelliteSosMessageRecommender2.cellularServiceState =
TelephonyProtoEnums.SERVICE_STATE_POWER_OFF;
+ mSatelliteSosMessageRecommender2.isMultiSim = false;
+ mSatelliteSosMessageRecommender2.recommendingHandoverType = 0;
+ mSatelliteSosMessageRecommender2.isSatelliteAllowedInCurrentLocation = true;
mSatelliteSosMessageRecommender2.count = 1;
mSatelliteSosMessageRecommenders =
@@ -4689,7 +4695,11 @@
== expectedStats.isDisplaySosMessageSent
&& stats.countOfTimerStarted == expectedStats.countOfTimerStarted
&& stats.isImsRegistered == expectedStats.isImsRegistered
- && stats.cellularServiceState == expectedStats.cellularServiceState) {
+ && stats.cellularServiceState == expectedStats.cellularServiceState
+ && stats.isMultiSim == expectedStats.isMultiSim
+ && stats.recommendingHandoverType == expectedStats.recommendingHandoverType
+ && stats.isSatelliteAllowedInCurrentLocation
+ == expectedStats.isSatelliteAllowedInCurrentLocation) {
actualCount = stats.count;
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
index 4393f1c..959b643 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/metrics/SatelliteStatsTest.java
@@ -225,6 +225,9 @@
.setCountOfTimerStarted(5)
.setImsRegistered(false)
.setCellularServiceState(TelephonyProtoEnums.SERVICE_STATE_OUT_OF_SERVICE)
+ .setIsMultiSim(false)
+ .setRecommendingHandoverType(0)
+ .setIsSatelliteAllowedInCurrentLocation(true)
.build();
mSatelliteStats.onSatelliteSosMessageRecommender(param);
@@ -238,6 +241,10 @@
assertEquals(param.getCountOfTimerStarted(), stats.countOfTimerStarted);
assertEquals(param.isImsRegistered(), stats.isImsRegistered);
assertEquals(param.getCellularServiceState(), stats.cellularServiceState);
+ assertEquals(param.isMultiSim(), stats.isMultiSim);
+ assertEquals(param.getRecommendingHandoverType(), stats.recommendingHandoverType);
+ assertEquals(param.isSatelliteAllowedInCurrentLocation(),
+ stats.isSatelliteAllowedInCurrentLocation);
verifyNoMoreInteractions(mPersistAtomsStorage);
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
index 0b8d658..0a1ab02 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramDispatcherTest.java
@@ -31,6 +31,8 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.inOrder;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
@@ -38,16 +40,19 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.content.Context;
import android.os.AsyncResult;
import android.os.Looper;
import android.os.Message;
+import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.satellite.SatelliteDatagram;
import android.telephony.satellite.SatelliteManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import com.android.internal.R;
import com.android.internal.telephony.Phone;
import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyTest;
@@ -61,8 +66,12 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
@RunWith(AndroidTestingRunner.class)
@TestableLooper.RunWithLooper
@@ -88,6 +97,22 @@
SatelliteDatagram mDatagram;
InOrder mInOrder;
+ private static final long TIMEOUT = 500;
+ private List<Integer> mIntegerConsumerResult = new ArrayList<>();
+ private Semaphore mIntegerConsumerSemaphore = new Semaphore(0);
+ private Consumer<Integer> mIntegerConsumer = integer -> {
+ logd("mIntegerConsumer: integer=" + integer);
+ mIntegerConsumerResult.add(integer);
+ try {
+ mIntegerConsumerSemaphore.release();
+ } catch (Exception ex) {
+ loge("mIntegerConsumer: Got exception in releasing semaphore, ex=" + ex);
+ }
+ };
+
+ private final int mConfigSendSatelliteDatagramToModemInDemoMode =
+ R.bool.config_send_satellite_datagram_to_modem_in_demo_mode;
+
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
@@ -105,6 +130,7 @@
replaceInstance(SatelliteSessionController.class, "sInstance", null,
mMockSatelliteSessionController);
+ when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
mDatagramDispatcherUT = DatagramDispatcher.make(mContext, Looper.myLooper(),
mMockDatagramController);
mTestDemoModeDatagramDispatcher = new TestDatagramDispatcher(mContext, Looper.myLooper(),
@@ -358,12 +384,13 @@
doAnswer(invocation -> {
Message message = (Message) invocation.getArguments()[3];
mDatagramDispatcherUT.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
- new AsyncResult(message.obj, null, null))
- .sendToTarget();
+ new AsyncResult(message.obj, SatelliteManager.SATELLITE_RESULT_SUCCESS,
+ null)).sendToTarget();
return null;
}).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
anyBoolean(), anyBoolean(), any(Message.class));
mTestDemoModeDatagramDispatcher.setDemoMode(true);
+ mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true);
replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[] {mPhone});
mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE2, mDatagram,
@@ -446,6 +473,82 @@
eq(0), eq(SatelliteManager.SATELLITE_RESULT_SUCCESS));
}
+ @Test
+ public void testSendSatelliteDatagramToModemInDemoMode()
+ throws Exception {
+ when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+ doAnswer(invocation -> {
+ Message message = (Message) invocation.getArguments()[3];
+ mTestDemoModeDatagramDispatcher.obtainMessage(2 /*EVENT_SEND_SATELLITE_DATAGRAM_DONE*/,
+ new AsyncResult(message.obj, null, null))
+ .sendToTarget();
+ return null;
+ }).when(mMockSatelliteModemInterface).sendSatelliteDatagram(any(SatelliteDatagram.class),
+ anyBoolean(), anyBoolean(), any(Message.class));
+ mTestDemoModeDatagramDispatcher.setDemoMode(true);
+ mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(true);
+ mIntegerConsumerSemaphore.drainPermits();
+
+ // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is true
+ mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null);
+ mContextFixture.putBooleanResource(mConfigSendSatelliteDatagramToModemInDemoMode, true);
+ mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+ true, mIntegerConsumer);
+ processAllMessages();
+ waitForIntegerConsumerResult(1);
+ assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS,
+ (int) mIntegerConsumerResult.get(0));
+ mIntegerConsumerResult.clear();
+ verify(mMockSatelliteModemInterface, times(1)).sendSatelliteDatagram(
+ any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
+
+ // Test when overlay config config_send_satellite_datagram_to_modem_in_demo_mode is false
+ reset(mMockSatelliteModemInterface);
+ mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null);
+ mContextFixture.putBooleanResource(mConfigSendSatelliteDatagramToModemInDemoMode, false);
+ mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+ true, mIntegerConsumer);
+ processAllMessages();
+ waitForIntegerConsumerResult(1);
+ assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS,
+ (int) mIntegerConsumerResult.get(0));
+ mIntegerConsumerResult.clear();
+ verify(mMockSatelliteModemInterface, never()).sendSatelliteDatagram(
+ any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
+
+ // Send datagram one more time
+ reset(mMockSatelliteModemInterface);
+ mTestDemoModeDatagramDispatcher.sendSatelliteDatagram(SUB_ID, DATAGRAM_TYPE1, mDatagram,
+ true, mIntegerConsumer);
+ processAllMessages();
+ waitForIntegerConsumerResult(1);
+ assertEquals(SatelliteManager.SATELLITE_RESULT_SUCCESS,
+ (int) mIntegerConsumerResult.get(0));
+ mIntegerConsumerResult.clear();
+ verify(mMockSatelliteModemInterface, never()).sendSatelliteDatagram(
+ any(SatelliteDatagram.class), anyBoolean(), anyBoolean(), any(Message.class));
+
+ mTestDemoModeDatagramDispatcher.setDemoMode(false);
+ mTestDemoModeDatagramDispatcher.setDeviceAlignedWithSatellite(false);
+ mTestDemoModeDatagramDispatcher.setShouldSendDatagramToModemInDemoMode(null);
+ }
+
+ private boolean waitForIntegerConsumerResult(int expectedNumberOfEvents) {
+ for (int i = 0; i < expectedNumberOfEvents; i++) {
+ try {
+ if (!mIntegerConsumerSemaphore.tryAcquire(TIMEOUT, TimeUnit.MILLISECONDS)) {
+ loge("Timeout to receive IIntegerConsumer() callback");
+ return false;
+ }
+ } catch (Exception ex) {
+ loge("waitForIIntegerConsumerResult: Got exception=" + ex);
+ return false;
+ }
+ }
+ return true;
+ }
+
private static class TestDatagramDispatcher extends DatagramDispatcher {
private long mLong = SATELLITE_ALIGN_TIMEOUT;
@@ -469,8 +572,18 @@
return mLong;
}
+ @Override
+ protected void setShouldSendDatagramToModemInDemoMode(
+ @Nullable Boolean shouldSendToModemInDemoMode) {
+ super.setShouldSendDatagramToModemInDemoMode(shouldSendToModemInDemoMode);
+ }
+
public void setDuration(long duration) {
mLong = duration;
}
}
+
+ private static void loge(String message) {
+ Rlog.e(TAG, message);
+ }
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
index 3578707..94f56b4 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/DatagramReceiverTest.java
@@ -429,7 +429,7 @@
@Test
public void testRegisterForSatelliteDatagram_satelliteNotSupported() {
- when(mMockSatelliteController.isSatelliteSupported()).thenReturn(false);
+ when(mMockSatelliteController.isSatelliteSupportedViaOem()).thenReturn(false);
ISatelliteDatagramCallback callback = new ISatelliteDatagramCallback() {
@Override
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
index 221aa0e..add1d52 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteControllerTest.java
@@ -16,6 +16,8 @@
package com.android.internal.telephony.satellite;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL;
+import static android.telephony.CarrierConfigManager.KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT;
import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GOOD;
import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_GREAT;
import static android.telephony.satellite.NtnSignalStrength.NTN_SIGNAL_STRENGTH_NONE;
@@ -92,7 +94,9 @@
import android.os.ResultReceiver;
import android.telephony.CarrierConfigManager;
import android.telephony.Rlog;
+import android.telephony.ServiceState;
import android.telephony.satellite.INtnSignalStrengthCallback;
+import android.telephony.satellite.ISatelliteCapabilitiesCallback;
import android.telephony.satellite.ISatelliteDatagramCallback;
import android.telephony.satellite.ISatelliteProvisionStateCallback;
import android.telephony.satellite.ISatelliteStateCallback;
@@ -109,6 +113,8 @@
import com.android.internal.R;
import com.android.internal.telephony.IIntegerConsumer;
import com.android.internal.telephony.IVoidConsumer;
+import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.satellite.metrics.ControllerMetricsStats;
@@ -121,6 +127,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
+import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
@@ -154,6 +161,7 @@
private TestSatelliteController mSatelliteControllerUT;
private TestSharedPreferences mSharedPreferences;
private PersistableBundle mCarrierConfigBundle;
+ private ServiceState mServiceState2;
@Mock private DatagramController mMockDatagramController;
@Mock private SatelliteModemInterface mMockSatelliteModemInterface;
@@ -433,6 +441,13 @@
mMockSessionMetricsStats);
replaceInstance(SubscriptionManagerService.class, "sInstance", null,
mMockSubscriptionManagerService);
+ replaceInstance(PhoneFactory.class, "sPhones", null, new Phone[]{mPhone, mPhone2});
+
+ mServiceState2 = Mockito.mock(ServiceState.class);
+ when(mPhone.getServiceState()).thenReturn(mServiceState);
+ when(mPhone.getSubId()).thenReturn(SUB_ID);
+ when(mPhone2.getServiceState()).thenReturn(mServiceState2);
+ when(mPhone2.getSubId()).thenReturn(SUB_ID1);
mContextFixture.putStringArrayResource(
R.array.config_satellite_providers,
@@ -2318,6 +2333,178 @@
.stopSendingNtnSignalStrength(any(Message.class));
}
+ @Test
+ public void testIsSatelliteSupportedViaCarrier() {
+ when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
+ assertFalse(mSatelliteControllerUT.isSatelliteSupportedViaCarrier());
+
+ when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+ assertFalse(mSatelliteControllerUT.isSatelliteSupportedViaCarrier());
+
+ mCarrierConfigBundle.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+ for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+ : mCarrierConfigChangedListenerList) {
+ pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+ /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+ );
+ }
+ processAllMessages();
+ assertTrue(mSatelliteControllerUT.isSatelliteSupportedViaCarrier());
+ }
+
+ @Test
+ public void testCarrierEnabledSatelliteConnectionHysteresisTime() {
+ when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(false);
+ assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+
+ when(mFeatureFlags.carrierEnabledSatelliteFlag()).thenReturn(true);
+ mCarrierConfigBundle.putInt(KEY_SATELLITE_CONNECTION_HYSTERESIS_SEC_INT, 1 * 60);
+ mCarrierConfigBundle.putBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, true);
+ for (Pair<Executor, CarrierConfigManager.CarrierConfigChangeListener> pair
+ : mCarrierConfigChangedListenerList) {
+ pair.first.execute(() -> pair.second.onCarrierConfigChanged(
+ /*slotIndex*/ 0, /*subId*/ SUB_ID, /*carrierId*/ 0, /*specificCarrierId*/ 0)
+ );
+ }
+ processAllMessages();
+ mSatelliteControllerUT.elapsedRealtime = 0;
+ assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+
+ when(mServiceState.isUsingNonTerrestrialNetwork()).thenReturn(false);
+ when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false);
+ sendServiceStateChangedEvent();
+ processAllMessages();
+ assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+
+ // Last satellite connected time of Phone2 should be 0
+ when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(true);
+ sendServiceStateChangedEvent();
+ processAllMessages();
+ // 2 minutes later and hysteresis timeout is 1 minute
+ mSatelliteControllerUT.elapsedRealtime = 2 * 60 * 1000;
+ // But Phone2 is connected to NTN right now
+ assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+
+ // Last satellite disconnected time of Phone2 should be 2 * 60 * 1000
+ when(mServiceState2.isUsingNonTerrestrialNetwork()).thenReturn(false);
+ sendServiceStateChangedEvent();
+ processAllMessages();
+ // Current time (2) - last disconnected time (2) < hysteresis timeout (1)
+ assertTrue(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+
+ // Current time (4) - last disconnected time (2) > hysteresis timeout (1)
+ mSatelliteControllerUT.elapsedRealtime = 4 * 60 * 1000;
+ assertFalse(mSatelliteControllerUT.isSatelliteConnectedViaCarrierWithinHysteresisTime());
+ }
+
+ @Test
+ public void testRegisterForSatelliteCapabilitiesChangedWithFeatureFlagEnabled() {
+ when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
+
+ Semaphore semaphore = new Semaphore(0);
+ final SatelliteCapabilities[] satelliteCapabilities = new SatelliteCapabilities[1];
+ ISatelliteCapabilitiesCallback callback =
+ new ISatelliteCapabilitiesCallback.Stub() {
+ @Override
+ public void onSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) {
+ logd("onSatelliteCapabilitiesChanged: " + capabilities);
+ try {
+ satelliteCapabilities[0] = capabilities;
+ semaphore.release();
+ } catch (Exception ex) {
+ loge("onSatelliteCapabilitiesChanged: Got exception in releasing "
+ + "semaphore, ex=" + ex);
+ }
+ }
+ };
+
+ int errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID,
+ callback);
+ assertEquals(SATELLITE_RESULT_INVALID_TELEPHONY_STATE, errorCode);
+
+ setUpResponseForRequestIsSatelliteSupported(false,
+ SATELLITE_RESULT_SUCCESS);
+ verifySatelliteSupported(false, SATELLITE_RESULT_SUCCESS);
+ errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID,
+ callback);
+ assertEquals(SATELLITE_RESULT_NOT_SUPPORTED, errorCode);
+
+ resetSatelliteControllerUT();
+ setUpResponseForRequestIsSatelliteProvisioned(true,
+ SATELLITE_RESULT_SUCCESS);
+ setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+ verifySatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+ errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID,
+ callback);
+ assertEquals(SATELLITE_RESULT_SUCCESS, errorCode);
+ SatelliteCapabilities expectedCapabilities = mSatelliteCapabilities;
+ sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null);
+ processAllMessages();
+ assertTrue(waitForForEvents(
+ semaphore, 1, "testRegisterForSatelliteCapabilitiesChanged"));
+ assertTrue(expectedCapabilities.equals(satelliteCapabilities[0]));
+
+ expectedCapabilities = mEmptySatelliteCapabilities;
+ sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null);
+ processAllMessages();
+ assertTrue(waitForForEvents(
+ semaphore, 1, "testRegisterForSatelliteCapabilitiesChanged"));
+ assertTrue(expectedCapabilities.equals(satelliteCapabilities[0]));
+
+ mSatelliteControllerUT.unregisterForSatelliteCapabilitiesChanged(SUB_ID, callback);
+ expectedCapabilities = mSatelliteCapabilities;
+ sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null);
+ processAllMessages();
+ assertTrue(waitForForEvents(
+ semaphore, 0, "testRegisterForSatelliteCapabilitiesChanged"));
+ }
+
+ @Test
+ public void testRegisterForSatelliteCapabilitiesChangedWithFeatureFlagDisabled() {
+ when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(false);
+
+ Semaphore semaphore = new Semaphore(0);
+ final SatelliteCapabilities[] satelliteCapabilities = new SatelliteCapabilities[1];
+ ISatelliteCapabilitiesCallback callback =
+ new ISatelliteCapabilitiesCallback.Stub() {
+ @Override
+ public void onSatelliteCapabilitiesChanged(SatelliteCapabilities capabilities) {
+ logd("onSatelliteCapabilitiesChanged: " + capabilities);
+ try {
+ satelliteCapabilities[0] = capabilities;
+ semaphore.release();
+ } catch (Exception ex) {
+ loge("onSatelliteCapabilitiesChanged: Got exception in releasing "
+ + "semaphore, ex=" + ex);
+ }
+ }
+ };
+
+ int errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID,
+ callback);
+ assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+
+ setUpResponseForRequestIsSatelliteSupported(false,
+ SATELLITE_RESULT_SUCCESS);
+ verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED);
+ errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID,
+ callback);
+ assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+
+ resetSatelliteControllerUT();
+ setUpResponseForRequestIsSatelliteSupported(true, SATELLITE_RESULT_SUCCESS);
+ verifySatelliteSupported(false, SATELLITE_RESULT_NOT_SUPPORTED);
+ errorCode = mSatelliteControllerUT.registerForSatelliteCapabilitiesChanged(SUB_ID,
+ callback);
+ assertEquals(SATELLITE_RESULT_REQUEST_NOT_SUPPORTED, errorCode);
+
+ SatelliteCapabilities expectedCapabilities = mSatelliteCapabilities;
+ sendSatelliteCapabilitiesChangedEvent(expectedCapabilities, null);
+ processAllMessages();
+ assertTrue(waitForForEvents(
+ semaphore, 0, "testRegisterForSatelliteCapabilitiesChanged"));
+ }
+
private void resetSatelliteControllerUTEnabledState() {
logd("resetSatelliteControllerUTEnabledState");
setUpResponseForRequestIsSatelliteSupported(false, SATELLITE_RESULT_RADIO_NOT_AVAILABLE);
@@ -2841,7 +3028,7 @@
private void sendCmdStartSendingNtnSignalStrengthChangedEvent(boolean shouldReport) {
Message msg = mSatelliteControllerUT.obtainMessage(
- 35 /* CMD_START_SENDING_NTN_SIGNAL_STRENGTH */);
+ 35 /* CMD_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING */);
msg.obj = new AsyncResult(null, shouldReport, null);
msg.sendToTarget();
}
@@ -2850,12 +3037,24 @@
@NtnSignalStrength.NtnSignalStrengthLevel int ntnSignalStrengthLevel,
Throwable exception) {
Message msg = mSatelliteControllerUT.obtainMessage(
- 36 /* EVENT_START_SENDING_NTN_SIGNAL_STRENGTH_DONE */);
+ 36 /* EVENT_UPDATE_NTN_SIGNAL_STRENGTH_REPORTING_DONE */);
msg.obj = new AsyncResult(null, new NtnSignalStrength(ntnSignalStrengthLevel),
exception);
msg.sendToTarget();
}
+ private void sendServiceStateChangedEvent() {
+ mSatelliteControllerUT.obtainMessage(37 /* EVENT_SERVICE_STATE_CHANGED */).sendToTarget();
+ }
+
+ private void sendSatelliteCapabilitiesChangedEvent(SatelliteCapabilities capabilities,
+ Throwable exception) {
+ Message msg = mSatelliteControllerUT.obtainMessage(
+ 38 /* EVENT_SATELLITE_CAPABILITIES_CHANGED */);
+ msg.obj = new AsyncResult(null, capabilities, exception);
+ msg.sendToTarget();
+ }
+
private void setRadioPower(boolean on) {
mSimulatedCommands.setRadioPower(on, false, false, null);
}
@@ -3008,6 +3207,7 @@
private static class TestSatelliteController extends SatelliteController {
public boolean setSettingsKeyForSatelliteModeCalled = false;
public boolean allRadiosDisabled = true;
+ public long elapsedRealtime = 0;
public int satelliteModeSettingValue = SATELLITE_MODE_ENABLED_FALSE;
TestSatelliteController(
@@ -3039,5 +3239,10 @@
logd("getCurrentNtnRadioTechnology: val=" + ntRadioTechnology);
return ntRadioTechnology;
}
+
+ @Override
+ protected long getElapsedRealtime() {
+ return elapsedRealtime;
+ }
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
index 3a108aa..589f32b 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/satellite/SatelliteSOSMessageRecommenderTest.java
@@ -16,6 +16,11 @@
package com.android.internal.telephony.satellite;
+import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+import static android.telephony.TelephonyManager.EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT;
+import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS;
+import static android.telephony.satellite.SatelliteManager.EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -26,17 +31,17 @@
import static org.mockito.Mockito.when;
import android.annotation.NonNull;
-import android.app.ActivityManager;
+import android.app.PendingIntent;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.res.Resources;
-import android.os.AsyncResult;
import android.os.Bundle;
import android.os.Looper;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.telecom.Connection;
import android.telephony.BinderCacheManager;
-import android.telephony.CarrierConfigManager;
import android.telephony.ServiceState;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
@@ -45,11 +50,14 @@
import android.telephony.satellite.SatelliteManager;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
+import android.text.TextUtils;
import android.util.Log;
import com.android.ims.ImsException;
import com.android.ims.ImsManager;
+import com.android.internal.R;
import com.android.internal.telephony.Phone;
+import com.android.internal.telephony.PhoneFactory;
import com.android.internal.telephony.TelephonyTest;
import com.android.internal.telephony.flags.FeatureFlags;
@@ -61,8 +69,10 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Executor;
@@ -76,13 +86,16 @@
private static final String TAG = "SatelliteSOSMessageRecommenderTest";
private static final long TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS = 500;
private static final int PHONE_ID = 0;
+ private static final int PHONE_ID2 = 1;
private static final String CALL_ID = "CALL_ID";
private static final String WRONG_CALL_ID = "WRONG_CALL_ID";
+ private static final String DEFAULT_SATELLITE_MESSAGING_PACKAGE = "android.com.google.default";
+ private static final String DEFAULT_SATELLITE_MESSAGING_CLASS =
+ "android.com.google.default.SmsMmsApp";
+ private static final String DEFAULT_HANDOVER_INTENT_ACTION =
+ "android.com.vendor.action.EMERGENCY_MESSAGING";
private TestSatelliteController mTestSatelliteController;
private TestImsManager mTestImsManager;
-
- @Mock
- private Context mMockContext;
@Mock
private Resources mResources;
@Mock
@@ -91,40 +104,38 @@
private FeatureFlags mFeatureFlags;
private TestConnection mTestConnection;
private TestSOSMessageRecommender mTestSOSMessageRecommender;
+ private ServiceState mServiceState2;
@Before
public void setUp() throws Exception {
super.setUp(getClass().getSimpleName());
MockitoAnnotations.initMocks(this);
- when(mMockContext.getMainLooper()).thenReturn(Looper.myLooper());
- when(mMockContext.getResources()).thenReturn(mResources);
- when(mResources.getString(com.android.internal.R.string.config_satellite_service_package))
+ when(mContext.getResources()).thenReturn(mResources);
+ when(mResources.getString(R.string.config_satellite_service_package))
.thenReturn("");
- when(mMockContext.getSystemServiceName(CarrierConfigManager.class))
- .thenReturn("CarrierConfigManager");
- when(mMockContext.getSystemService(CarrierConfigManager.class))
- .thenReturn(mCarrierConfigManager);
- when(mMockContext.getSystemServiceName(SubscriptionManager.class))
- .thenReturn("SubscriptionManager");
- when(mMockContext.getSystemService(SubscriptionManager.class))
- .thenReturn(mSubscriptionManager);
- when(mMockContext.getSystemServiceName(ActivityManager.class))
- .thenReturn("ActivityManager");
- when(mMockContext.getSystemService(ActivityManager.class))
- .thenReturn(mActivityManager);
+ when(mResources.getString(R.string.config_satellite_emergency_handover_intent_action))
+ .thenReturn(DEFAULT_HANDOVER_INTENT_ACTION);
when(mFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
- mTestSatelliteController = new TestSatelliteController(mMockContext,
+ mTestSatelliteController = new TestSatelliteController(mContext,
Looper.myLooper(), mFeatureFlags);
mTestImsManager = new TestImsManager(
- mMockContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null);
+ mContext, PHONE_ID, mMmTelFeatureConnectionFactory, null, null, null);
mTestConnection = new TestConnection(CALL_ID);
+ mPhones = new Phone[] {mPhone, mPhone2};
+ replaceInstance(PhoneFactory.class, "sPhones", null, mPhones);
+ mServiceState2 = Mockito.mock(ServiceState.class);
when(mPhone.getServiceState()).thenReturn(mServiceState);
- mTestSOSMessageRecommender = new TestSOSMessageRecommender(Looper.myLooper(),
+ when(mPhone.getPhoneId()).thenReturn(PHONE_ID);
+ when(mPhone2.getServiceState()).thenReturn(mServiceState2);
+ when(mPhone2.getPhoneId()).thenReturn(PHONE_ID2);
+ mTestSOSMessageRecommender = new TestSOSMessageRecommender(mContext, Looper.myLooper(),
mTestSatelliteController, mTestImsManager,
TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
when(mServiceState.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
+ when(mServiceState2.getState()).thenReturn(ServiceState.STATE_OUT_OF_SERVICE);
when(mPhone.isImsRegistered()).thenReturn(false);
+ when(mPhone2.isImsRegistered()).thenReturn(false);
}
@After
@@ -133,18 +144,103 @@
}
@Test
- public void testTimeoutBeforeEmergencyCallEnd() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ public void testTimeoutBeforeEmergencyCallEnd_T911() {
+ testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
+ DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
+ DEFAULT_HANDOVER_INTENT_ACTION);
+ }
+
+ @Test
+ public void testTimeoutBeforeEmergencyCallEnd_SOS_WithValidHandoverAppConfigured() {
+ String satelliteHandoverApp =
+ "android.com.vendor.message;android.com.vendor.message.SmsApp";
+ when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
+ .thenReturn(satelliteHandoverApp);
+ mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+ testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS,
+ "android.com.vendor.message", "android.com.vendor.message.SmsApp",
+ DEFAULT_HANDOVER_INTENT_ACTION);
+ }
+
+ @Test
+ public void testTimeoutBeforeEmergencyCallEnd_SOS_WithInValidHandoverAppConfigured() {
+ String satelliteHandoverApp =
+ "android.com.vendor.message;android.com.vendor.message.SmsApp;abc";
+ when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
+ .thenReturn(satelliteHandoverApp);
+ mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+ testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
+ DEFAULT_HANDOVER_INTENT_ACTION);
+ }
+
+ @Test
+ public void testTimeoutBeforeEmergencyCallEnd_SOS_WithoutHandoverAppConfigured() {
+ when(mResources.getString(R.string.config_oem_enabled_satellite_sos_handover_app))
+ .thenReturn("");
+ mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+ testTimeoutBeforeEmergencyCallEnd(EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_SOS, "", "",
+ DEFAULT_HANDOVER_INTENT_ACTION);
+ }
+
+ private void testTimeoutBeforeEmergencyCallEnd(int expectedHandoverType,
+ String expectedPackageName, String expectedClassName, String expectedAction) {
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
// Wait for the timeout to expires
moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
processAllMessages();
+ if (TextUtils.isEmpty(expectedPackageName) || TextUtils.isEmpty(expectedClassName)) {
+ assertTrue(mTestConnection.isEventWithoutLaunchIntentSent(
+ TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE, expectedHandoverType));
+ } else {
+ assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
+ expectedHandoverType, expectedPackageName, expectedClassName, expectedAction));
+ }
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+ }
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
- assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ @Test
+ public void testTimeoutBeforeEmergencyCallEnd_EventDisplayEmergencyMessageNotSent() {
+ mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+ mTestSatelliteController.setIsSatelliteViaOemProvisioned(false);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ processAllMessages();
+ assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+
+ // Wait for the timeout to expires
+ moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+ processAllMessages();
+ assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+ }
+
+ @Test
+ public void testTimeoutBeforeEmergencyCallEnd_T911_FromNotConnectedToConnected() {
+ mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(false);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
+ processAllMessages();
+ assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+
+ mTestSatelliteController.setSatelliteConnectedViaCarrierWithinHysteresisTime(true);
+ // Wait for the timeout to expires
+ moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
+ processAllMessages();
+ assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
+ EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911,
+ DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS,
+ DEFAULT_HANDOVER_INTENT_ACTION));
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
}
@Test
@@ -159,22 +255,34 @@
@Test
public void testImsRegistrationStateChangedBeforeTimeout() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
- mTestImsManager.sendImsRegistrationStateChangedEvent(true);
+ when(mPhone.isImsRegistered()).thenReturn(true);
+ mTestImsManager.sendImsRegistrationStateChangedEvent(0, true);
processAllMessages();
- assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
+ assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
- mTestImsManager.sendImsRegistrationStateChangedEvent(false);
+ when(mPhone.isImsRegistered()).thenReturn(false);
+ when(mPhone2.isImsRegistered()).thenReturn(true);
+ mTestImsManager.sendImsRegistrationStateChangedEvent(1, true);
+ processAllMessages();
+ assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
+ assertFalse(mTestSOSMessageRecommender.isTimerStarted());
+ assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
+
+ when(mPhone2.isImsRegistered()).thenReturn(false);
+ mTestImsManager.sendImsRegistrationStateChangedEvent(1, false);
processAllMessages();
assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted());
@@ -182,19 +290,23 @@
moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
processAllMessages();
- assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
+ EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
+ DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
}
@Test
public void testSatelliteProvisionStateChangedBeforeTimeout() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
mTestSatelliteController.sendProvisionStateChangedEvent(
SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, false);
@@ -202,13 +314,15 @@
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 2, 2, 2);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 2, 4, 2);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 2, 4, 2);
mTestSatelliteController.sendProvisionStateChangedEvent(
SubscriptionManager.DEFAULT_SUBSCRIPTION_ID, true);
@@ -217,57 +331,44 @@
moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
processAllMessages();
- assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
+ assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
+ EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
+ DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 2, 2);
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 2, 4, 2);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 2, 4, 2);
}
@Test
public void testEmergencyCallRedialBeforeTimeout() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
- Phone newPhone = Mockito.mock(Phone.class);
- when(newPhone.getServiceState()).thenReturn(mServiceState);
- when(newPhone.isImsRegistered()).thenReturn(false);
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, newPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- /**
- * Since {@link SatelliteSOSMessageRecommender} always uses
- * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} when registering for provision state
- * changed events with {@link SatelliteController}, registerForProvisionCount does
- * not depend on Phone.
- * <p>
- * Since we use a single mocked ImsManager instance, registerForImsCount does not depend on
- * Phone.
- */
- assertRegisterForStateChangedEventsTriggered(newPhone, 2, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
// Wait for the timeout to expires
moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
processAllMessages();
- assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
- /**
- * Since {@link SatelliteSOSMessageRecommender} always uses
- * {@link SubscriptionManager#DEFAULT_SUBSCRIPTION_ID} when unregistering for provision
- * state changed events with {@link SatelliteController}, unregisterForProvisionCount does
- * not depend on Phone.
- * <p>
- * Since we use a single mocked ImsManager instance, unregisterForImsCount does not depend
- * on Phone.
- */
- assertUnregisterForStateChangedEventsTriggered(newPhone, 2, 2, 1);
+ assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
+ EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
+ DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertFalse(mTestSOSMessageRecommender.isTimerStarted());
}
@Test
@@ -296,50 +397,55 @@
@Test
public void testOnEmergencyCallConnectionStateChangedWithWrongCallId() {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(
WRONG_CALL_ID, Connection.STATE_ACTIVE);
processAllMessages();
- assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
+ assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
}
@Test
public void testSatelliteNotAllowedInCurrentLocation() {
mTestSatelliteController.setIsSatelliteCommunicationAllowed(false);
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
/**
- * We should have registered for the state change events abd started the timer when
+ * We should have registered for the state change events and started the timer when
* receiving the event onEmergencyCallStarted. After getting the callback for the result of
* the request requestIsSatelliteCommunicationAllowedForCurrentLocation, the resources
* should be cleaned up.
*/
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
}
@Test
public void testOnEmergencyCallStarted() {
SatelliteController satelliteController = new SatelliteController(
- mMockContext, Looper.myLooper(), mFeatureFlags);
+ mContext, Looper.myLooper(), mFeatureFlags);
TestSOSMessageRecommender testSOSMessageRecommender = new TestSOSMessageRecommender(
+ mContext,
Looper.myLooper(),
satelliteController, mTestImsManager,
TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
- testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ testSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertFalse(testSOSMessageRecommender.isTimerStarted());
@@ -348,51 +454,68 @@
private void testStopTrackingCallBeforeTimeout(
@Connection.ConnectionState int connectionState) {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
mTestSOSMessageRecommender.onEmergencyCallConnectionStateChanged(CALL_ID, connectionState);
processAllMessages();
- assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
+ assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
}
private void testCellularServiceStateChangedBeforeTimeout(
@ServiceState.RegState int availableServiceState,
@ServiceState.RegState int unavailableServiceState) {
- mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection, mPhone);
+ mTestSOSMessageRecommender.onEmergencyCallStarted(mTestConnection);
processAllMessages();
assertTrue(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
- assertRegisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertRegisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
- mTestSOSMessageRecommender.sendServiceStateChangedEvent(availableServiceState);
+ when(mServiceState.getState()).thenReturn(availableServiceState);
+ mTestSOSMessageRecommender.sendServiceStateChangedEvent();
processAllMessages();
-
- assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
+ assertFalse(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE));
assertFalse(mTestSOSMessageRecommender.isTimerStarted());
assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
assertUnregisterForStateChangedEventsTriggered(mPhone, 0, 0, 0);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 0, 0, 0);
- mTestSOSMessageRecommender.sendServiceStateChangedEvent(unavailableServiceState);
+ when(mServiceState.getState()).thenReturn(unavailableServiceState);
+ when(mServiceState2.getState()).thenReturn(availableServiceState);
+ mTestSOSMessageRecommender.sendServiceStateChangedEvent();
+ processAllMessages();
+ assertFalse(mTestSOSMessageRecommender.isTimerStarted());
+ assertEquals(1, mTestSOSMessageRecommender.getCountOfTimerStarted());
+
+ when(mServiceState2.getState()).thenReturn(unavailableServiceState);
+ mTestSOSMessageRecommender.sendServiceStateChangedEvent();
processAllMessages();
assertEquals(2, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertTrue(mTestSOSMessageRecommender.isTimerStarted());
// Wait for the timeout to expires
moveTimeForward(TEST_EMERGENCY_CALL_TO_SOS_MSG_HYSTERESIS_TIMEOUT_MILLIS);
processAllMessages();
- assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_SOS_MESSAGE));
- assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 1, 1);
+ assertTrue(mTestConnection.isEventSent(TelephonyManager.EVENT_DISPLAY_EMERGENCY_MESSAGE,
+ EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE_T911, DEFAULT_SATELLITE_MESSAGING_PACKAGE,
+ DEFAULT_SATELLITE_MESSAGING_CLASS, DEFAULT_HANDOVER_INTENT_ACTION));
+ assertUnregisterForStateChangedEventsTriggered(mPhone, 1, 2, 1);
+ assertUnregisterForStateChangedEventsTriggered(mPhone2, 1, 2, 1);
assertEquals(0, mTestSOSMessageRecommender.getCountOfTimerStarted());
+ assertFalse(mTestSOSMessageRecommender.isTimerStarted());
}
private void assertRegisterForStateChangedEventsTriggered(
@@ -421,8 +544,9 @@
mProvisionStateChangedCallbacks;
private int mRegisterForSatelliteProvisionStateChangedCalls = 0;
private int mUnregisterForSatelliteProvisionStateChangedCalls = 0;
- private boolean mIsSatelliteProvisioned = true;
+ private boolean mIsSatelliteViaOemProvisioned = true;
private boolean mIsSatelliteCommunicationAllowed = true;
+ private boolean mIsSatelliteConnectedViaCarrierWithinHysteresisTime = true;
/**
* Create a SatelliteController to act as a backend service of
@@ -437,12 +561,12 @@
}
@Override
- public Boolean isSatelliteProvisioned() {
- return mIsSatelliteProvisioned;
+ public Boolean isSatelliteViaOemProvisioned() {
+ return mIsSatelliteViaOemProvisioned;
}
@Override
- public boolean isSatelliteSupported() {
+ public boolean isSatelliteSupportedViaOem() {
return true;
}
@@ -477,10 +601,25 @@
result.send(SatelliteManager.SATELLITE_RESULT_SUCCESS, bundle);
}
+ @Override
+ public boolean isSatelliteConnectedViaCarrierWithinHysteresisTime() {
+ return mIsSatelliteConnectedViaCarrierWithinHysteresisTime;
+ }
+
+ @Override
+ protected int getEnforcedEmergencyCallToSatelliteHandoverType() {
+ return INVALID_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE;
+ }
+
public void setIsSatelliteCommunicationAllowed(boolean allowed) {
mIsSatelliteCommunicationAllowed = allowed;
}
+ public void setSatelliteConnectedViaCarrierWithinHysteresisTime(
+ boolean connectedViaCarrier) {
+ mIsSatelliteConnectedViaCarrierWithinHysteresisTime = connectedViaCarrier;
+ }
+
public int getRegisterForSatelliteProvisionStateChangedCalls() {
return mRegisterForSatelliteProvisionStateChangedCalls;
}
@@ -489,8 +628,12 @@
return mUnregisterForSatelliteProvisionStateChangedCalls;
}
+ public void setIsSatelliteViaOemProvisioned(boolean provisioned) {
+ mIsSatelliteViaOemProvisioned = provisioned;
+ }
+
public void sendProvisionStateChangedEvent(int subId, boolean provisioned) {
- mIsSatelliteProvisioned = provisioned;
+ mIsSatelliteViaOemProvisioned = provisioned;
Set<ISatelliteProvisionStateCallback> perSubscriptionCallbacks =
mProvisionStateChangedCallbacks.get(subId);
if (perSubscriptionCallbacks != null) {
@@ -507,7 +650,7 @@
private static class TestImsManager extends ImsManager {
- private final Set<RegistrationManager.RegistrationCallback> mCallbacks;
+ private final List<RegistrationManager.RegistrationCallback> mCallbacks;
private int mAddRegistrationCallbackCalls = 0;
private int mRemoveRegistrationListenerCalls = 0;
@@ -518,7 +661,7 @@
SubscriptionManagerProxy subManagerProxy, SettingsProxy settingsProxy,
BinderCacheManager binderCacheManager) {
super(context, phoneId, factory, subManagerProxy, settingsProxy, binderCacheManager);
- mCallbacks = new HashSet<>();
+ mCallbacks = new ArrayList<>();
}
@Override
@@ -535,7 +678,9 @@
}
callback.setExecutor(executor);
- mCallbacks.add(callback);
+ if (!mCallbacks.contains(callback)) {
+ mCallbacks.add(callback);
+ }
}
@Override
@@ -556,20 +701,24 @@
return mRemoveRegistrationListenerCalls;
}
- public void sendImsRegistrationStateChangedEvent(boolean registered) {
+ public void sendImsRegistrationStateChangedEvent(int callbackIndex, boolean registered) {
+ if (callbackIndex < 0 || callbackIndex >= mCallbacks.size()) {
+ throw new IndexOutOfBoundsException("sendImsRegistrationStateChangedEvent: invalid"
+ + "callbackIndex=" + callbackIndex
+ + ", mCallbacks.size=" + mCallbacks.size());
+ }
+ RegistrationManager.RegistrationCallback callback = mCallbacks.get(callbackIndex);
if (registered) {
- for (RegistrationManager.RegistrationCallback callback : mCallbacks) {
- callback.onRegistered(null);
- }
+ callback.onRegistered(null);
} else {
- for (RegistrationManager.RegistrationCallback callback : mCallbacks) {
- callback.onUnregistered(null);
- }
+ callback.onUnregistered(null);
}
}
}
private static class TestSOSMessageRecommender extends SatelliteSOSMessageRecommender {
+ private ComponentName mSmsAppComponent = new ComponentName(
+ DEFAULT_SATELLITE_MESSAGING_PACKAGE, DEFAULT_SATELLITE_MESSAGING_CLASS);
/**
* Create an instance of SatelliteSOSMessageRecommender.
@@ -581,9 +730,15 @@
* null only in unit tests.
* @param timeoutMillis The timeout duration of the timer.
*/
- TestSOSMessageRecommender(Looper looper, SatelliteController satelliteController,
- ImsManager imsManager, long timeoutMillis) {
- super(looper, satelliteController, imsManager, timeoutMillis);
+ TestSOSMessageRecommender(Context context, Looper looper,
+ SatelliteController satelliteController, ImsManager imsManager,
+ long timeoutMillis) {
+ super(context, looper, satelliteController, imsManager, timeoutMillis);
+ }
+
+ @Override
+ protected ComponentName getDefaultSmsApp() {
+ return mSmsAppComponent;
}
public boolean isTimerStarted() {
@@ -594,28 +749,66 @@
return mCountOfTimerStarted;
}
- public void sendServiceStateChangedEvent(@ServiceState.RegState int state) {
- ServiceState serviceState = new ServiceState();
- serviceState.setState(state);
- sendMessage(obtainMessage(EVENT_CELLULAR_SERVICE_STATE_CHANGED,
- new AsyncResult(null, serviceState, null)));
+ public void sendServiceStateChangedEvent() {
+ sendMessage(obtainMessage(EVENT_SERVICE_STATE_CHANGED));
}
}
private static class TestConnection extends Connection {
- private final Set<String> mSentEvents;
+ private String mSentEvent = null;
+ private Bundle mExtras = null;
TestConnection(String callId) {
setTelecomCallId(callId);
- mSentEvents = new HashSet<>();
}
@Override
public void sendConnectionEvent(String event, Bundle extras) {
- mSentEvents.add(event);
+ mSentEvent = event;
+ mExtras = extras;
+ }
+
+ public boolean isEventSent(String event, int handoverType, String packageName,
+ String className, String action) {
+ if (mSentEvent == null || mExtras == null) {
+ return false;
+ }
+
+ PendingIntent pendingIntent = mExtras.getParcelable(
+ EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT, PendingIntent.class);
+ Intent intent = pendingIntent.getIntent();
+ if (!TextUtils.equals(event, mSentEvent) || handoverType != mExtras.getInt(
+ EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE)
+ || !TextUtils.equals(packageName, intent.getComponent().getPackageName())
+ || !TextUtils.equals(className, intent.getComponent().getClassName())
+ || !TextUtils.equals(action, intent.getAction())) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean isEventWithoutLaunchIntentSent(String event, int handoverType) {
+ if (mSentEvent == null || mExtras == null) {
+ return false;
+ }
+
+ PendingIntent pendingIntent = mExtras.getParcelable(
+ EXTRA_EMERGENCY_CALL_TO_SATELLITE_LAUNCH_INTENT, PendingIntent.class);
+ if (!TextUtils.equals(event, mSentEvent) || handoverType != mExtras.getInt(
+ EXTRA_EMERGENCY_CALL_TO_SATELLITE_HANDOVER_TYPE) || pendingIntent != null) {
+ return false;
+ }
+
+ return true;
}
public boolean isEventSent(String event) {
- return mSentEvents.contains(event);
+ if (mSentEvent == null) {
+ return false;
+ }
+ if (!TextUtils.equals(event, mSentEvent)) {
+ return false;
+ }
+ return true;
}
}
}
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
index 230f147..1d320a3 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccSlotTest.java
@@ -42,7 +42,6 @@
import org.junit.Test;
public class UiccSlotTest extends TelephonyTest {
- private UiccSlot mUiccSlot;
private UiccSlotTestHandlerThread mTestHandlerThread;
private Handler mTestHandler;
@@ -263,7 +262,7 @@
// assert on updated values
assertTrue(mUiccSlot.isActive());
- assertEquals(mUiccSlot.getMinimumVoltageClass(), UiccSlot.VOLTAGE_CLASS_A);
+ assertEquals(UiccSlot.VOLTAGE_CLASS_A, mUiccSlot.getMinimumVoltageClass());
}
@Test
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
index 7e51bad..d5b6ccb 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/UiccStateChangedLauncherTest.java
@@ -50,7 +50,6 @@
private static final String PROVISIONING_PACKAGE_NAME = "test.provisioning.package";
// Mocked classes
- private Context mContext;
private Resources mResources;
private IccCardStatus makeCardStatus(CardState state) {
diff --git a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
index b6dd7bd..c38be60 100644
--- a/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
+++ b/tests/telephonytests/src/com/android/internal/telephony/uicc/euicc/EuiccCardTest.java
@@ -52,7 +52,6 @@
private static class ResultCaptor<T> extends AsyncResultCallback<T> {
public T result;
- public Throwable exception;
private CountDownLatch mLatch;
@@ -68,7 +67,6 @@
@Override
public void onException(Throwable e) {
- exception = e;
mLatch.countDown();
}
}