From 6f21b063f80c2210a2cb9b30a3b8c575de9cfe04 Mon Sep 17 00:00:00 2001 From: Will Leshner Date: Sat, 8 Feb 2025 13:47:25 -0800 Subject: [PATCH 01/15] Only show "hub mode" settings when the glanceable_hub_v2 flag is true. Bug: 395320922 Test: atest CommunalPreferenceControllerTest Flag: com.android.systemui.glanceable_hub_v2 Change-Id: I46e5931205a219806917fafcc1a7aac3b7046796 --- Android.bp | 1 + .../communal/CommunalPreferenceController.java | 14 +++++++------- tests/robotests/Android.bp | 1 + .../communal/CommunalPreferenceControllerTest.java | 12 ++++++------ 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/Android.bp b/Android.bp index c966eca2e92..ed094cfae72 100644 --- a/Android.bp +++ b/Android.bp @@ -115,6 +115,7 @@ android_library { "device_policy_aconfig_flags_lib", "keyboard_flags_lib", "settings_connectivity_flags", + "com_android_systemui_flags_lib", ], plugins: [ diff --git a/src/com/android/settings/communal/CommunalPreferenceController.java b/src/com/android/settings/communal/CommunalPreferenceController.java index f93746833ff..e44afab90a6 100644 --- a/src/com/android/settings/communal/CommunalPreferenceController.java +++ b/src/com/android/settings/communal/CommunalPreferenceController.java @@ -21,7 +21,6 @@ import android.content.Context; import com.android.settings.R; import com.android.settings.Utils; import com.android.settings.core.BasePreferenceController; -import com.android.settings.flags.Flags; /** * Controls the top-level Communal settings preference. @@ -40,14 +39,15 @@ public class CommunalPreferenceController extends BasePreferenceController { * Returns whether communal preferences are available. */ public static boolean isAvailable(Context context) { + if (!Utils.canCurrentUserDream(context)) { + return false; + } + if (context.getResources().getBoolean(R.bool.config_show_communal_settings)) { - return Utils.canCurrentUserDream(context); + return true; } - if (context.getResources().getBoolean(R.bool.config_show_communal_settings_mobile)) { - return Flags.enableHubModeSettingsOnMobile() && Utils.canCurrentUserDream(context); - } - - return false; + return com.android.systemui.Flags.glanceableHubV2() + && context.getResources().getBoolean(R.bool.config_show_communal_settings_mobile); } } diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp index 464d9708c0a..bb70a702b6d 100644 --- a/tests/robotests/Android.bp +++ b/tests/robotests/Android.bp @@ -77,6 +77,7 @@ android_robolectric_test { "platform-test-annotations", "testables", "android.app.flags-aconfig-java", + "com_android_systemui_flags_lib", ], libs: [ diff --git a/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java index b88b1aa661b..cc970eb6b1d 100644 --- a/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/communal/CommunalPreferenceControllerTest.java @@ -17,6 +17,7 @@ package com.android.settings.communal; import static com.android.settings.core.BasePreferenceController.AVAILABLE; +import static com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2; import static com.google.common.truth.Truth.assertThat; @@ -34,7 +35,6 @@ import android.platform.test.annotations.EnableFlags; import android.platform.test.flag.junit.SetFlagsRule; import com.android.settings.R; -import com.android.settings.flags.Flags; import com.android.settings.testutils.shadow.SettingsShadowResources; import com.android.settings.testutils.shadow.ShadowUserManager; @@ -87,7 +87,7 @@ public class CommunalPreferenceControllerTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) public void isAvailable_communalOnMobileEnabled_shouldBeTrueForPrimaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(true); @@ -96,7 +96,7 @@ public class CommunalPreferenceControllerTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) public void isAvailable_communalOnMobileEnabled_shouldBeFalseForSecondaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(true); @@ -105,7 +105,7 @@ public class CommunalPreferenceControllerTest { } @Test - @EnableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) + @EnableFlags(FLAG_GLANCEABLE_HUB_V2) public void isAvailable_communalOnMobileDisabled_shouldBeFalseForPrimaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(false); @@ -114,8 +114,8 @@ public class CommunalPreferenceControllerTest { } @Test - @DisableFlags(Flags.FLAG_ENABLE_HUB_MODE_SETTINGS_ON_MOBILE) - public void isAvailable_hubModeSettingsOnMobileFlagDisabled_shouldBeFalseForPrimaryUser() { + @DisableFlags(FLAG_GLANCEABLE_HUB_V2) + public void isAvailable_glanceableHubV2FlagDisabled_shouldBeFalseForPrimaryUser() { setCommunalEnabled(false); setCommunalOnMobileEnabled(true); mShadowUserManager.setUserForeground(true); From 4a55472cf3e539d86d0dba17cef553495fcf163d Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Tue, 11 Feb 2025 22:28:53 +0000 Subject: [PATCH 02/15] Check if device is online before starting 16kb test Test: atest -c Enable16KbTest Bug: 390535191 Change-Id: I32cc404f8e84fba0e90ecb5b801d98908242292d --- .../src/com/android/test/Enable16KbTest.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java b/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java index e4ebdefb1a5..8e8dba82d7d 100644 --- a/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java +++ b/tests/Enable16KbTests/src/com/android/test/Enable16KbTest.java @@ -51,7 +51,12 @@ public class Enable16KbTest extends BaseHostJUnit4Test { @Test @AppModeFull public void enable16KbToggle() throws Exception { - assertTrue(isPackageInstalled(APP_PACKAGE)); + // Wait for 2 mins device to be online + getDevice().waitForDeviceOnline(120000); + if (!isPackageInstalled(APP_PACKAGE)) { + //If test app has failed for some reason, retry installation + installTestApp(); + } // Check if developer option is enabled otherwise exit getDevice().enableAdbRoot(); From 30e63f61783d7c12495b41897c8446dd134c0ad0 Mon Sep 17 00:00:00 2001 From: Riley Jones Date: Fri, 7 Feb 2025 01:01:34 +0000 Subject: [PATCH 03/15] Left & Right buttons for Display size & text preview Test: manually open page and verify buttons work Bug: 386906497 Flag: EXEMPT small internal change dependant on xml Change-Id: I49ecf2940be897725a0864cf898655837a3e2399 --- res/drawable/keyboard_arrow_left.xml | 19 +++++++ res/drawable/keyboard_arrow_right.xml | 19 +++++++ .../accessibility_text_reading_preview.xml | 51 ++++++++++++++----- res/values/strings.xml | 5 ++ .../TextReadingPreviewPreference.java | 22 +++++++- 5 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 res/drawable/keyboard_arrow_left.xml create mode 100644 res/drawable/keyboard_arrow_right.xml diff --git a/res/drawable/keyboard_arrow_left.xml b/res/drawable/keyboard_arrow_left.xml new file mode 100644 index 00000000000..77a2bfb6046 --- /dev/null +++ b/res/drawable/keyboard_arrow_left.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/res/drawable/keyboard_arrow_right.xml b/res/drawable/keyboard_arrow_right.xml new file mode 100644 index 00000000000..5b0dd3d27dd --- /dev/null +++ b/res/drawable/keyboard_arrow_right.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/res/layout/accessibility_text_reading_preview.xml b/res/layout/accessibility_text_reading_preview.xml index 830d9e66778..9c3ce31db22 100644 --- a/res/layout/accessibility_text_reading_preview.xml +++ b/res/layout/accessibility_text_reading_preview.xml @@ -38,20 +38,45 @@ android:text="@string/screen_zoom_preview_title" style="@style/AccessibilityTextReadingPreviewTitle" /> - - - + android:orientation="vertical"> + + + + + + + diff --git a/res/values/strings.xml b/res/values/strings.xml index c49d6e3f767..828e5c3e5aa 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -78,6 +78,11 @@ Preview + + Previous preview + + Next preview + QR code diff --git a/src/com/android/settings/accessibility/TextReadingPreviewPreference.java b/src/com/android/settings/accessibility/TextReadingPreviewPreference.java index 9161171914a..717da70e49c 100644 --- a/src/com/android/settings/accessibility/TextReadingPreviewPreference.java +++ b/src/com/android/settings/accessibility/TextReadingPreviewPreference.java @@ -22,6 +22,7 @@ import android.os.Parcelable; import android.util.AttributeSet; import android.view.View; import android.widget.FrameLayout; +import android.widget.ImageButton; import android.widget.LinearLayout; import androidx.preference.Preference; @@ -99,6 +100,23 @@ public class TextReadingPreviewPreference extends Preference { (DotsPageIndicator) holder.findViewById(R.id.page_indicator); updateAdapterIfNeeded(viewPager, pageIndicator, mPreviewAdapter); updatePagerAndIndicator(viewPager, pageIndicator); + viewPager.setClipToOutline(true); + + int layoutDirection = + getContext().getResources().getConfiguration().getLayoutDirection(); + int previousId = (layoutDirection == View.LAYOUT_DIRECTION_RTL) + ? R.id.preview_right_button : R.id.preview_left_button; + int nextId = (layoutDirection == View.LAYOUT_DIRECTION_RTL) + ? R.id.preview_left_button : R.id.preview_right_button; + final ImageButton previousButton = previewLayout.findViewById(previousId); + final ImageButton nextButton = previewLayout.findViewById(nextId); + + previousButton.setOnClickListener((view) -> setCurrentItem(getCurrentItem() - 1)); + previousButton.setContentDescription(getContext().getString( + R.string.preview_pager_previous_button)); + nextButton.setOnClickListener((view) -> setCurrentItem(getCurrentItem() + 1)); + previousButton.setContentDescription(getContext().getString( + R.string.preview_pager_next_button)); } @Override @@ -158,7 +176,9 @@ public class TextReadingPreviewPreference extends Preference { Preconditions.checkNotNull(mPreviewAdapter, "Preview adapter is null, you should init the preview adapter first"); - if (currentItem != mCurrentItem) { + if (currentItem < 0 || currentItem >= mPreviewAdapter.getCount()) { + return; + } else if (currentItem != mCurrentItem) { mCurrentItem = currentItem; notifyChanged(); } From 6179d4fdf3c70f1af6267339c5cff1807a706041 Mon Sep 17 00:00:00 2001 From: Shraddha Basantwani Date: Mon, 2 Dec 2024 09:36:05 +0000 Subject: [PATCH 04/15] RESTRICT AUTOMERGE Add biometric authentication for package modification Add an extra step of Lock Screen for disabling, force-stopping or uninstalling updates for protected packages Bug: 352504490, 344865740 Test: atest AppButtonsPreferenceControllerTest Flag: EXEMPT High Security Bug (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:32e388ad3199de3c062bb2e2db5d3239f934d0eb) Merged-In: I0c494e307b02229d751de118abcc89e4e61a6861 Change-Id: I0c494e307b02229d751de118abcc89e4e61a6861 --- src/com/android/settings/Utils.java | 16 +++++ .../AppButtonsPreferenceController.java | 64 +++++++++++++------ .../appinfo/AppInfoDashboardFragment.java | 3 +- .../AppButtonsPreferenceControllerTest.java | 3 + .../testutils/shadow/ShadowUtils.java | 11 ++++ 5 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/com/android/settings/Utils.java b/src/com/android/settings/Utils.java index f996444b482..ad747ff92e1 100644 --- a/src/com/android/settings/Utils.java +++ b/src/com/android/settings/Utils.java @@ -114,6 +114,7 @@ import com.android.settings.password.ChooseLockSettingsHelper; import com.android.settingslib.widget.ActionBarShadowController; import com.android.settingslib.widget.AdaptiveIcon; +import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Locale; @@ -1229,4 +1230,19 @@ public final class Utils extends com.android.settingslib.Utils { public static int getHomepageIconColorHighlight(Context context) { return context.getColor(R.color.accent_select_primary_text); } + + /** + * Returns {@code true} if the supplied package is a protected package. Otherwise, returns + * {@code false}. + * + * @param context the context + * @param packageName the package name + */ + public static boolean isProtectedPackage( + @NonNull Context context, @NonNull String packageName) { + final List protectedPackageNames = Arrays.asList(context.getResources() + .getStringArray(com.android.internal.R.array + .config_biometric_protected_package_names)); + return protectedPackageNames != null && protectedPackageNames.contains(packageName); + } } diff --git a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java index 1b270d63b4d..69f23fe5648 100644 --- a/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java +++ b/src/com/android/settings/applications/appinfo/AppButtonsPreferenceController.java @@ -52,6 +52,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.Utils; import com.android.settings.applications.ApplicationFeatureProvider; +import com.android.settings.applications.appinfo.AppInfoDashboardFragment; import com.android.settings.applications.specialaccess.deviceadmin.DeviceAdminAdd; import com.android.settings.core.BasePreferenceController; import com.android.settings.core.InstrumentedPreferenceFragment; @@ -249,13 +250,21 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp } else { showDialogInner(ButtonActionDialogFragment.DialogType.DISABLE); } + } else if (mAppEntry.info.enabled) { + requireAuthAndExecute(() -> { + mMetricsFeatureProvider.action( + mActivity, + SettingsEnums.ACTION_SETTINGS_DISABLE_APP, + getPackageNameForMetric()); + AsyncTask.execute(new DisableChangerRunnable(mPm, + mAppEntry.info.packageName, + PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)); + }); } else { mMetricsFeatureProvider.action( mActivity, - mAppEntry.info.enabled - ? SettingsEnums.ACTION_SETTINGS_DISABLE_APP - : SettingsEnums.ACTION_SETTINGS_ENABLE_APP, - getPackageNameForMetric()); + SettingsEnums.ACTION_SETTINGS_ENABLE_APP, + getPackageNameForMetric()); AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT)); } @@ -303,13 +312,28 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp } } + /** + * Runs the given action with restricted lock authentication if it is a protected package. + * + * @param action The action to run. + */ + private void requireAuthAndExecute(Runnable action) { + if (Utils.isProtectedPackage(mContext, mAppEntry.info.packageName)) { + AppInfoDashboardFragment.showLockScreen(mContext, () -> action.run()); + } else { + action.run(); + } + } + public void handleDialogClick(int id) { switch (id) { case ButtonActionDialogFragment.DialogType.DISABLE: - mMetricsFeatureProvider.action(mActivity, - SettingsEnums.ACTION_SETTINGS_DISABLE_APP); - AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)); + requireAuthAndExecute(() -> { + mMetricsFeatureProvider.action(mActivity, + SettingsEnums.ACTION_SETTINGS_DISABLE_APP); + AsyncTask.execute(new DisableChangerRunnable(mPm, mAppEntry.info.packageName, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER)); + }); break; case ButtonActionDialogFragment.DialogType.SPECIAL_DISABLE: mMetricsFeatureProvider.action(mActivity, @@ -317,7 +341,9 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp uninstallPkg(mAppEntry.info.packageName, false, true); break; case ButtonActionDialogFragment.DialogType.FORCE_STOP: - forceStopPackage(mAppEntry.info.packageName); + requireAuthAndExecute(() -> { + forceStopPackage(mAppEntry.info.packageName); + }); break; } } @@ -547,16 +573,18 @@ public class AppButtonsPreferenceController extends BasePreferenceController imp @VisibleForTesting void uninstallPkg(String packageName, boolean allUsers, boolean andDisable) { - stopListeningToPackageRemove(); - // Create new intent to launch Uninstaller activity - Uri packageUri = Uri.parse("package:" + packageName); - Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); - uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); + requireAuthAndExecute(() -> { + stopListeningToPackageRemove(); + // Create new intent to launch Uninstaller activity + Uri packageUri = Uri.parse("package:" + packageName); + Intent uninstallIntent = new Intent(Intent.ACTION_UNINSTALL_PACKAGE, packageUri); + uninstallIntent.putExtra(Intent.EXTRA_UNINSTALL_ALL_USERS, allUsers); - mMetricsFeatureProvider.action( - mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP); - mFragment.startActivityForResult(uninstallIntent, mRequestUninstall); - mDisableAfterUninstall = andDisable; + mMetricsFeatureProvider.action( + mActivity, SettingsEnums.ACTION_SETTINGS_UNINSTALL_APP); + mFragment.startActivityForResult(uninstallIntent, mRequestUninstall); + mDisableAfterUninstall = andDisable; + }); } @VisibleForTesting diff --git a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java index 54455d4f110..8f79b910055 100755 --- a/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java +++ b/src/com/android/settings/applications/appinfo/AppInfoDashboardFragment.java @@ -430,7 +430,8 @@ public class AppInfoDashboardFragment extends DashboardFragment } } - private static void showLockScreen(Context context, Runnable successRunnable) { + /** Shows the lock screen if the keyguard is secured. */ + public static void showLockScreen(Context context, Runnable successRunnable) { final KeyguardManager keyguardManager = context.getSystemService( KeyguardManager.class); diff --git a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java index 9a65dc8829c..39201f317dc 100644 --- a/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/applications/appinfo/AppButtonsPreferenceControllerTest.java @@ -56,6 +56,7 @@ import com.android.settings.R; import com.android.settings.SettingsActivity; import com.android.settings.core.InstrumentedPreferenceFragment; import com.android.settings.testutils.FakeFeatureFactory; +import com.android.settings.testutils.shadow.ShadowUtils; import com.android.settingslib.applications.AppUtils; import com.android.settingslib.applications.ApplicationsState; import com.android.settingslib.applications.instantapps.InstantAppDataProvider; @@ -81,6 +82,7 @@ import org.robolectric.util.ReflectionHelpers; import java.util.Set; +@Config(shadows = {ShadowUtils.class}) @RunWith(RobolectricTestRunner.class) public class AppButtonsPreferenceControllerTest { @@ -166,6 +168,7 @@ public class AppButtonsPreferenceControllerTest { @After public void tearDown() { ShadowAppUtils.reset(); + ShadowUtils.reset(); } @Test diff --git a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java index 40cb25bfb83..8bd959f0715 100644 --- a/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java +++ b/tests/robotests/src/com/android/settings/testutils/shadow/ShadowUtils.java @@ -48,6 +48,7 @@ public class ShadowUtils { private static ArraySet sResultLinks = new ArraySet<>(); private static boolean sIsBatteryPresent; private static boolean sIsMultipleBiometricsSupported; + private static boolean sIsProtectedPackage; @Implementation protected static int enforceSameOwner(Context context, int userId) { @@ -71,6 +72,7 @@ public class ShadowUtils { sResultLinks = new ArraySet<>(); sIsBatteryPresent = true; sIsMultipleBiometricsSupported = false; + sIsProtectedPackage = false; } public static void setIsDemoUser(boolean isDemoUser) { @@ -177,4 +179,13 @@ public class ShadowUtils { public static void setIsMultipleBiometricsSupported(boolean isMultipleBiometricsSupported) { sIsMultipleBiometricsSupported = isMultipleBiometricsSupported; } + + @Implementation + protected static boolean isProtectedPackage(Context context, String packageName) { + return sIsProtectedPackage; + } + + public static void setIsProtectedPackage(boolean isProtectedPackage) { + sIsProtectedPackage = isProtectedPackage; + } } From 538fb34027858cf30b5d2052d9316ddb6b3cb06c Mon Sep 17 00:00:00 2001 From: songferngwang Date: Thu, 13 Feb 2025 12:04:07 +0000 Subject: [PATCH 05/15] Check if ECBMode when activate SIM card If in ECBMode, start ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS to show a dialog instead. This align with the deactivate sim case Bug: 393298086 Test: atest SubscriptionActivationRepositoryTest Test: adb shell cmd phone emergency-callback-mode Flag: EXEMPT bugfix Change-Id: Id40d087b7d2d3ca99504ec75bac1c5e29c67258d --- .../SubscriptionActivationRepository.kt | 2 +- .../SubscriptionActivationRepositoryTest.kt | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt b/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt index 185af0c3d09..a7f6a0b5dcb 100644 --- a/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt +++ b/src/com/android/settings/network/telephony/SubscriptionActivationRepository.kt @@ -52,7 +52,7 @@ class SubscriptionActivationRepository( Log.i(TAG, "Unable to toggle subscription due to unusable subscription ID.") return } - if (!active && isEmergencyCallbackMode(subId)) { + if (isEmergencyCallbackMode(subId)) { val intent = Intent(ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS).apply { setPackage(Utils.PHONE_PACKAGE_NAME) } diff --git a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt index 427ab7b1685..01015be7730 100644 --- a/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt +++ b/tests/spa_unit/src/com/android/settings/network/telephony/SubscriptionActivationRepositoryTest.kt @@ -17,12 +17,15 @@ package com.android.settings.network.telephony import android.content.Context +import android.content.Intent +import android.os.UserHandle import android.telephony.SubscriptionManager import android.telephony.TelephonyManager import android.telephony.TelephonyManager.ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS import androidx.test.core.app.ApplicationProvider import androidx.test.ext.junit.runners.AndroidJUnit4 import com.android.settings.network.SatelliteRepository +import com.android.settings.network.SimOnboardingActivity import com.android.settingslib.spa.testutils.firstWithTimeoutOrNull import com.google.common.truth.Truth.assertThat import kotlinx.coroutines.flow.flowOf @@ -33,6 +36,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argThat import org.mockito.kotlin.doNothing import org.mockito.kotlin.doReturn +import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.spy @@ -107,6 +111,17 @@ class SubscriptionActivationRepositoryTest { verify(context, never()).startActivity(any()) } + @Test + fun setActive_turnOnAndIsEmergencyCallbackMode() = runBlocking { + mockTelephonyManager.stub { + on { emergencyCallbackMode } doReturn true + } + + repository.setActive(subId = SUB_ID, active = true) + + verify(context).startActivity(argThat { action == ACTION_SHOW_NOTICE_ECM_BLOCK_OTHERS }) + } + @Test fun setActive_turnOffAndIsEmergencyCallbackMode() = runBlocking { mockTelephonyManager.stub { @@ -131,6 +146,19 @@ class SubscriptionActivationRepositoryTest { }) } + @Test + fun setActive_turnOnAndNotEmergencyCallbackMode() = runBlocking { + mockTelephonyManager.stub { + on { emergencyCallbackMode } doReturn false + } + + repository.setActive(subId = SUB_ID, active = true) + + verify(context).startActivityAsUser(argThat { + component?.className == SimOnboardingActivity::class.qualifiedName + }, eq(UserHandle.CURRENT)) + } + private companion object { const val SUB_ID = 1 } From bf50c0baef56fe50775b0c885c50f03ee9662123 Mon Sep 17 00:00:00 2001 From: Pierre Barbier de Reuille Date: Thu, 23 Jan 2025 20:38:30 +0000 Subject: [PATCH 06/15] Create new sections for developer options To group desktop experience and window management options Test: Build and check Bug: 390625230 Flag: EXEMPT (refactor) Change-Id: Ie076501da68045fa5f1098423a42d32f16a02838 --- res/xml/development_settings.xml | 68 +++++++++++-------- .../DevelopmentSettingsDashboardFragment.java | 6 ++ ...DesktopExperiencePreferenceController.java | 5 +- .../DesktopModePreferenceController.java | 5 +- ...eSecondaryDisplayPreferenceController.java | 5 +- .../FreeformWindowsPreferenceController.java | 5 +- .../development/desktopexperience/OWNERS | 3 + ...izableMultiWindowPreferenceController.java | 2 +- .../settings/development/window/OWNERS | 2 + ...ResizableActivityPreferenceController.java | 6 +- ...topExperiencePreferenceControllerTest.java | 4 +- .../DesktopModePreferenceControllerTest.java | 4 +- ...ondaryDisplayPreferenceControllerTest.java | 14 ++-- ...eeformWindowsPreferenceControllerTest.java | 8 ++- .../development/desktopexperience/OWNERS | 2 + ...leMultiWindowPreferenceControllerTest.java | 6 +- .../settings/development/window/OWNERS | 3 + ...zableActivityPreferenceControllerTest.java | 4 +- 18 files changed, 98 insertions(+), 54 deletions(-) rename src/com/android/settings/development/{ => desktopexperience}/DesktopExperiencePreferenceController.java (94%) rename src/com/android/settings/development/{ => desktopexperience}/DesktopModePreferenceController.java (93%) rename src/com/android/settings/development/{ => desktopexperience}/DesktopModeSecondaryDisplayPreferenceController.java (93%) rename src/com/android/settings/development/{ => desktopexperience}/FreeformWindowsPreferenceController.java (92%) create mode 100644 src/com/android/settings/development/desktopexperience/OWNERS rename src/com/android/settings/development/{ => window}/NonResizableMultiWindowPreferenceController.java (98%) create mode 100644 src/com/android/settings/development/window/OWNERS rename src/com/android/settings/development/{ => window}/ResizableActivityPreferenceController.java (94%) rename tests/robotests/src/com/android/settings/development/{ => desktopexperience}/DesktopExperiencePreferenceControllerTest.java (97%) rename tests/robotests/src/com/android/settings/development/{ => desktopexperience}/DesktopModePreferenceControllerTest.java (97%) rename tests/robotests/src/com/android/settings/development/{ => desktopexperience}/DesktopModeSecondaryDisplayPreferenceControllerTest.java (91%) rename tests/robotests/src/com/android/settings/development/{ => desktopexperience}/FreeformWindowsPreferenceControllerTest.java (93%) create mode 100644 tests/robotests/src/com/android/settings/development/desktopexperience/OWNERS rename tests/robotests/src/com/android/settings/development/{ => window}/NonResizableMultiWindowPreferenceControllerTest.java (93%) create mode 100644 tests/robotests/src/com/android/settings/development/window/OWNERS rename tests/robotests/src/com/android/settings/development/{ => window}/ResizableActivityPreferenceControllerTest.java (98%) diff --git a/res/xml/development_settings.xml b/res/xml/development_settings.xml index 2f9a9b98585..518e2d16e73 100644 --- a/res/xml/development_settings.xml +++ b/res/xml/development_settings.xml @@ -745,32 +745,6 @@ android:title="@string/force_allow_on_external" android:summary="@string/force_allow_on_external_summary" /> - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + android:order="1200"> + android:order="1300"> + android:order="1400"> @@ -857,7 +865,7 @@ + android:order="1500"> Date: Thu, 13 Feb 2025 07:37:33 -0800 Subject: [PATCH 07/15] Fix private volume UI items incorrectly displayed for public volume The loading of private volume UI items is async, these private volume UI items should not be displayed if user has switched to public volume. Limit private volume UI items only visible for private volume. Bug: 396043608 (cherry picked from https://android-review.googlesource.com/q/commit:1bfb959c1f14226231145a24624731650278af3a) Merged-In: I5ea5cfb5d73f74cae33d780ed1f7f04fba870e32 Change-Id: I5ea5cfb5d73f74cae33d780ed1f7f04fba870e32 Flag: EXEMPT bug fix --- .../deviceinfo/storage/StorageItemPreferenceController.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java index c0caff7a494..cb8e6fc03b0 100644 --- a/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java +++ b/src/com/android/settings/deviceinfo/storage/StorageItemPreferenceController.java @@ -475,7 +475,10 @@ public class StorageItemPreferenceController extends AbstractPreferenceControlle updatePrivateStorageCategoryPreferencesOrder(); mIsPreferenceOrderedBySize = true; } - setPrivateStorageCategoryPreferencesVisibility(true); + + if (isValidPrivateVolume()) { + setPrivateStorageCategoryPreferencesVisibility(true); + } } private StorageCacheHelper.StorageCache getSizeInfo( From 80b28cb6cc47198ee9689655a7319e21c34f11ce Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Wed, 12 Feb 2025 16:02:10 +0800 Subject: [PATCH 08/15] [Audiosharing] Avoid concurrent issue when adding preference Bug: 394685943 Flag: EXEMPT bug fix Test: atest Change-Id: I0d50dee9a36fd719236b52ab633a18818c3e10bb --- ...dioSharingDeviceVolumeGroupController.java | 98 ++++++++++--------- ...haringDeviceVolumeGroupControllerTest.java | 4 + 2 files changed, 55 insertions(+), 47 deletions(-) diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java index be0ee0b8b44..7b670a80fba 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupController.java @@ -51,10 +51,9 @@ import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.bluetooth.LocalBluetoothProfileManager; import com.android.settingslib.bluetooth.VolumeControlProfile; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArraySet; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.concurrent.atomic.AtomicBoolean; @@ -73,8 +72,9 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre private final Executor mExecutor; private final ContentObserver mSettingsObserver; @Nullable private PreferenceGroup mPreferenceGroup; - private List mVolumePreferences = new ArrayList<>(); - private Map mValueMap = new HashMap(); + private CopyOnWriteArraySet mVolumePreferences = + new CopyOnWriteArraySet<>(); + private ConcurrentHashMap mValueMap = new ConcurrentHashMap<>(); private AtomicBoolean mCallbacksRegistered = new AtomicBoolean(false); @VisibleForTesting @@ -104,8 +104,8 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre + finalVolume + " for " + device.getAnonymizedAddress()); - mContext.getMainExecutor() - .execute(() -> preference.setProgress(finalVolume)); + AudioSharingUtils.postOnMainThread(mContext, + () -> preference.setProgress(finalVolume)); break; } } @@ -196,7 +196,9 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre public void onChange(boolean selfChange) { Log.d(TAG, "onChange, fallback device group id has been changed"); for (AudioSharingDeviceVolumePreference preference : mVolumePreferences) { - preference.setOrder(getPreferenceOrderForDevice(preference.getCachedDevice())); + int order = getPreferenceOrderForDevice(preference.getCachedDevice()); + Log.d(TAG, "onChange: set order to " + order + " for " + preference); + AudioSharingUtils.postOnMainThread(mContext, () -> preference.setOrder(order)); } } } @@ -240,52 +242,54 @@ public class AudioSharingDeviceVolumeGroupController extends AudioSharingBasePre @Override public void onDeviceAdded(Preference preference) { - if (mPreferenceGroup != null) { - if (mPreferenceGroup.getPreferenceCount() == 0) { - mPreferenceGroup.setVisible(true); + if (!(preference instanceof AudioSharingDeviceVolumePreference)) { + Log.d(TAG, "Skip onDeviceAdded, invalid preference type"); + return; + } + var volumePref = (AudioSharingDeviceVolumePreference) preference; + mVolumePreferences.add(volumePref); + AudioSharingUtils.postOnMainThread(mContext, () -> { + if (mPreferenceGroup != null) { + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(true); + } + mPreferenceGroup.addPreference(volumePref); } - mPreferenceGroup.addPreference(preference); - } - if (preference instanceof AudioSharingDeviceVolumePreference) { - var volumePref = (AudioSharingDeviceVolumePreference) preference; - CachedBluetoothDevice cachedDevice = volumePref.getCachedDevice(); - volumePref.setOrder(getPreferenceOrderForDevice(cachedDevice)); - mVolumePreferences.add(volumePref); - if (volumePref.getProgress() > 0) return; - int volume = mValueMap.getOrDefault(BluetoothUtils.getGroupId(cachedDevice), -1); - // If the volume is invalid, try to get the volume from AudioManager.STREAM_MUSIC - int finalVolume = getAudioVolumeIfNeeded(volume); - Log.d( - TAG, - "onDeviceAdded: set volume to " - + finalVolume - + " for " - + cachedDevice.getDevice().getAnonymizedAddress()); - AudioSharingUtils.postOnMainThread(mContext, () -> volumePref.setProgress(finalVolume)); - } + }); + CachedBluetoothDevice cachedDevice = volumePref.getCachedDevice(); + String address = cachedDevice.getDevice() == null ? "null" + : cachedDevice.getDevice().getAnonymizedAddress(); + int order = getPreferenceOrderForDevice(cachedDevice); + Log.d(TAG, "onDeviceAdded: set order to " + order + " for " + address); + AudioSharingUtils.postOnMainThread(mContext, () -> volumePref.setOrder(order)); + int volume = mValueMap.getOrDefault(BluetoothUtils.getGroupId(cachedDevice), -1); + // If the volume is invalid, try to get the volume from AudioManager.STREAM_MUSIC + int finalVolume = getAudioVolumeIfNeeded(volume); + Log.d(TAG, "onDeviceAdded: set volume to " + finalVolume + " for " + address); + AudioSharingUtils.postOnMainThread(mContext, () -> volumePref.setProgress(finalVolume)); } @Override public void onDeviceRemoved(Preference preference) { - if (mPreferenceGroup != null) { - mPreferenceGroup.removePreference(preference); - if (mPreferenceGroup.getPreferenceCount() == 0) { - mPreferenceGroup.setVisible(false); - } + if (!(preference instanceof AudioSharingDeviceVolumePreference)) { + Log.d(TAG, "Skip onDeviceRemoved, invalid preference type"); + return; } - if (preference instanceof AudioSharingDeviceVolumePreference) { - var volumePref = (AudioSharingDeviceVolumePreference) preference; - if (mVolumePreferences.contains(volumePref)) { - mVolumePreferences.remove(volumePref); - } - CachedBluetoothDevice device = volumePref.getCachedDevice(); - Log.d( - TAG, - "onDeviceRemoved: " - + (device == null - ? "null" - : device.getDevice().getAnonymizedAddress())); + var volumePref = (AudioSharingDeviceVolumePreference) preference; + if (mVolumePreferences.contains(volumePref)) { + mVolumePreferences.remove(volumePref); } + String address = volumePref.getCachedDevice().getDevice() == null ? "null" + : volumePref.getCachedDevice().getDevice().getAnonymizedAddress(); + Log.d(TAG, "onDeviceRemoved: " + address); + AudioSharingUtils.postOnMainThread(mContext, () -> { + if (mPreferenceGroup != null) { + mPreferenceGroup.removePreference(volumePref); + if (mPreferenceGroup.getPreferenceCount() == 0) { + mPreferenceGroup.setVisible(false); + } + } + }); } @Override diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java index bac8b30ff16..a739bb3b4fb 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeGroupControllerTest.java @@ -309,6 +309,8 @@ public class AudioSharingDeviceVolumeGroupControllerTest { when(mPreference1.getProgress()).thenReturn(TEST_VOLUME_VALUE); mController.setPreferenceGroup(mPreferenceGroup); mController.onDeviceAdded(mPreference1); + shadowOf(Looper.getMainLooper()).idle(); + verify(mPreferenceGroup).setVisible(true); assertThat(mPreferenceGroup.isVisible()).isTrue(); } @@ -365,6 +367,8 @@ public class AudioSharingDeviceVolumeGroupControllerTest { mPreferenceGroup.addPreference(mPreference1); mController.setPreferenceGroup(mPreferenceGroup); mController.onDeviceRemoved(mPreference1); + shadowOf(Looper.getMainLooper()).idle(); + verify(mPreferenceGroup).setVisible(false); assertThat(mPreferenceGroup.isVisible()).isFalse(); } From 8aa9b9a189aa16e125ace889e6b5d8e4a910537c Mon Sep 17 00:00:00 2001 From: Vincent Wang Date: Fri, 14 Feb 2025 03:57:19 +0000 Subject: [PATCH 09/15] Avoid triggering BGE scaning multiple times BUG: b/391255128 Flag: EXEMPT bug fixing Test: Manual test and check BGE scanning behavior Change-Id: I7d8649360a09f8eb48b990f5ae33ee6cd1723445 --- .../biometrics/fingerprint/FingerprintSettings.java | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java index 6773fdcf1ce..31ebeb7c705 100644 --- a/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java +++ b/src/com/android/settings/biometrics/fingerprint/FingerprintSettings.java @@ -1067,8 +1067,11 @@ public class FingerprintSettings extends SubSettings { mRemovalSidecar.setListener(mRemovalListener); } - mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() - .getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, null); + if (!mLaunchedConfirm && !mIsEnrolling) { + mCalibrator = FeatureFactory.getFeatureFactory().getFingerprintFeatureProvider() + .getUdfpsEnrollCalibrator(getActivity().getApplicationContext(), null, + null); + } } private void updatePreferences() { @@ -1517,6 +1520,11 @@ public class FingerprintSettings extends SubSettings { intent.putExtra(ChooseLockSettingsHelper.EXTRA_KEY_CHALLENGE_TOKEN, mToken); intent.putExtra(BiometricEnrollBase.EXTRA_KEY_CHALLENGE, mChallenge); } + + if (mCalibrator != null) { + intent.putExtras(mCalibrator.getExtrasForNextIntent()); + } + startActivityForResult(intent, AUTO_ADD_FIRST_FINGERPRINT_REQUEST); } From fb21686468625bf9046ee3165c1ceceeb113b5e9 Mon Sep 17 00:00:00 2001 From: Yiyi Shen Date: Fri, 14 Feb 2025 14:48:38 +0800 Subject: [PATCH 10/15] Show device in Media devices section if has LEA member connected Test: atest Bug: 396009828 Flag: EXEMPT simple fix Change-Id: Icc6bd1c4fa7cf3c43eec1c4c950fbf778975f803 --- .../AvailableMediaBluetoothDeviceUpdater.java | 3 +- .../ConnectedBluetoothDeviceUpdater.java | 7 +- .../AudioSharingBluetoothDeviceUpdater.java | 3 +- ...udioSharingDeviceVolumeControlUpdater.java | 3 +- ...ilableMediaBluetoothDeviceUpdaterTest.java | 41 +++++++ .../ConnectedBluetoothDeviceUpdaterTest.java | 30 ++++++ ...udioSharingBluetoothDeviceUpdaterTest.java | 102 +++++++++++++++++- ...SharingDeviceVolumeControlUpdaterTest.java | 59 +++++++++- 8 files changed, 234 insertions(+), 14 deletions(-) diff --git a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java index d97e93be094..6b0215de6d7 100644 --- a/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdater.java @@ -88,7 +88,8 @@ public class AvailableMediaBluetoothDeviceUpdater extends BluetoothDeviceUpdater // If device is LE Audio, it is compatible with HFP and A2DP. // It would show in Available Devices group if the audio sharing flag is disabled or // the device is not in the audio sharing session. - if (cachedDevice.isConnectedLeAudioDevice()) { + if (cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) { if (BluetoothUtils.isAudioSharingUIAvailable(mContext) && BluetoothUtils.hasConnectedBroadcastSource( cachedDevice, mLocalBtManager)) { diff --git a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java index 03473cf1e1d..9df2301c0f7 100644 --- a/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java +++ b/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdater.java @@ -85,7 +85,12 @@ public class ConnectedBluetoothDeviceUpdater extends BluetoothDeviceUpdater { // If device is Hearing Aid or LE Audio, it is compatible with HFP and A2DP. // It would not show in Connected Devices group. if (cachedDevice.isConnectedAshaHearingAidDevice() - || cachedDevice.isConnectedLeAudioDevice()) { + || cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) { + if (DBG) { + Log.d(TAG, "isFilterMatched() device : " + cachedDevice.getName() + + ", isFilterMatched : false, ha or lea device"); + } return false; } // According to the current audio profile type, diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java index e57e53e524a..9b51197a969 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdater.java @@ -65,7 +65,8 @@ public class AudioSharingBluetoothDeviceUpdater extends BluetoothDeviceUpdater // If device is LE audio device and has a broadcast source, // it would show in audio sharing devices group. if (BluetoothUtils.isAudioSharingUIAvailable(mContext) - && cachedDevice.isConnectedLeAudioDevice() + && (cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) && BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, mLocalBtManager)) { isFilterMatched = true; } diff --git a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java index 548d17cc9ce..7f12ec84b3b 100644 --- a/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java +++ b/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdater.java @@ -62,7 +62,8 @@ public class AudioSharingDeviceVolumeControlUpdater extends BluetoothDeviceUpdat if (isDeviceConnected(cachedDevice) && isDeviceInCachedDevicesList(cachedDevice)) { // If device is LE audio device and in a sharing session on current sharing device, // it would show in volume control group. - if (cachedDevice.isConnectedLeAudioDevice() + if ((cachedDevice.isConnectedLeAudioDevice() + || cachedDevice.hasConnectedLeAudioMemberDevice()) && BluetoothUtils.isBroadcasting(mBtManager) && BluetoothUtils.hasConnectedBroadcastSource(cachedDevice, mBtManager)) { isFilterMatched = true; diff --git a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java index 2251c3bff5a..87d7aed8f19 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/AvailableMediaBluetoothDeviceUpdaterTest.java @@ -282,6 +282,28 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_notInCallFlagOff_addPref() { + mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))) + .thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of(mBroadcastReceiveState)); + List bisSyncState = new ArrayList<>(); + bisSyncState.add(1L); + when(mBroadcastReceiveState.getBisSyncState()).thenReturn(bisSyncState); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_leaConnected_notInCallNotInSharing_addPref() { mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); @@ -299,6 +321,25 @@ public class AvailableMediaBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); } + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_notInCallNotInSharing_addPref() { + mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))) + .thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + when(mAssistant.getAllSources(any())).thenReturn(ImmutableList.of()); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).addPreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_leaConnected_inCallSharingFlagOff_addPref() { mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); diff --git a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java index ad155ffd743..2a16c3ad21f 100644 --- a/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/bluetooth/ConnectedBluetoothDeviceUpdaterTest.java @@ -272,6 +272,20 @@ public class ConnectedBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } + @Test + public void onProfileConnectionStateChanged_hasLeaMemberConnected_inCall_removesPreference() { + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_IN_CALL); + when(mBluetoothDeviceUpdater + .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_leAudioDeviceConnected_notInCall_removesPreference() { @@ -285,6 +299,22 @@ public class ConnectedBluetoothDeviceUpdaterTest { verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); } + + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_notInCall_removesPreference() { + setUpDeviceUpdaterWithAudioMode(AudioManager.MODE_NORMAL); + when(mBluetoothDeviceUpdater + .isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + + mBluetoothDeviceUpdater.onProfileConnectionStateChanged(mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, BluetoothProfile.LE_AUDIO); + + verify(mBluetoothDeviceUpdater).removePreference(mCachedBluetoothDevice); + } + @Test public void onProfileConnectionStateChanged_deviceIsNotInList_inCall_invokesRemovesPreference() { diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java index 12e03d4cd63..84fd820323f 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingBluetoothDeviceUpdaterTest.java @@ -153,6 +153,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceConnected_flagOff_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -172,6 +177,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaConnected_flagOff_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_LE_AUDIO_SHARING); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -191,6 +201,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaConnected_noSource_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of()); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -210,6 +225,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaConnected_noSource_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of()); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -229,6 +249,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_deviceIsNotInList_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mCachedDevices.clear(); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); @@ -249,6 +274,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_deviceIsNotInList_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mCachedDevices.clear(); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); @@ -269,6 +299,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnected_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -288,6 +323,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnected_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -307,6 +347,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnecting_removesPref() { setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); doReturn(false).when(mCachedBluetoothDevice).isConnectedLeAudioDevice(); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -325,6 +370,11 @@ public class AudioSharingBluetoothDeviceUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDisconnecting_hysteresisMode_removesPref() { setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); doReturn(false).when(mCachedBluetoothDevice).isConnectedLeAudioDevice(); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -344,6 +394,29 @@ public class AudioSharingBluetoothDeviceUpdaterTest { public void onProfileConnectionStateChanged_leaConnected_hasSource_addsPref() { ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); setupPreferenceMapWithDevice(false); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); + assertThat(((BluetoothDevicePreference) captor.getValue()).getBluetoothDevice()) + .isEqualTo(mCachedBluetoothDevice); + } + + @Test + public void onProfileConnectionStateChanged_hasLeaMemberConnected_hasSource_addsPref() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(false); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); @@ -355,6 +428,30 @@ public class AudioSharingBluetoothDeviceUpdaterTest { public void onProfileConnectionStateChanged_leaConnected_hasSource_hysteresisMode_addsPref() { ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); setupPreferenceMapWithDevice(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); + assertThat(((BluetoothDevicePreference) captor.getValue()).getBluetoothDevice()) + .isEqualTo(mCachedBluetoothDevice); + } + + @Test + public void + onProfileConnectionStateChanged_hasLeaMemberConnected_hasSource_hysteresis_addsPref() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(true); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); assertThat(captor.getValue() instanceof BluetoothDevicePreference).isTrue(); @@ -397,10 +494,5 @@ public class AudioSharingBluetoothDeviceUpdaterTest { when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of(mState)); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); doReturn(true).when(mCachedBluetoothDevice).isConnectedLeAudioDevice(); - mDeviceUpdater.onProfileConnectionStateChanged( - mCachedBluetoothDevice, - BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.LE_AUDIO); - shadowOf(Looper.getMainLooper()).idle(); } } diff --git a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java index 95e51e99d51..2bdd0da243f 100644 --- a/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java +++ b/tests/robotests/src/com/android/settings/connecteddevice/audiosharing/AudioSharingDeviceVolumeControlUpdaterTest.java @@ -127,6 +127,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceConnected_noSharing_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mBroadcast.isEnabled(null)).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -146,6 +151,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceConnected_noSource_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of()); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -165,6 +175,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_deviceIsNotInList_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); mCachedDevices.clear(); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(mCachedDevices); @@ -185,6 +200,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceDisconnected_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -204,6 +224,11 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void onProfileConnectionStateChanged_leaDeviceDisconnecting_removesPref() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); @@ -224,6 +249,29 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { public void onProfileConnectionStateChanged_leaDeviceConnected_hasSource_addsPreference() { ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + + verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); + assertThat(captor.getValue() instanceof AudioSharingDeviceVolumePreference).isTrue(); + assertThat(((AudioSharingDeviceVolumePreference) captor.getValue()).getCachedDevice()) + .isEqualTo(mCachedBluetoothDevice); + } + + @Test + public void onProfileConnectionStateChanged_hasLeaMemberConnected_hasSource_addsPreference() { + ArgumentCaptor captor = ArgumentCaptor.forClass(Preference.class); + setupPreferenceMapWithDevice(); + when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(false); + when(mCachedBluetoothDevice.hasConnectedLeAudioMemberDevice()).thenReturn(true); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); verify(mDevicePreferenceCallback).onDeviceAdded(captor.capture()); assertThat(captor.getValue() instanceof AudioSharingDeviceVolumePreference).isTrue(); @@ -262,6 +310,12 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { @Test public void refreshPreference_doNothing() { setupPreferenceMapWithDevice(); + mDeviceUpdater.onProfileConnectionStateChanged( + mCachedBluetoothDevice, + BluetoothProfile.STATE_CONNECTED, + BluetoothProfile.LE_AUDIO); + shadowOf(Looper.getMainLooper()).idle(); + verify(mDevicePreferenceCallback).onDeviceAdded(any(Preference.class)); when(mCachedDeviceManager.getCachedDevicesCopy()).thenReturn(ImmutableList.of()); mDeviceUpdater.refreshPreference(); @@ -276,10 +330,5 @@ public class AudioSharingDeviceVolumeControlUpdaterTest { when(mAssistant.getAllSources(mBluetoothDevice)).thenReturn(ImmutableList.of(mState)); when(mDeviceUpdater.isDeviceConnected(any(CachedBluetoothDevice.class))).thenReturn(true); when(mCachedBluetoothDevice.isConnectedLeAudioDevice()).thenReturn(true); - mDeviceUpdater.onProfileConnectionStateChanged( - mCachedBluetoothDevice, - BluetoothProfile.STATE_CONNECTED, - BluetoothProfile.LE_AUDIO); - shadowOf(Looper.getMainLooper()).idle(); } } From 63242bc3ff82a0922f8a9671a2d206a0f13ce19c Mon Sep 17 00:00:00 2001 From: tom hsu Date: Tue, 11 Feb 2025 11:14:23 +0000 Subject: [PATCH 11/15] [Satellite Settings] Add a new API to SatelliteRepository Flag: com.android.internal.telephony.flags.satellite_25q4_apis Bug: b/395813844 Test: atest pass Change-Id: Ife9e370dbcb3694adfd0bfbcc2ec2a742fbc4434 --- .../settings/network/SatelliteRepository.kt | 25 ++++++++++++- .../network/SatelliteRepositoryTest.kt | 37 ++++++++++++++++++- 2 files changed, 59 insertions(+), 3 deletions(-) diff --git a/src/com/android/settings/network/SatelliteRepository.kt b/src/com/android/settings/network/SatelliteRepository.kt index c70484a7e7a..994f8ec96d4 100644 --- a/src/com/android/settings/network/SatelliteRepository.kt +++ b/src/com/android/settings/network/SatelliteRepository.kt @@ -23,6 +23,7 @@ import android.telephony.satellite.SatelliteModemStateCallback import android.util.Log import androidx.annotation.VisibleForTesting import androidx.concurrent.futures.CallbackToFutureAdapter +import com.android.internal.telephony.flags.Flags import com.google.common.util.concurrent.Futures.immediateFuture import com.google.common.util.concurrent.ListenableFuture import java.util.concurrent.Executor @@ -40,7 +41,7 @@ import kotlinx.coroutines.flow.flowOn /** * A repository class for interacting with the SatelliteManager API. */ -class SatelliteRepository( +open class SatelliteRepository( private val context: Context, ) { @@ -196,6 +197,28 @@ class SatelliteRepository( } } + /** + * @return A list with application package names which support Satellite service. + * 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) { + Log.d(TAG, "SatelliteManager is null") + return emptyList() + } + try { + return satelliteManager.getSatelliteDataOptimizedApps(); + } catch (e: IllegalStateException) { + Log.w(TAG, "IllegalStateException $e") + } + return emptyList() + } + companion object { private const val TAG: String = "SatelliteRepository" diff --git a/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt b/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt index 619d290f0c4..0f845df90e7 100644 --- a/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt +++ b/tests/robotests/src/com/android/settings/network/SatelliteRepositoryTest.kt @@ -18,10 +18,12 @@ package com.android.settings.network import android.content.Context import android.os.OutcomeReceiver +import android.platform.test.annotations.EnableFlags import android.telephony.satellite.SatelliteManager import android.telephony.satellite.SatelliteManager.SatelliteException import android.telephony.satellite.SatelliteModemStateCallback import androidx.test.core.app.ApplicationProvider +import com.android.internal.telephony.flags.Flags import com.google.common.truth.Truth.assertThat import com.google.common.util.concurrent.ListenableFuture import kotlinx.coroutines.flow.first @@ -38,10 +40,10 @@ import org.mockito.Mockito.* import org.mockito.Spy import org.mockito.junit.MockitoJUnit import org.mockito.junit.MockitoRule +import org.mockito.kotlin.whenever import org.robolectric.RobolectricTestRunner import java.util.concurrent.Executor - @RunWith(RobolectricTestRunner::class) class SatelliteRepositoryTest { @@ -267,4 +269,35 @@ class SatelliteRepositoryTest { assertThat(flow.first()).isFalse() } -} \ No newline at end of file + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + fun getSatelliteDataOptimizedApps_returnPackageNameList() = runBlocking { + whenever( + mockSatelliteManager.getSatelliteDataOptimizedApps() + ).thenReturn( + listOf( + "com.android.settings", + "com.android.apps.messaging", + "com.android.dialer", + "com.android.systemui" + ) + ) + + val result = repository.getSatelliteDataOptimizedApps() + + assertThat(result.size == 4).isTrue() + } + + @Test + @EnableFlags(Flags.FLAG_SATELLITE_25Q4_APIS) + fun getSatelliteDataOptimizedApps_noTelephony_returnEmptyList() = runBlocking { + whenever( + mockSatelliteManager.getSatelliteDataOptimizedApps() + ).thenThrow(IllegalStateException("Telephony is null")) + + val result = repository.getSatelliteDataOptimizedApps() + + assertThat(result.isEmpty()).isTrue() + } +} From bb80fe2df15365b733b76e998c43b56bb95c142b Mon Sep 17 00:00:00 2001 From: tom hsu Date: Wed, 12 Feb 2025 03:29:45 +0000 Subject: [PATCH 12/15] [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(); + } +} From 8485f0e8f275b9dfb36e53774d2724a85f614c45 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Thu, 13 Feb 2025 09:17:11 +0000 Subject: [PATCH 13/15] Styling seekbar color for Accessibility Bug: 317163103 Test: visual test Flag: EXEMPT style update Change-Id: I5fc685d8bf5f7e67f6f1876db2f8885e5f2151c7 --- res/layout/preference_volume_slider.xml | 5 +++-- res/values-night/colors.xml | 4 ++++ res/values/colors.xml | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/res/layout/preference_volume_slider.xml b/res/layout/preference_volume_slider.xml index 1d9a8484920..02f0f7007fe 100644 --- a/res/layout/preference_volume_slider.xml +++ b/res/layout/preference_volume_slider.xml @@ -66,8 +66,9 @@ android:layout_gravity="center_vertical" android:paddingStart="0dp" android:paddingEnd="12dp" - android:progressBackgroundTint="@color/settingslib_materialColorOutline" - android:progressTint="@color/settingslib_materialColorPrimaryFixed" + android:thumbTint="@color/seekbar_thumb_tint_color" + android:progressTint="@color/seekbar_progress_tint_color" + android:progressBackgroundTint="@color/seekbar_progress_background_tint_color" android:layout_width="match_parent" android:layout_height="48dp"/> diff --git a/res/values-night/colors.xml b/res/values-night/colors.xml index 79949ceb85b..4edb6f43688 100644 --- a/res/values-night/colors.xml +++ b/res/values-night/colors.xml @@ -82,5 +82,9 @@ @color/settingslib_color_charcoal @android:color/system_secondary_dark + + + @android:color/system_accent1_100 + @android:color/system_accent1_100 diff --git a/res/values/colors.xml b/res/values/colors.xml index 73efeb232fa..c9e01e5a612 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -222,4 +222,9 @@ @color/settingslib_color_grey100 @android:color/system_secondary_light + + + @android:color/system_accent1_800 + @android:color/system_accent1_800 + @android:color/system_neutral2_50 From 5a310e9c8f2584d63cbe0a9621436461f85c4a72 Mon Sep 17 00:00:00 2001 From: Mill Chen Date: Thu, 13 Feb 2025 07:47:32 +0000 Subject: [PATCH 14/15] Add hint to EditText for Talkback Set the title as the hint of EditText to fix the missing accessibility label. Fix: 386758099 Test: atest DeviceNamePreferenceControllerTest Flag: EXEMPT bug fix Change-Id: Icde6796aa3faa3e0ad79611ba2dd0b18b13590a7 --- .../android/settings/widget/ValidatedEditTextPreference.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/com/android/settings/widget/ValidatedEditTextPreference.java b/src/com/android/settings/widget/ValidatedEditTextPreference.java index cc344ac67f1..c85e81ef381 100644 --- a/src/com/android/settings/widget/ValidatedEditTextPreference.java +++ b/src/com/android/settings/widget/ValidatedEditTextPreference.java @@ -67,6 +67,9 @@ public class ValidatedEditTextPreference extends CustomEditTextPreferenceCompat protected void onBindDialogView(View view) { super.onBindDialogView(view); final EditText editText = view.findViewById(android.R.id.edit); + if (editText != null) { + editText.setHint(getDialogTitle()); + } if (editText != null && !TextUtils.isEmpty(editText.getText())) { editText.setSelection(editText.getText().length()); } From e3dc23f7674e3d28c1eb726c34ef6a02859d1e31 Mon Sep 17 00:00:00 2001 From: Matthew DeVore Date: Thu, 13 Feb 2025 21:17:44 +0000 Subject: [PATCH 15/15] Show topology pane detached from mirror toggle Remove the extra blue border from the topology pane and give the toggle below it its own rounded corners. Flag: com.android.settings.flags.display_topology_pane_in_display_list Test: screenshots Test: verify display blocks are still clipped to the topology holder view Bug: b/396116157 Change-Id: I3c0f826db24e5c599c6b51f71d099976fb04cbf0 --- res/layout/display_topology_preference.xml | 8 +++++++- res/values/dimens.xml | 1 + .../connecteddevice/display/DisplayTopologyPreference.kt | 7 +++++-- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/res/layout/display_topology_preference.xml b/res/layout/display_topology_preference.xml index 9f2805d0e83..add84b6b235 100644 --- a/res/layout/display_topology_preference.xml +++ b/res/layout/display_topology_preference.xml @@ -14,13 +14,19 @@ limitations under the License. --> + 24dp + 24dp 5dp 2dp 10dp diff --git a/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt b/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt index 42e633f62e7..7894a7e6c0d 100644 --- a/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt +++ b/src/com/android/settings/connecteddevice/display/DisplayTopologyPreference.kt @@ -16,9 +16,10 @@ package com.android.settings.connecteddevice.display -import android.app.WallpaperManager import com.android.settings.R +import com.android.settingslib.widget.GroupSectionDividerMixin +import android.app.WallpaperManager import android.content.Context import android.graphics.Bitmap import android.graphics.PointF @@ -45,7 +46,7 @@ import kotlin.math.abs * when there is one or more extended display attached. */ class DisplayTopologyPreference(context : Context) - : Preference(context), ViewTreeObserver.OnGlobalLayoutListener { + : Preference(context), ViewTreeObserver.OnGlobalLayoutListener, GroupSectionDividerMixin { @VisibleForTesting lateinit var mPaneContent : FrameLayout @VisibleForTesting lateinit var mPaneHolder : FrameLayout @VisibleForTesting lateinit var mTopologyHint : TextView @@ -82,6 +83,8 @@ class DisplayTopologyPreference(context : Context) isPersistent = false + isCopyingEnabled = false + injector = Injector(context) }