From dc788ed9d1479064509a1cb36a08b0fcea7e1cbe Mon Sep 17 00:00:00 2001 From: tom hsu Date: Wed, 19 Mar 2025 08:53:27 +0000 Subject: [PATCH] [Satellite] Use satellite data mode for UX visibility - Use SatelliteManager#getSatelliteDataSupportMode() to check data restricted or not. Flag: EXEMPT bug fix Bug: b/401043401 Test: atest pass Test: Manual test Change-Id: I6f3e25610717eca0f6e871a9e1158422659058ea --- .../settings/network/SatelliteRepository.kt | 3 - .../SatelliteAppListCategoryController.java | 84 ++++++++--- .../telephony/satellite/SatelliteSetting.java | 53 ++++--- ...atelliteAppListCategoryControllerTest.java | 134 +++++++++++++++--- 4 files changed, 215 insertions(+), 59 deletions(-) diff --git a/src/com/android/settings/network/SatelliteRepository.kt b/src/com/android/settings/network/SatelliteRepository.kt index 994f8ec96d4..543961646de 100644 --- a/src/com/android/settings/network/SatelliteRepository.kt +++ b/src/com/android/settings/network/SatelliteRepository.kt @@ -202,9 +202,6 @@ open class SatelliteRepository( * e.g. "com.android.settings" */ open fun getSatelliteDataOptimizedApps(): List { - if (!Flags.satellite25q4Apis()) { - return emptyList() - } val satelliteManager: SatelliteManager? = context.getSystemService(SatelliteManager::class.java) if (satelliteManager == null) { diff --git a/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryController.java b/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryController.java index a29a388579a..d182229dd01 100644 --- a/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryController.java +++ b/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryController.java @@ -16,10 +16,17 @@ package com.android.settings.network.telephony.satellite; +import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL; + import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.drawable.Drawable; +import android.os.PersistableBundle; +import android.telephony.satellite.SatelliteManager; +import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.VisibleForTesting; @@ -27,20 +34,23 @@ import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceScreen; -import com.android.internal.telephony.flags.Flags; -import com.android.settings.core.BasePreferenceController; -import com.android.settings.network.SatelliteRepository; +import com.android.settings.network.telephony.TelephonyBasePreferenceController; import com.android.settingslib.Utils; import java.util.List; +import java.util.Set; /** A controller to show some of apps info which supported on Satellite service. */ -public class SatelliteAppListCategoryController extends BasePreferenceController { +public class SatelliteAppListCategoryController extends TelephonyBasePreferenceController { private static final String TAG = "SatelliteAppListCategoryController"; @VisibleForTesting static final int MAXIMUM_OF_PREFERENCE_AMOUNT = 3; private List mPackageNameList; + private boolean mIsSmsAvailable; + private boolean mIsDataAvailable; + private boolean mIsSatelliteEligible; + private PersistableBundle mConfigBundle = new PersistableBundle(); public SatelliteAppListCategoryController( @NonNull Context context, @@ -49,14 +59,14 @@ public class SatelliteAppListCategoryController extends BasePreferenceController } /** Initialize the necessary applications' data*/ - public void init() { - SatelliteRepository satelliteRepository = new SatelliteRepository(mContext); - init(satelliteRepository); - } - - @VisibleForTesting - void init(@NonNull SatelliteRepository satelliteRepository) { - mPackageNameList = satelliteRepository.getSatelliteDataOptimizedApps(); + public void init(int subId, @NonNull PersistableBundle configBundle, boolean isSmsAvailable, + boolean isDataAvailable) { + mSubId = subId; + mConfigBundle = configBundle; + mIsSmsAvailable = isSmsAvailable; + mIsDataAvailable = isDataAvailable; + mPackageNameList = getSatelliteDataOptimizedApps(); + mIsSatelliteEligible = isSatelliteEligible(); } @Override @@ -78,13 +88,53 @@ public class SatelliteAppListCategoryController extends BasePreferenceController } @Override - public int getAvailabilityStatus() { - if (!Flags.satellite25q4Apis()) { + public int getAvailabilityStatus(int subId) { + // Only when carrier support entitlement check, it shall check account eligible or not. + if (mConfigBundle.getBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL) + && !mIsSatelliteEligible) { return CONDITIONALLY_UNAVAILABLE; } - return mPackageNameList.isEmpty() - ? CONDITIONALLY_UNAVAILABLE - : AVAILABLE; + Log.d(TAG, "Supported apps have " + mPackageNameList.size()); + + return mIsDataAvailable && !mPackageNameList.isEmpty() + ? AVAILABLE_UNSEARCHABLE + : CONDITIONALLY_UNAVAILABLE; + } + + @VisibleForTesting + protected List getSatelliteDataOptimizedApps() { + SatelliteManager satelliteManager = mContext.getSystemService(SatelliteManager.class); + if (satelliteManager == null) { + return List.of(); + } + try { + return satelliteManager.getSatelliteDataOptimizedApps(); + } catch (IllegalStateException e) { + Log.d(TAG, "getSatelliteDataOptimizedApps failed due to " + e); + } + return List.of(); + } + + @VisibleForTesting + protected boolean isSatelliteEligible() { + if (mConfigBundle.getInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT) + == CARRIER_ROAMING_NTN_CONNECT_MANUAL) { + return mIsSmsAvailable; + } + SatelliteManager satelliteManager = mContext.getSystemService(SatelliteManager.class); + if (satelliteManager == null) { + Log.d(TAG, "SatelliteManager is null."); + return false; + } + try { + Set restrictionReason = + satelliteManager.getAttachRestrictionReasonsForCarrier(mSubId); + return !restrictionReason.contains( + SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT); + } catch (SecurityException | IllegalStateException | IllegalArgumentException ex) { + Log.d(TAG, "Error to getAttachRestrictionReasonsForCarrier : " + ex); + return false; + } } static ApplicationInfo getApplicationInfo(Context context, String packageName) { diff --git a/src/com/android/settings/network/telephony/satellite/SatelliteSetting.java b/src/com/android/settings/network/telephony/satellite/SatelliteSetting.java index e0f1d62a22e..8b7fdc68a4c 100644 --- a/src/com/android/settings/network/telephony/satellite/SatelliteSetting.java +++ b/src/com/android/settings/network/telephony/satellite/SatelliteSetting.java @@ -23,6 +23,7 @@ import static android.telephony.CarrierConfigManager.KEY_EMERGENCY_MESSAGING_SUP import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ATTACH_SUPPORTED_BOOL; import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL; import static android.telephony.CarrierConfigManager.KEY_SATELLITE_INFORMATION_REDIRECT_URL_STRING; +import static android.telephony.CarrierConfigManager.SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; import android.app.Activity; import android.app.settings.SettingsEnums; @@ -78,35 +79,30 @@ public class SatelliteSetting extends RestrictedDashboardFragment { public void onAttach(Context context) { super.onAttach(context); mActivity = getActivity(); - mSubId = mActivity.getIntent().getIntExtra(SUB_ID, - SubscriptionManager.INVALID_SUBSCRIPTION_ID); - mConfigBundle = fetchCarrierConfigData(mSubId); - mIsServiceDataType = getIntent().getBooleanExtra(EXTRA_IS_SERVICE_DATA_TYPE, false); - mIsSmsAvailableForManualType = getIntent().getBooleanExtra( - EXTRA_IS_SMS_AVAILABLE_FOR_MANUAL_TYPE, false); - - use(SatelliteAppListCategoryController.class).init(); - use(SatelliteSettingAboutContentController.class).init(mSubId); - use(SatelliteSettingAccountInfoController.class).init(mSubId, mConfigBundle, - mIsSmsAvailableForManualType, mIsServiceDataType); - use(SatelliteSettingFooterController.class).init(mSubId, mConfigBundle); - } - - @Override - public void onCreate(@NonNull Bundle savedInstanceState) { - super.onCreate(savedInstanceState); mSatelliteManager = mActivity.getSystemService(SatelliteManager.class); if (mSatelliteManager == null) { Log.d(TAG, "SatelliteManager is null, do nothing."); finish(); return; } - - if (!isSatelliteAttachSupported(mSubId)) { + mSubId = mActivity.getIntent().getIntExtra(SUB_ID, + SubscriptionManager.INVALID_SUBSCRIPTION_ID); + mConfigBundle = fetchCarrierConfigData(mSubId); + if (!isSatelliteAttachSupported()) { Log.d(TAG, "SatelliteSettings: KEY_SATELLITE_ATTACH_SUPPORTED_BOOL is false, " + "do nothing."); finish(); } + mIsServiceDataType = getIntent().getBooleanExtra(EXTRA_IS_SERVICE_DATA_TYPE, false); + mIsSmsAvailableForManualType = getIntent().getBooleanExtra( + EXTRA_IS_SMS_AVAILABLE_FOR_MANUAL_TYPE, false); + boolean isDataAvailableAndNotRestricted = isDataAvailableAndNotRestricted(); + use(SatelliteAppListCategoryController.class).init(mSubId, mConfigBundle, + mIsSmsAvailableForManualType, isDataAvailableAndNotRestricted); + use(SatelliteSettingAboutContentController.class).init(mSubId); + use(SatelliteSettingAccountInfoController.class).init(mSubId, mConfigBundle, + mIsSmsAvailableForManualType, isDataAvailableAndNotRestricted); + use(SatelliteSettingFooterController.class).init(mSubId, mConfigBundle); } @Override @@ -152,6 +148,7 @@ public class SatelliteSetting extends RestrictedDashboardFragment { try { Set restrictionReason = mSatelliteManager.getAttachRestrictionReasonsForCarrier(mSubId); + Log.d(TAG, "Restriction reason : " + restrictionReason); return !restrictionReason.contains( SatelliteManager.SATELLITE_COMMUNICATION_RESTRICTION_REASON_ENTITLEMENT); } catch (SecurityException | IllegalStateException | IllegalArgumentException ex) { @@ -186,10 +183,26 @@ public class SatelliteSetting extends RestrictedDashboardFragment { KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, CARRIER_ROAMING_NTN_CONNECT_AUTOMATIC); } - private boolean isSatelliteAttachSupported(int subId) { + private boolean isSatelliteAttachSupported() { return mConfigBundle.getBoolean(KEY_SATELLITE_ATTACH_SUPPORTED_BOOL, false); } + private boolean isDataAvailableAndNotRestricted() { + return getIntent().getBooleanExtra(EXTRA_IS_SERVICE_DATA_TYPE, false) + && !isDataRestricted(); + } + + private boolean isDataRestricted() { + int dataMode = SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; + try { + dataMode = mSatelliteManager.getSatelliteDataSupportMode(mSubId); + Log.d(TAG, "Data mode : " + dataMode); + } catch (IllegalStateException e) { + Log.d(TAG, "Failed to get data mode : " + e); + } + return dataMode <= SATELLITE_DATA_SUPPORT_ONLY_RESTRICTED; + } + private static void loge(String message) { Log.e(TAG, message); } diff --git a/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryControllerTest.java index 56d4b9fe183..8f2fb7225a1 100644 --- a/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryControllerTest.java +++ b/tests/unit/src/com/android/settings/network/telephony/satellite/SatelliteAppListCategoryControllerTest.java @@ -16,7 +16,11 @@ package com.android.settings.network.telephony.satellite; -import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static android.telephony.CarrierConfigManager.CARRIER_ROAMING_NTN_CONNECT_MANUAL; +import static android.telephony.CarrierConfigManager.KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT; +import static android.telephony.CarrierConfigManager.KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE_UNSEARCHABLE; import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; import static com.android.settings.network.telephony.satellite.SatelliteAppListCategoryController.MAXIMUM_OF_PREFERENCE_AMOUNT; @@ -31,6 +35,7 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Looper; +import android.os.PersistableBundle; import android.platform.test.annotations.EnableFlags; import androidx.preference.PreferenceCategory; @@ -39,7 +44,6 @@ import androidx.preference.PreferenceScreen; import androidx.test.core.app.ApplicationProvider; import com.android.internal.telephony.flags.Flags; -import com.android.settings.network.SatelliteRepository; import org.junit.Before; import org.junit.Rule; @@ -48,25 +52,23 @@ import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; -import java.util.Collections; import java.util.List; public class SatelliteAppListCategoryControllerTest { @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + private static final int TEST_SUB_ID = 0; private static final List PACKAGE_NAMES = List.of("com.android.settings", "com.android.apps.messaging", "com.android.dialer", "com.android.systemui"); private static final String KEY = "SatelliteAppListCategoryControllerTest"; @Mock private PackageManager mPackageManager; - @Mock - private SatelliteRepository mRepository; private Context mContext; private SatelliteAppListCategoryController mController; - + private PersistableBundle mPersistableBundle = new PersistableBundle(); @Before public void setUp() { @@ -75,16 +77,28 @@ public class SatelliteAppListCategoryControllerTest { } mContext = spy(ApplicationProvider.getApplicationContext()); when(mContext.getPackageManager()).thenReturn(mPackageManager); + mPersistableBundle.putInt(KEY_CARRIER_ROAMING_NTN_CONNECT_TYPE_INT, + CARRIER_ROAMING_NTN_CONNECT_MANUAL); + mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, false); } @Test @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) public void displayPreference_has4SatSupportedApps_showMaxPreference() throws Exception { - when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(PACKAGE_NAMES); when(mPackageManager.getApplicationInfoAsUser(any(), anyInt(), anyInt())).thenReturn( new ApplicationInfo()); - mController = new SatelliteAppListCategoryController(mContext, KEY); - mController.init(mRepository); + mController = new SatelliteAppListCategoryController(mContext, KEY) { + @Override + protected boolean isSatelliteEligible() { + return true; + } + + @Override + protected List getSatelliteDataOptimizedApps() { + return PACKAGE_NAMES; + } + }; + mController.init(TEST_SUB_ID, mPersistableBundle, true, true); PreferenceManager preferenceManager = new PreferenceManager(mContext); PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); PreferenceCategory category = new PreferenceCategory(mContext); @@ -100,25 +114,107 @@ public class SatelliteAppListCategoryControllerTest { @Test @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) public void getAvailabilityStatus_hasSatSupportedApps_returnAvailable() { - when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(PACKAGE_NAMES); - mController = new SatelliteAppListCategoryController(mContext, KEY); - mController.init(mRepository); + mController = new SatelliteAppListCategoryController(mContext, KEY) { + @Override + protected boolean isSatelliteEligible() { + return true; + } - int result = mController.getAvailabilityStatus(); + @Override + protected List getSatelliteDataOptimizedApps() { + return PACKAGE_NAMES; + } + }; + mController.init(TEST_SUB_ID, mPersistableBundle, true, true); - assertThat(result).isEqualTo(AVAILABLE); + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(AVAILABLE_UNSEARCHABLE); } @Test @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) public void getAvailabilityStatus_noSatSupportedApps_returnUnavailable() { - List packageNames = Collections.emptyList(); - when(mRepository.getSatelliteDataOptimizedApps()).thenReturn(packageNames); - mController = new SatelliteAppListCategoryController(mContext, KEY); - mController.init(mRepository); + mController = new SatelliteAppListCategoryController(mContext, KEY) { + @Override + protected boolean isSatelliteEligible() { + return true; + } - int result = mController.getAvailabilityStatus(); + @Override + protected List getSatelliteDataOptimizedApps() { + return List.of(); + } + }; + mController.init(TEST_SUB_ID, mPersistableBundle, true, true); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE); } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void getAvailabilityStatus_dataUnavailable_returnUnavailable() { + mController = new SatelliteAppListCategoryController(mContext, KEY) { + @Override + protected boolean isSatelliteEligible() { + return true; + } + + @Override + protected List getSatelliteDataOptimizedApps() { + return PACKAGE_NAMES; + } + }; + mController.init(TEST_SUB_ID, mPersistableBundle, true, false); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void getAvailabilityStatus_entitlementSupportedButAccountIneligible_returnUnavailable() { + mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true); + mController = new SatelliteAppListCategoryController(mContext, KEY) { + @Override + protected boolean isSatelliteEligible() { + return false; + } + + @Override + protected List getSatelliteDataOptimizedApps() { + return PACKAGE_NAMES; + } + }; + mController.init(TEST_SUB_ID, mPersistableBundle, true, true); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + public void getAvailabilityStatus_entitlementSupportedAndAccountEligible_returnAvailable() { + mPersistableBundle.putBoolean(KEY_SATELLITE_ENTITLEMENT_SUPPORTED_BOOL, true); + mController = new SatelliteAppListCategoryController(mContext, KEY) { + @Override + protected boolean isSatelliteEligible() { + return true; + } + + @Override + protected List getSatelliteDataOptimizedApps() { + return PACKAGE_NAMES; + } + }; + mController.init(TEST_SUB_ID, mPersistableBundle, true, true); + + int result = mController.getAvailabilityStatus(TEST_SUB_ID); + + assertThat(result).isEqualTo(AVAILABLE_UNSEARCHABLE); + } }