From bb80fe2df15365b733b76e998c43b56bb95c142b Mon Sep 17 00:00:00 2001 From: tom hsu Date: Wed, 12 Feb 2025 03:29:45 +0000 Subject: [PATCH] [Satellite Settings] Show device's app info on Satellite settings page. - Shows device apps' info up to 3 on Satellite settings' page. - Add a new page to show all device's app info with Satellite supported. Flag: com.android.internal.telephony.flags.satellite_25q4_apis Fix: b/395813844 Test: atest pass Change-Id: Ibd5e1c74b636639082ec9477f2b6796bcbc8340d --- res/values/strings.xml | 6 + res/xml/satellite_setting.xml | 17 +++ res/xml/satellite_settings_apps_list.xml | 21 +++ .../SatelliteAppListCategoryController.java | 98 ++++++++++++++ .../telephony/SatelliteAppListFragment.java | 126 ++++++++++++++++++ .../network/telephony/SatelliteSetting.java | 7 + ...atelliteAppListCategoryControllerTest.java | 124 +++++++++++++++++ .../SatelliteAppListFragmentTest.java | 92 +++++++++++++ 8 files changed, 491 insertions(+) create mode 100644 res/xml/satellite_settings_apps_list.xml create mode 100644 src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java create mode 100644 src/com/android/settings/network/telephony/SatelliteAppListFragment.java create mode 100644 tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java create mode 100644 tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java diff --git a/res/values/strings.xml b/res/values/strings.xml index 94d6384e732..694700c3aff 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -12607,6 +12607,12 @@ satellite messaging Use of data is included with your account + + Supported apps on your phone + + see all apps + + Supported apps on your phone Access Point Names diff --git a/res/xml/satellite_setting.xml b/res/xml/satellite_setting.xml index 60fe5bfb335..21743f3f9d5 100644 --- a/res/xml/satellite_setting.xml +++ b/res/xml/satellite_setting.xml @@ -62,6 +62,23 @@ android:icon="@drawable/ic_android_satellite_24px"/> + + + + + + + + + \ No newline at end of file diff --git a/src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java b/src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java new file mode 100644 index 00000000000..4afa7f245ff --- /dev/null +++ b/src/com/android/settings/network/telephony/SatelliteAppListCategoryController.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; +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.settingslib.Utils; + +import java.util.List; + +/** A controller to show some of apps info which supported on Satellite service. */ +public class SatelliteAppListCategoryController extends BasePreferenceController { + private static final String TAG = "SatelliteAppListCategoryController"; + @VisibleForTesting + static final int MAXIMUM_OF_PREFERENCE_AMOUNT = 3; + + private List mPackageNameList; + + public SatelliteAppListCategoryController( + @NonNull Context context, + @NonNull String preferenceKey) { + super(context, preferenceKey); + } + + /** Initialize the necessary applications' data*/ + public void init() { + SatelliteRepository satelliteRepository = new SatelliteRepository(mContext); + init(satelliteRepository); + } + + @VisibleForTesting + void init(@NonNull SatelliteRepository satelliteRepository) { + mPackageNameList = satelliteRepository.getSatelliteDataOptimizedApps(); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + PreferenceCategory preferenceCategory = screen.findPreference(getPreferenceKey()); + for (int i = 0; i < mPackageNameList.size() && i < MAXIMUM_OF_PREFERENCE_AMOUNT; i++) { + String packageName = mPackageNameList.get(i); + ApplicationInfo appInfo = getApplicationInfo(mContext, packageName); + if (appInfo != null) { + Drawable icon = Utils.getBadgedIcon(mContext, appInfo); + CharSequence name = appInfo.loadLabel(mContext.getPackageManager()); + Preference pref = new Preference(mContext); + pref.setIcon(icon); + pref.setTitle(name); + preferenceCategory.addPreference(pref); + } + } + } + + @Override + public int getAvailabilityStatus() { + if (!Flags.satellite25q4Apis()) { + return CONDITIONALLY_UNAVAILABLE; + } + return mPackageNameList.isEmpty() + ? CONDITIONALLY_UNAVAILABLE + : AVAILABLE; + } + + static ApplicationInfo getApplicationInfo(Context context, String packageName) { + try { + PackageManager pm = context.getPackageManager(); + return pm.getApplicationInfoAsUser(packageName, /* flags= */ 0, context.getUserId()); + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } +} diff --git a/src/com/android/settings/network/telephony/SatelliteAppListFragment.java b/src/com/android/settings/network/telephony/SatelliteAppListFragment.java new file mode 100644 index 00000000000..97f70bb2652 --- /dev/null +++ b/src/com/android/settings/network/telephony/SatelliteAppListFragment.java @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import static com.android.settings.network.telephony.SatelliteAppListCategoryController.getApplicationInfo; + +import android.app.settings.SettingsEnums; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.graphics.drawable.Drawable; +import android.os.UserManager; +import android.util.Log; + +import androidx.annotation.VisibleForTesting; +import androidx.preference.Preference; +import androidx.preference.PreferenceScreen; + +import com.android.settings.R; +import com.android.settings.core.BasePreferenceController; +import com.android.settings.dashboard.RestrictedDashboardFragment; +import com.android.settings.network.SatelliteRepository; +import com.android.settingslib.Utils; +import com.android.settingslib.core.AbstractPreferenceController; + +import org.checkerframework.checker.nullness.qual.NonNull; + +import java.util.List; +import java.util.stream.Collectors; + +/** Shows all applications which support satellite service. */ +public class SatelliteAppListFragment extends RestrictedDashboardFragment { + public SatelliteAppListFragment() { + super(UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS); + } + + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(SatelliteAppListPreferenceController.class).init(); + } + + @Override + protected List createPreferenceControllers(Context context) { + SatelliteAppListPreferenceController satelliteAppListPreferenceController = + new SatelliteAppListPreferenceController(getContext()); + return List.of(satelliteAppListPreferenceController); + } + + @Override + protected int getPreferenceScreenResId() { + return R.xml.satellite_settings_apps_list; + } + + @Override + protected String getLogTag() { + return "SatelliteAppListFragment"; + } + + @Override + public int getMetricsCategory() { + return SettingsEnums.SATELLITE_APPS_LIST; + } + + @VisibleForTesting + static class SatelliteAppListPreferenceController extends BasePreferenceController { + private static final String TAG = "SatelliteAppListPreferenceController"; + private static final String KEY = "key_satellite_app_list"; + + private List mApplicationInfoList = List.of(); + + SatelliteAppListPreferenceController(@NonNull Context context) { + super(context, KEY); + } + + public void init() { + SatelliteRepository satelliteRepository = new SatelliteRepository(mContext); + init(satelliteRepository); + } + + void init(@NonNull SatelliteRepository satelliteRepository) { + mApplicationInfoList = + satelliteRepository.getSatelliteDataOptimizedApps() + .stream() + .map(name -> getApplicationInfo(mContext, name)) + .collect(Collectors.toList()); + } + + @Override + public void displayPreference(PreferenceScreen screen) { + super.displayPreference(screen); + if (mApplicationInfoList.isEmpty()) { + return; + } + mApplicationInfoList.forEach(appInfo -> { + if (appInfo != null) { + Log.i(TAG, "Add preference to UI : " + appInfo.packageName); + Drawable icon = Utils.getBadgedIcon(mContext, appInfo); + CharSequence name = appInfo.loadLabel(mContext.getPackageManager()); + Preference pref = new Preference(mContext); + pref.setIcon(icon); + pref.setTitle(name); + screen.addPreference(pref); + } + }); + } + + @Override + public int getAvailabilityStatus() { + return AVAILABLE; + } + } +} diff --git a/src/com/android/settings/network/telephony/SatelliteSetting.java b/src/com/android/settings/network/telephony/SatelliteSetting.java index d4bd212d153..bc10abb212d 100644 --- a/src/com/android/settings/network/telephony/SatelliteSetting.java +++ b/src/com/android/settings/network/telephony/SatelliteSetting.java @@ -26,6 +26,7 @@ import static android.telephony.CarrierConfigManager.KEY_SATELLITE_INFORMATION_R import android.app.Activity; import android.app.settings.SettingsEnums; +import android.content.Context; import android.content.Intent; import android.graphics.Typeface; import android.graphics.drawable.Drawable; @@ -92,6 +93,12 @@ public class SatelliteSetting extends RestrictedDashboardFragment { return SettingsEnums.SATELLITE_SETTING; } + @Override + public void onAttach(Context context) { + super.onAttach(context); + use(SatelliteAppListCategoryController.class).init(); + } + @Override public void onCreate(@NonNull Bundle savedInstanceState) { super.onCreate(savedInstanceState); diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java new file mode 100644 index 00000000000..74797ae69d3 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListCategoryControllerTest.java @@ -0,0 +1,124 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.settings.core.BasePreferenceController.CONDITIONALLY_UNAVAILABLE; +import static com.android.settings.network.telephony.SatelliteAppListCategoryController.MAXIMUM_OF_PREFERENCE_AMOUNT; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Looper; +import android.platform.test.annotations.EnableFlags; + +import androidx.preference.PreferenceCategory; +import androidx.preference.PreferenceManager; +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; +import org.junit.Test; +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 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; + + + @Before + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @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); + PreferenceManager preferenceManager = new PreferenceManager(mContext); + PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); + PreferenceCategory category = new PreferenceCategory(mContext); + category.setKey(mController.getPreferenceKey()); + preferenceScreen.addPreference(category); + + mController.displayPreference(preferenceScreen); + + assertThat(category.getPreferenceCount() == MAXIMUM_OF_PREFERENCE_AMOUNT).isTrue(); + } + + + @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); + + int result = mController.getAvailabilityStatus(); + + assertThat(result).isEqualTo(AVAILABLE); + } + + @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); + + int result = mController.getAvailabilityStatus(); + + assertThat(result).isEqualTo(CONDITIONALLY_UNAVAILABLE); + } +} diff --git a/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java new file mode 100644 index 00000000000..ba91d179f99 --- /dev/null +++ b/tests/unit/src/com/android/settings/network/telephony/SatelliteAppListFragmentTest.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2025 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.settings.network.telephony; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.when; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Looper; +import android.platform.test.annotations.EnableFlags; + +import androidx.preference.PreferenceManager; +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; +import org.junit.Test; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +import java.util.List; + +public class SatelliteAppListFragmentTest { + @Rule + public final MockitoRule mMockitoRule = MockitoJUnit.rule(); + + 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 = "SatelliteAppListPreferenceController"; + + @Mock + private PackageManager mPackageManager; + @Mock + private SatelliteRepository mRepository; + + private Context mContext; + private SatelliteAppListFragment.SatelliteAppListPreferenceController mController; + + @Before + public void setUp() { + if (Looper.myLooper() == null) { + Looper.prepare(); + } + mContext = spy(ApplicationProvider.getApplicationContext()); + when(mContext.getPackageManager()).thenReturn(mPackageManager); + } + + @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 SatelliteAppListFragment.SatelliteAppListPreferenceController(mContext); + mController.init(mRepository); + PreferenceManager preferenceManager = new PreferenceManager(mContext); + PreferenceScreen preferenceScreen = preferenceManager.createPreferenceScreen(mContext); + + mController.displayPreference(preferenceScreen); + + assertThat(preferenceScreen.getPreferenceCount() == PACKAGE_NAMES.size()).isTrue(); + } +}