Merge "[Geofence] Write/read entry value byte count and version number to/from the header block" into main
diff --git a/src/com/android/phone/PhoneInterfaceManager.java b/src/com/android/phone/PhoneInterfaceManager.java
index d7f7939..bd90a9d 100644
--- a/src/com/android/phone/PhoneInterfaceManager.java
+++ b/src/com/android/phone/PhoneInterfaceManager.java
@@ -158,6 +158,7 @@
import android.telephony.satellite.ISatelliteCapabilitiesCallback;
import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
import android.telephony.satellite.ISatelliteDatagramCallback;
+import android.telephony.satellite.ISatelliteDisallowedReasonsCallback;
import android.telephony.satellite.ISatelliteModemStateCallback;
import android.telephony.satellite.ISatelliteProvisionStateCallback;
import android.telephony.satellite.ISatelliteSupportedStateCallback;
@@ -13225,8 +13226,14 @@
return;
}
if (isAllowed) {
- mSatelliteController.requestSatelliteEnabled(
- enableSatellite, enableDemoMode, isEmergency, callback);
+ if (mFeatureFlags.carrierRoamingNbIotNtn()
+ && !mSatelliteAccessController.getSatelliteDisallowedReasons()
+ .isEmpty()) {
+ result.accept(SATELLITE_RESULT_ACCESS_BARRED);
+ } else {
+ mSatelliteController.requestSatelliteEnabled(
+ enableSatellite, enableDemoMode, isEmergency, callback);
+ }
} else {
result.accept(SATELLITE_RESULT_ACCESS_BARRED);
}
@@ -13634,6 +13641,64 @@
}
/**
+ * Returns integer array of disallowed reasons of satellite.
+ *
+ * @return Integer array of disallowed reasons of satellite.
+ *
+ * @throws SecurityException if the caller doesn't have the required permission.
+ */
+ @NonNull public int[] getSatelliteDisallowedReasons() {
+ enforceSatelliteCommunicationPermission("getSatelliteDisallowedReasons");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ return mSatelliteAccessController.getSatelliteDisallowedReasons()
+ .stream().mapToInt(Integer::intValue).toArray();
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Registers for disallowed reasons change event from satellite service.
+ *
+ * @param callback The callback to handle disallowed reasons changed event.
+ *
+ * @throws SecurityException if the caller doesn't have the required permission.
+ */
+ @Override
+ public void registerForSatelliteDisallowedReasonsChanged(
+ @NonNull ISatelliteDisallowedReasonsCallback callback) {
+ enforceSatelliteCommunicationPermission("registerForSatelliteDisallowedReasonsChanged");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSatelliteAccessController.registerForSatelliteDisallowedReasonsChanged(callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
+ * Unregisters for disallowed reasons change event from satellite service.
+ * If callback was not registered before, the request will be ignored.
+ *
+ * @param callback The callback to handle disallowed reasons changed event.
+ * {@link #registerForSatelliteDisallowedReasonsChanged(
+ * ISatelliteDisallowedReasonsCallback)}.
+ * @throws SecurityException if the caller doesn't have the required permission.
+ */
+ @Override
+ public void unregisterForSatelliteDisallowedReasonsChanged(
+ @NonNull ISatelliteDisallowedReasonsCallback callback) {
+ enforceSatelliteCommunicationPermission("unregisterForSatelliteDisallowedReasonsChanged");
+ final long identity = Binder.clearCallingIdentity();
+ try {
+ mSatelliteAccessController.unregisterForSatelliteDisallowedReasonsChanged(callback);
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ /**
* Request to get whether satellite communication is allowed for the current location.
*
* @param subId The subId of the subscription to check whether satellite communication is
diff --git a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
index 78e4ace..49edf6a 100644
--- a/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
+++ b/src/com/android/phone/satellite/accesscontrol/SatelliteAccessController.java
@@ -19,6 +19,11 @@
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_COMMUNICATION_ALLOWED;
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_PROVISIONED;
import static android.telephony.satellite.SatelliteManager.KEY_SATELLITE_SUPPORTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP;
+import static android.telephony.satellite.SatelliteManager.SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_DISABLED;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_LOCATION_NOT_AVAILABLE;
import static android.telephony.satellite.SatelliteManager.SATELLITE_RESULT_NOT_SUPPORTED;
@@ -34,7 +39,11 @@
import android.annotation.ArrayRes;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.Notification;
+import android.app.NotificationChannel;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -56,14 +65,17 @@
import android.os.ResultReceiver;
import android.os.SystemClock;
import android.os.SystemProperties;
+import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.telecom.TelecomManager;
import android.telephony.AnomalyReporter;
import android.telephony.DropBoxManagerLoggerBackend;
+import android.telephony.NetworkRegistrationInfo;
import android.telephony.PersistentLogger;
import android.telephony.Rlog;
import android.telephony.SubscriptionManager;
import android.telephony.satellite.ISatelliteCommunicationAllowedStateCallback;
+import android.telephony.satellite.ISatelliteDisallowedReasonsCallback;
import android.telephony.satellite.ISatelliteProvisionStateCallback;
import android.telephony.satellite.ISatelliteSupportedStateCallback;
import android.telephony.satellite.SatelliteManager;
@@ -76,6 +88,7 @@
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.TelephonyCountryDetector;
import com.android.internal.telephony.flags.FeatureFlags;
import com.android.internal.telephony.satellite.SatelliteConfig;
@@ -97,6 +110,7 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
@@ -147,6 +161,56 @@
public static final int DEFAULT_REGIONAL_SATELLITE_CONFIG_ID = 0;
+ private static final String KEY_AVAILABLE_NOTIFICATION_SHOWN = "available_notification_shown";
+ private static final String KEY_UNAVAILABLE_NOTIFICATION_SHOWN =
+ "unavailable_notification_shown";
+ private static final String NOTIFICATION_TAG = "SatelliteAccessController";
+ private static final int NOTIFICATION_ID = 1;
+ private static final String NOTIFICATION_CHANNEL = "satelliteChannel";
+ private static final String NOTIFICATION_CHANNEL_ID = "satellite";
+ private static final int SATELLITE_DISALLOWED_REASON_NONE = -1;
+ private static final List<Integer> DISALLOWED_REASONS_TO_BE_RESET =
+ Arrays.asList(SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION,
+ SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED);
+
+ private static final HashMap<Integer, Pair<Integer, Integer>>
+ SATELLITE_SOS_UNAVAILABLE_REASONS = new HashMap<>(Map.of(
+ SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED, new Pair<>(
+ R.string.satellite_sos_not_supported_notification_title,
+ R.string.satellite_sos_not_supported_notification_summary),
+ SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED, new Pair<>(
+ R.string.satellite_sos_not_provisioned_notification_title,
+ R.string.satellite_sos_not_provisioned_notification_summary),
+ SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION, new Pair<>(
+ R.string.satellite_sos_not_in_allowed_region_notification_title,
+ R.string.satellite_sos_not_in_allowed_region_notification_summary),
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP, new Pair<>(
+ R.string.satellite_sos_unsupported_default_sms_app_notification_title,
+ R.string.satellite_sos_unsupported_default_sms_app_notification_summary),
+ SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED, new Pair<>(
+ R.string.satellite_sos_location_disabled_notification_title,
+ R.string.satellite_sos_location_disabled_notification_summary)
+ ));
+
+ private static final HashMap<Integer, Pair<Integer, Integer>>
+ SATELLITE_MESSAGING_UNAVAILABLE_REASONS = new HashMap<>(Map.of(
+ SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED, new Pair<>(
+ R.string.satellite_messaging_not_supported_notification_title,
+ R.string.satellite_messaging_not_supported_notification_summary),
+ SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED, new Pair<>(
+ R.string.satellite_messaging_not_provisioned_notification_title,
+ R.string.satellite_messaging_not_provisioned_notification_summary),
+ SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION, new Pair<>(
+ R.string.satellite_messaging_not_in_allowed_region_notification_title,
+ R.string.satellite_messaging_not_in_allowed_region_notification_summary),
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP, new Pair<>(
+ R.string.satellite_messaging_unsupported_default_sms_app_notification_title,
+ R.string.satellite_messaging_unsupported_default_sms_app_notification_summary),
+ SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED, new Pair<>(
+ R.string.satellite_messaging_location_disabled_notification_title,
+ R.string.satellite_messaging_location_disabled_notification_summary)
+ ));
+
private static SatelliteAccessController sInstance;
/** Feature flags to control behavior and errors. */
@@ -268,6 +332,10 @@
@GuardedBy("mSatelliteCommunicationAllowStateLock")
protected boolean mCurrentSatelliteAllowedState = false;
+ private final ConcurrentHashMap<IBinder, ISatelliteDisallowedReasonsCallback>
+ mSatelliteDisallowedReasonsChangedListeners = new ConcurrentHashMap<>();
+ private final Object mSatelliteDisallowedReasonsLock = new Object();
+
protected static final long ALLOWED_STATE_CACHE_VALID_DURATION_NANOS =
TimeUnit.HOURS.toNanos(4);
@@ -278,6 +346,13 @@
private long mOnDeviceLookupStartTimeMillis;
private long mTotalCheckingStartTimeMillis;
+ private final boolean mNotifySatelliteAvailabilityEnabled;
+ private Notification mSatelliteAvailableNotification;
+ // Key: SatelliteManager#SatelliteDisallowedReason; Value: Notification
+ private final Map<Integer, Notification> mSatelliteUnAvailableNotifications = new HashMap<>();
+ private NotificationManager mNotificationManager;
+ private final List<Integer> mSatelliteDisallowedReasons = new ArrayList<>();
+
protected BroadcastReceiver mLocationModeChangedBroadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
@@ -358,6 +433,9 @@
};
mConfigUpdaterMetricsStats = ConfigUpdaterMetricsStats.getOrCreateInstance();
+ mNotifySatelliteAvailabilityEnabled =
+ context.getResources().getBoolean(
+ R.bool.config_satellite_should_notify_availability);
mInternalSatelliteSupportedStateCallback = new ISatelliteSupportedStateCallback.Stub() {
@Override
@@ -371,6 +449,19 @@
// do nothing
}
}, false);
+ if (mSatelliteDisallowedReasons.contains(
+ Integer.valueOf(SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED))) {
+ mSatelliteDisallowedReasons.remove(
+ Integer.valueOf(SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED));
+ handleEventDisallowedReasonsChanged();
+ }
+ } else {
+ if (!mSatelliteDisallowedReasons.contains(
+ Integer.valueOf(SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED))) {
+ mSatelliteDisallowedReasons.add(
+ Integer.valueOf(SATELLITE_DISALLOWED_REASON_NOT_SUPPORTED));
+ handleEventDisallowedReasonsChanged();
+ }
}
}
};
@@ -389,6 +480,19 @@
// do nothing
}
}, false);
+ if (mSatelliteDisallowedReasons.contains(
+ SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED)) {
+ mSatelliteDisallowedReasons.remove(
+ Integer.valueOf(SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED));
+ handleEventDisallowedReasonsChanged();
+ }
+ } else {
+ if (!mSatelliteDisallowedReasons.contains(
+ SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED)) {
+ mSatelliteDisallowedReasons.add(
+ SATELLITE_DISALLOWED_REASON_NOT_PROVISIONED);
+ handleEventDisallowedReasonsChanged();
+ }
}
}
@@ -404,7 +508,9 @@
// Init the SatelliteOnDeviceAccessController so that the S2 level can be cached
initSatelliteOnDeviceAccessController();
+ initializeSatelliteSystemNotification(context);
registerLocationModeChangedBroadcastReceiver(context);
+ registerDefaultSmsAppChangedBroadcastReceiver(context);
}
private void updateCurrentSatelliteAllowedState(boolean isAllowed) {
@@ -951,6 +1057,18 @@
}
}
+ private void registerDefaultSmsAppChangedBroadcastReceiver(Context context) {
+ if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
+ plogd("registerDefaultSmsAppChangedBroadcastReceiver: Flag "
+ + "oemEnabledSatellite is disabled");
+ return;
+ }
+ IntentFilter intentFilter = new IntentFilter();
+ intentFilter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+ intentFilter.addDataScheme("package");
+ context.registerReceiver(mDefaultSmsAppChangedBroadcastReceiver, intentFilter);
+ }
+
private void registerLocationModeChangedBroadcastReceiver(Context context) {
if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
plogd("registerLocationModeChangedBroadcastReceiver: Flag "
@@ -1054,7 +1172,7 @@
}
private void sendSatelliteAllowResultToReceivers(int resultCode, Bundle resultData,
- boolean allowed) {
+ boolean allowed) {
plogd("sendSatelliteAllowResultToReceivers : resultCode is " + resultCode);
if (resultCode == SATELLITE_RESULT_SUCCESS) {
updateCurrentSatelliteAllowedState(allowed);
@@ -1068,12 +1186,95 @@
if (!shouldRetryValidatingPossibleChangeInAllowedRegion(resultCode)) {
setIsSatelliteAllowedRegionPossiblyChanged(false);
}
+ Integer disallowedReason = getDisallowedReason(resultCode, allowed);
+ boolean isChanged = false;
+ if (disallowedReason != SATELLITE_DISALLOWED_REASON_NONE) {
+ if (!mSatelliteDisallowedReasons.contains(disallowedReason)) {
+ isChanged = true;
+ }
+ } else {
+ if (mSatelliteDisallowedReasons.contains(
+ SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION)
+ || mSatelliteDisallowedReasons.contains(
+ SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED)) {
+ isChanged = true;
+ }
+ }
+ mSatelliteDisallowedReasons.removeAll(DISALLOWED_REASONS_TO_BE_RESET);
+ if (disallowedReason != SATELLITE_DISALLOWED_REASON_NONE) {
+ mSatelliteDisallowedReasons.add(disallowedReason);
+ }
+ if (isChanged) {
+ handleEventDisallowedReasonsChanged();
+ }
synchronized (mIsAllowedCheckBeforeEnablingSatelliteLock) {
mIsAllowedCheckBeforeEnablingSatellite = false;
}
reportMetrics(resultCode, allowed);
}
+ private int getDisallowedReason(int resultCode, boolean allowed) {
+ if (resultCode == SATELLITE_RESULT_SUCCESS) {
+ if (!allowed) {
+ return SATELLITE_DISALLOWED_REASON_NOT_IN_ALLOWED_REGION;
+ }
+ } else if (resultCode == SATELLITE_RESULT_LOCATION_DISABLED) {
+ return SATELLITE_DISALLOWED_REASON_LOCATION_DISABLED;
+ }
+ return SATELLITE_DISALLOWED_REASON_NONE;
+ }
+
+ private void handleEventDisallowedReasonsChanged() {
+ logd("mSatelliteDisallowedReasons:"
+ + String.join(", ", mSatelliteDisallowedReasons.toString()));
+ notifySatelliteDisallowedReasonsChanged();
+ if (mNotifySatelliteAvailabilityEnabled) {
+ showSatelliteSystemNotification();
+ }
+ }
+
+ private void showSatelliteSystemNotification() {
+ if (mSatelliteDisallowedReasons.isEmpty()) {
+ if (!hasAlreadyNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN, 0)) {
+ mNotificationManager.notifyAsUser(
+ NOTIFICATION_TAG,
+ NOTIFICATION_ID,
+ mSatelliteAvailableNotification,
+ UserHandle.ALL
+ );
+ markAsNotified(KEY_AVAILABLE_NOTIFICATION_SHOWN, 0);
+ }
+ } else {
+ for (Integer reason : mSatelliteDisallowedReasons) {
+ if (!hasAlreadyNotified(KEY_UNAVAILABLE_NOTIFICATION_SHOWN, reason)) {
+ mNotificationManager.notifyAsUser(
+ NOTIFICATION_TAG,
+ NOTIFICATION_ID,
+ mSatelliteUnAvailableNotifications.get(reason),
+ UserHandle.ALL
+ );
+ markAsNotified(KEY_UNAVAILABLE_NOTIFICATION_SHOWN, reason);
+ break;
+ }
+ }
+ }
+ }
+
+ private boolean hasAlreadyNotified(String key, int reason) {
+ Set<String> reasons = mSharedPreferences.getStringSet(key, new HashSet<>());
+ return reasons.contains(String.valueOf(reason));
+ }
+
+ private void markAsNotified(String key, int reason) {
+ Set<String> reasons = mSharedPreferences.getStringSet(key, new HashSet<>());
+ if (!reasons.contains(String.valueOf(reason))) {
+ reasons.add(String.valueOf(reason));
+ SharedPreferences.Editor editor = mSharedPreferences.edit();
+ editor.putStringSet(key, reasons);
+ editor.apply();
+ }
+ }
+
/**
* Telephony-internal logic to verify if satellite access is restricted at the current
* location.
@@ -1137,6 +1338,122 @@
};
}
+ private void initializeSatelliteSystemNotification(@NonNull Context context) {
+ final NotificationChannel notificationChannel = new NotificationChannel(
+ NOTIFICATION_CHANNEL_ID,
+ NOTIFICATION_CHANNEL,
+ NotificationManager.IMPORTANCE_DEFAULT
+ );
+ notificationChannel.setSound(null, null);
+ mNotificationManager = context.getSystemService(NotificationManager.class);
+ mNotificationManager.createNotificationChannel(notificationChannel);
+
+ createAvailableNotifications(context);
+ createUnavailableNotifications(context);
+ }
+
+ private Notification createNotification(@NonNull Context context,
+ String title,
+ String content) {
+ Notification.Builder notificationBuilder = new Notification.Builder(context)
+ .setContentTitle(title)
+ .setContentText(content)
+ .setSmallIcon(R.drawable.ic_android_satellite_24px)
+ .setChannelId(NOTIFICATION_CHANNEL_ID)
+ .setAutoCancel(true)
+ .setColor(context.getColor(
+ com.android.internal.R.color.system_notification_accent_color))
+ .setVisibility(Notification.VISIBILITY_PUBLIC);
+
+ return notificationBuilder.build();
+ }
+
+ private void createAvailableNotifications(Context context) {
+ int subId = mSatelliteController.getSelectedSatelliteSubId();
+ int titleId;
+ int summaryId;
+
+ if (mSatelliteController.isSatelliteServiceSupportedByCarrier(
+ subId, NetworkRegistrationInfo.SERVICE_TYPE_SMS)) {
+ titleId = R.string.satellite_messaging_available_notification_title;
+ summaryId = R.string.satellite_messaging_available_notification_summary;
+ } else {
+ titleId = R.string.satellite_sos_available_notification_title;
+ summaryId = R.string.satellite_sos_available_notification_summary;
+ }
+
+ mSatelliteAvailableNotification = createNotification(
+ context,
+ context.getResources().getString(titleId),
+ context.getResources().getString(summaryId));
+ }
+
+ private void createUnavailableNotifications(Context context) {
+ int subId = mSatelliteController.getSelectedSatelliteSubId();
+
+ HashMap<Integer, Pair<Integer, Integer>> unavailableReasons;
+ if (mSatelliteController.isSatelliteServiceSupportedByCarrier(
+ subId, NetworkRegistrationInfo.SERVICE_TYPE_SMS)) {
+ unavailableReasons = SATELLITE_MESSAGING_UNAVAILABLE_REASONS;
+ } else {
+ unavailableReasons = SATELLITE_SOS_UNAVAILABLE_REASONS;
+ }
+
+ for (int reason : unavailableReasons.keySet()) {
+ Pair<Integer, Integer> notificationString =
+ unavailableReasons.getOrDefault(reason, null);
+ if (notificationString != null) {
+ mSatelliteUnAvailableNotifications.put(reason,
+ createNotification(
+ context,
+ context.getResources().getString(notificationString.first),
+ context.getResources().getString(notificationString.second)));
+ }
+ }
+ }
+
+ private final BroadcastReceiver mDefaultSmsAppChangedBroadcastReceiver =
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (intent.getAction()
+ .equals(Intent.ACTION_PACKAGE_CHANGED)) {
+ boolean isDefaultMsgAppSupported = false;
+ ComponentName componentName =
+ SmsApplication.getDefaultSmsApplicationAsUser(
+ context, true, context.getUser());
+ logd("Current default SMS app:" + componentName);
+ if (componentName != null) {
+ String packageName = componentName.getPackageName();
+ List<String> supportedMsgApps =
+ mSatelliteController.getSatelliteSupportedMsgApps(
+ mSatelliteController.getSelectedSatelliteSubId());
+ if (supportedMsgApps.contains(packageName)) {
+ isDefaultMsgAppSupported = true;
+ }
+ } else {
+ logd("No default SMS app");
+ }
+
+ if (isDefaultMsgAppSupported) {
+ if (mSatelliteDisallowedReasons.contains(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP))) {
+ mSatelliteDisallowedReasons.remove(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP));
+ handleEventDisallowedReasonsChanged();
+ }
+ } else {
+ if (!mSatelliteDisallowedReasons.contains(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP))) {
+ mSatelliteDisallowedReasons.add(Integer.valueOf(
+ SATELLITE_DISALLOWED_REASON_UNSUPPORTED_DEFAULT_MSG_APP));
+ handleEventDisallowedReasonsChanged();
+ }
+ }
+ }
+ }
+ };
+
private void handleSatelliteAllowedRegionPossiblyChanged(int handleEvent) {
if (!mFeatureFlags.oemEnabledSatelliteFlag()) {
ploge("handleSatelliteAllowedRegionPossiblyChanged: "
@@ -1912,6 +2229,74 @@
}
/**
+ * Returns integer array of disallowed reasons of satellite.
+ *
+ * @return Integer array of disallowed reasons of satellite.
+ *
+ */
+ @NonNull public List<Integer> getSatelliteDisallowedReasons() {
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ plogd("getSatelliteDisallowedReasons: carrierRoamingNbIotNtn is disabled");
+ return new ArrayList<>();
+ }
+
+ synchronized (mSatelliteDisallowedReasonsLock) {
+ return mSatelliteDisallowedReasons;
+ }
+ }
+
+ /**
+ * Registers for disallowed reasons change event from satellite service.
+ *
+ * @param callback The callback to handle disallowed reasons changed event.
+ *
+ */
+ public void registerForSatelliteDisallowedReasonsChanged(
+ @NonNull ISatelliteDisallowedReasonsCallback callback) {
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ plogd("registerForSatelliteDisallowedReasonsChanged: carrierRoamingNbIotNtn is "
+ + "disabled");
+ return;
+ }
+
+ mSatelliteDisallowedReasonsChangedListeners.put(callback.asBinder(), callback);
+
+ this.post(() -> {
+ try {
+ synchronized (mSatelliteDisallowedReasonsLock) {
+ callback.onSatelliteDisallowedReasonsChanged(
+ mSatelliteDisallowedReasons.stream()
+ .mapToInt(Integer::intValue)
+ .toArray());
+ logd("registerForSatelliteDisallowedReasonsChanged: "
+ + "mSatelliteDisallowedReasons " + mSatelliteDisallowedReasons.size());
+ }
+ } catch (RemoteException ex) {
+ ploge("registerForSatelliteDisallowedReasonsChanged: RemoteException ex=" + ex);
+ }
+ });
+ }
+
+ /**
+ * Unregisters for disallowed reasons change event from satellite service.
+ * If callback was not registered before, the request will be ignored.
+ *
+ * @param callback The callback that was passed to
+ * {@link #registerForSatelliteDisallowedReasonsChanged(
+ * ISatelliteDisallowedReasonsCallback)}.
+ */
+ public void unregisterForSatelliteDisallowedReasonsChanged(
+ @NonNull ISatelliteDisallowedReasonsCallback callback) {
+ if (!mFeatureFlags.carrierRoamingNbIotNtn()) {
+ plogd("unregisterForSatelliteDisallowedReasonsChanged: "
+ + "carrierRoamingNbIotNtn is disabled");
+ return;
+ }
+
+ mSatelliteDisallowedReasonsChangedListeners.remove(callback.asBinder());
+ }
+
+ /**
* This API can be used by only CTS to set the cache whether satellite communication is allowed.
*
* @param state a state indicates whether satellite access allowed state should be cached and
@@ -1977,6 +2362,26 @@
});
}
+ private void notifySatelliteDisallowedReasonsChanged() {
+ plogd("notifySatelliteDisallowedReasonsChanged");
+
+ List<ISatelliteDisallowedReasonsCallback> deadCallersList = new ArrayList<>();
+ mSatelliteDisallowedReasonsChangedListeners.values().forEach(listener -> {
+ try {
+ listener.onSatelliteDisallowedReasonsChanged(
+ mSatelliteDisallowedReasons.stream()
+ .mapToInt(Integer::intValue)
+ .toArray());
+ } catch (RemoteException e) {
+ plogd("notifySatelliteDisallowedReasonsChanged RemoteException: " + e);
+ deadCallersList.add(listener);
+ }
+ });
+ deadCallersList.forEach(listener -> {
+ mSatelliteDisallowedReasonsChangedListeners.remove(listener.asBinder());
+ });
+ }
+
private void reportMetrics(int resultCode, boolean allowed) {
if (resultCode == SATELLITE_RESULT_SUCCESS) {
mControllerMetricsStats.reportAllowedSatelliteAccessCount(allowed);
diff --git a/src/com/android/phone/settings/RadioInfo.java b/src/com/android/phone/settings/RadioInfo.java
index 7a1d093..579a853 100644
--- a/src/com/android/phone/settings/RadioInfo.java
+++ b/src/com/android/phone/settings/RadioInfo.java
@@ -786,9 +786,13 @@
mSatelliteEnableNonEmergencyModeButton = (Button) findViewById(
R.id.satellite_enable_non_emergency_mode);
CarrierConfigManager cm = getSystemService(CarrierConfigManager.class);
- if (!cm.getConfigForSubId(mSubId,
- CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL)
- .getBoolean(CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL)) {
+ PersistableBundle bundle = cm.getConfigForSubId(mSubId,
+ CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL,
+ CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL);
+ if (!bundle.getBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ESOS_SUPPORTED_BOOL, false)
+ || !bundle.getBoolean(
+ CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false)) {
mSatelliteEnableNonEmergencyModeButton.setVisibility(View.GONE);
}
if (!Build.isDebuggable()) {
diff --git a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
index 971f87a..c2f5979 100644
--- a/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
+++ b/tests/src/com/android/phone/satellite/accesscontrol/SatelliteAccessControllerTest.java
@@ -63,16 +63,21 @@
import static org.mockito.Mockito.when;
import android.annotation.Nullable;
+import android.app.NotificationManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
import android.content.res.Resources;
import android.location.Location;
import android.location.LocationManager;
import android.location.LocationRequest;
import android.os.AsyncResult;
+import android.os.Build;
import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.DropBoxManager;
@@ -81,8 +86,10 @@
import android.os.Looper;
import android.os.Message;
import android.os.ResultReceiver;
+import android.os.UserHandle;
import android.telecom.TelecomManager;
import android.telephony.SubscriptionManager;
+import android.telephony.TelephonyManager;
import android.telephony.satellite.SatelliteManager;
import android.testing.TestableLooper;
import android.util.Log;
@@ -189,6 +196,17 @@
private Set<ResultReceiver> mMockSatelliteAllowResultReceivers;
@Mock
private ResultReceiver mMockSatelliteSupportedResultReceiver;
+ @Mock
+ private TelephonyManager mMockTelephonyManager;
+ @Mock
+ private PackageManager mMockPackageManager;
+ @Mock
+ private List<ResolveInfo> mMockResolveInfoList;
+ @Mock
+ private NotificationManager mMockNotificationManager;
+ @Mock
+ private ApplicationInfo mMockApplicationInfo;
+
private Looper mLooper;
private TestableLooper mTestableLooper;
@@ -343,6 +361,22 @@
when(mMockFeatureFlags.oemEnabledSatelliteFlag()).thenReturn(true);
when(mMockFeatureFlags.carrierRoamingNbIotNtn()).thenReturn(true);
+ when(mMockContext.getSystemService(Context.TELEPHONY_SERVICE))
+ .thenReturn(mMockTelephonyManager);
+ when(mMockTelephonyManager.isSmsCapable()).thenReturn(true);
+ when(mMockContext.getPackageManager()).thenReturn(mMockPackageManager);
+ mMockResolveInfoList = new ArrayList<>();
+ when(mMockPackageManager.queryBroadcastReceiversAsUser(any(Intent.class), anyInt(), any(
+ UserHandle.class)))
+ .thenReturn(mMockResolveInfoList);
+ when(mMockContext.getSystemServiceName(
+ NotificationManager.class)).thenReturn(Context.NOTIFICATION_SERVICE);
+ when(mMockContext.getSystemService(Context.NOTIFICATION_SERVICE))
+ .thenReturn(mMockNotificationManager);
+ when(mMockContext.getApplicationInfo()).thenReturn(mMockApplicationInfo);
+ mMockApplicationInfo.targetSdkVersion = Build.VERSION_CODES.UPSIDE_DOWN_CAKE;
+ when(mMockPackageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenReturn(mMockApplicationInfo);
mSatelliteAccessControllerUT = new TestSatelliteAccessController(mMockContext,
mMockFeatureFlags, mLooper, mMockLocationManager, mMockTelecomManager,
mMockSatelliteOnDeviceAccessController, mMockSatS2File);
@@ -1148,11 +1182,9 @@
mSatelliteAccessControllerUT.elapsedRealtimeNanos = TEST_LOCATION_FRESH_DURATION_NANOS + 1;
// Captor and Verify if the mockReceiver and mocContext is registered well
- verify(mMockContext).registerReceiver(mLocationBroadcastReceiverCaptor.capture(),
+ verify(mMockContext, times(2))
+ .registerReceiver(mLocationBroadcastReceiverCaptor.capture(),
mIntentFilterCaptor.capture());
- assertSame(mSatelliteAccessControllerUT.getLocationBroadcastReceiver(),
- mLocationBroadcastReceiverCaptor.getValue());
- assertSame(MODE_CHANGED_ACTION, mIntentFilterCaptor.getValue().getAction(0));
// When the intent action is not MODE_CHANGED_ACTION,
// verify if the location manager never invoke isLocationEnabled()