From 43420f16af008027da391b4bd94ad06c26740348 Mon Sep 17 00:00:00 2001 From: Riley Jones Date: Thu, 8 Feb 2024 22:52:51 +0000 Subject: [PATCH 1/3] DragToEdit Dynaimc Title Bug: 323388734 Test: atest EditShortcutsPreferenceFragmentTest Flag: aconfig edit_shortcut_dynamic_title true Change-Id: I74785054e4f846db04d13a54bd6695e4690f5b8b --- res/values/accessibility_shortcut_keys.xml | 1 + res/values/strings.xml | 4 + res/xml/accessibility_edit_shortcuts.xml | 106 +++++++++--------- .../EditShortcutsPreferenceFragment.java | 90 ++++++++++++++- .../EditShortcutsPreferenceFragmentTest.java | 72 ++++++++++++ 5 files changed, 221 insertions(+), 52 deletions(-) diff --git a/res/values/accessibility_shortcut_keys.xml b/res/values/accessibility_shortcut_keys.xml index 0d409a8304a..4992a544eb0 100644 --- a/res/values/accessibility_shortcut_keys.xml +++ b/res/values/accessibility_shortcut_keys.xml @@ -16,6 +16,7 @@ --> + shortcut_description shortcut_volume_keys_pref shortcut_gesture_pref shortcut_nav_button_pref diff --git a/res/values/strings.xml b/res/values/strings.xml index 45305ece4f6..533c9b54447 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -5096,6 +5096,10 @@ Hold volume keys Triple tap screen + + Edit accessibility shortcuts + + Chose your shortcut for %1$s Continue diff --git a/res/xml/accessibility_edit_shortcuts.xml b/res/xml/accessibility_edit_shortcuts.xml index 06cbeddc6ab..8be0ee50857 100644 --- a/res/xml/accessibility_edit_shortcuts.xml +++ b/res/xml/accessibility_edit_shortcuts.xml @@ -18,62 +18,66 @@ - + - + - + - + - + - + - + + + + \ No newline at end of file diff --git a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java index a3cbb57ba5b..5a3b13ab640 100644 --- a/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java +++ b/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragment.java @@ -27,16 +27,21 @@ import static com.android.internal.accessibility.AccessibilityShortcutController import static com.android.internal.accessibility.AccessibilityShortcutController.MAGNIFICATION_CONTROLLER_NAME; import static com.android.settings.SettingsActivity.EXTRA_SHOW_FRAGMENT_TITLE; +import android.app.Activity; import android.app.settings.SettingsEnums; import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.content.res.Resources; import android.database.ContentObserver; +import android.icu.text.ListFormatter; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.Settings; import android.text.TextUtils; +import android.util.ArrayMap; +import android.util.Pair; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -48,9 +53,12 @@ import androidx.annotation.VisibleForTesting; import androidx.preference.Preference; import androidx.recyclerview.widget.RecyclerView; +import com.android.internal.accessibility.dialog.AccessibilityTarget; +import com.android.internal.accessibility.dialog.AccessibilityTargetHelper; import com.android.settings.R; import com.android.settings.SetupWizardUtils; import com.android.settings.accessibility.AccessibilitySetupWizardUtils; +import com.android.settings.accessibility.Flags; import com.android.settings.accessibility.PreferredShortcuts; import com.android.settings.core.SubSettingLauncher; import com.android.settings.dashboard.DashboardFragment; @@ -60,7 +68,10 @@ import com.google.android.setupcompat.template.FooterBarMixin; import com.google.android.setupcompat.util.WizardManagerHelper; import com.google.android.setupdesign.GlifPreferenceLayout; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.Set; /** @@ -171,6 +182,36 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { registerSettingsObserver(); } + @Override + public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { + super.onCreatePreferences(savedInstanceState, rootKey); + + Activity activity = getActivity(); + + if (!activity.getIntent().getAction().equals( + Settings.ACTION_ACCESSIBILITY_SHORTCUT_SETTINGS) + || !Flags.editShortcutsInFullScreen()) { + return; + } + + // TODO(b/325664350): Implement shortcut type for "all shortcuts" + List accessibilityTargets = + AccessibilityTargetHelper.getInstalledTargets( + activity.getBaseContext(), AccessibilityManager.ACCESSIBILITY_SHORTCUT_KEY); + + Pair titles = getTitlesFromAccessibilityTargetList( + mShortcutTargets, + accessibilityTargets, + activity.getResources() + ); + + activity.setTitle(titles.first); + + String categoryKey = activity.getResources().getString( + R.string.accessibility_shortcut_description_pref); + findPreference(categoryKey).setTitle(titles.second); + } + @NonNull @Override public RecyclerView onCreateRecyclerView( @@ -275,7 +316,6 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { } mShortcutTargets = Set.of(targets); - // TODO(318748373): use 'targets' to populate title when no title is given } @Override @@ -356,4 +396,52 @@ public class EditShortcutsPreferenceFragment extends DashboardFragment { // A11y Nav Button refreshPreferenceController(NavButtonShortcutOptionController.class); } + + /** + * Generates a title & subtitle pair describing the features whose shortcuts are being edited. + * + * @param shortcutTargets string list of component names corresponding to + * the relevant shortcut targets. + * @param accessibilityTargets list of accessibility targets + * to try and find corresponding labels in. + * @return pair of strings to be used as page title and subtitle. + * If there is only one shortcut label, It is displayed in the title and the subtitle is null. + * Otherwise, the title is a generic prompt and the subtitle lists all shortcut labels. + */ + @VisibleForTesting + static Pair getTitlesFromAccessibilityTargetList( + Set shortcutTargets, + List accessibilityTargets, + Resources resources) { + ArrayList featureLabels = new ArrayList<>(); + + Map accessibilityTargetLabels = new ArrayMap<>(); + accessibilityTargets.forEach((target) -> accessibilityTargetLabels.put( + target.getId(), target.getLabel())); + + for (String target: shortcutTargets) { + if (accessibilityTargetLabels.containsKey(target)) { + featureLabels.add(accessibilityTargetLabels.get(target)); + } else { + throw new IllegalStateException("Shortcut target does not have a label: " + target); + } + } + + if (featureLabels.size() == 1) { + return new Pair<>( + resources.getString( + R.string.accessibility_shortcut_title, featureLabels.get(0)), + null + ); + } else if (featureLabels.size() == 0) { + throw new IllegalStateException("Found no labels for any shortcut targets."); + } else { + return new Pair<>( + resources.getString(R.string.accessibility_shortcut_edit_screen_title), + resources.getString( + R.string.accessibility_shortcut_edit_screen_prompt, + ListFormatter.getInstance().format(featureLabels)) + ); + } + } } diff --git a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java index 13f0b24236e..b2ddb6c3cd5 100644 --- a/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/accessibility/shortcuts/EditShortcutsPreferenceFragmentTest.java @@ -28,6 +28,9 @@ import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_P import static com.google.android.setupcompat.util.WizardManagerHelper.EXTRA_IS_SETUP_FLOW; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import static org.robolectric.Shadows.shadowOf; import android.content.ComponentName; @@ -35,7 +38,9 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.platform.test.flag.junit.SetFlagsRule; import android.provider.Settings; +import android.util.Pair; import android.view.accessibility.AccessibilityManager; import androidx.fragment.app.FragmentActivity; @@ -46,6 +51,7 @@ import androidx.preference.TwoStatePreference; import androidx.test.core.app.ApplicationProvider; import com.android.internal.accessibility.common.ShortcutConstants; +import com.android.internal.accessibility.dialog.AccessibilityTarget; import com.android.internal.accessibility.util.ShortcutUtils; import com.android.settings.R; import com.android.settings.SettingsActivity; @@ -60,6 +66,7 @@ import com.google.android.setupcompat.util.WizardManagerHelper; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.Robolectric; @@ -89,6 +96,9 @@ public class EditShortcutsPreferenceFragmentTest { private static final String TARGET = MAGNIFICATION_CONTROLLER_NAME; private static final Set TARGETS = Set.of(TARGET); + @Rule + public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(); + private final Context mContext = ApplicationProvider.getApplicationContext(); private FragmentActivity mActivity; private FragmentScenario mFragmentScenario; @@ -414,6 +424,60 @@ public class EditShortcutsPreferenceFragmentTest { } + @Test + public void findTitles_withSingleTarget_hasNullSubtitle() { + final String fake_label = "FAKE"; + List accessibilityTargets = List.of( + generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label)); + + Pair titles = EditShortcutsPreferenceFragment + .getTitlesFromAccessibilityTargetList( + Set.of(TARGET_FAKE_COMPONENT.flattenToString()), + accessibilityTargets, mActivity.getResources() + ); + + assertThat(titles.first).isNotNull(); + assertThat(titles.first).contains(fake_label); + assertThat(titles.second).isNull(); + } + + @Test + public void findTitles_withMoreTargets_hasSubtitle() { + final String fake_label = "FAKE"; + final String magnification_label = "MAGNIFICATION"; + List accessibilityTargets = List.of( + generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label), + generateAccessibilityTargetMock(MAGNIFICATION_COMPONENT_NAME, magnification_label)); + + Pair titles = EditShortcutsPreferenceFragment + .getTitlesFromAccessibilityTargetList( + Set.of(TARGET_FAKE_COMPONENT.flattenToString(), + MAGNIFICATION_COMPONENT_NAME.flattenToString()), + accessibilityTargets, mActivity.getResources() + ); + + assertThat(titles.first).isNotNull(); + assertThat(titles.second).isNotNull(); + assertThat(titles.second).contains(fake_label); + assertThat(titles.second).contains(magnification_label); + } + + @Test + public void findTitles_targetMissing_labelNotInTitles() { + final String fake_label = "FAKE"; + List accessibilityTargets = List.of( + generateAccessibilityTargetMock(TARGET_FAKE_COMPONENT, fake_label)); + + assertThrows(IllegalStateException.class, + () -> EditShortcutsPreferenceFragment + .getTitlesFromAccessibilityTargetList( + Set.of(MAGNIFICATION_COMPONENT_NAME.flattenToString()), + accessibilityTargets, mActivity.getResources() + )); + } + + + private void assertLaunchSubSettingWithCurrentTargetComponents( String componentName, boolean isInSuw) { Intent intent = shadowOf(mActivity.getApplication()).getNextStartedActivity(); @@ -480,4 +544,12 @@ public class EditShortcutsPreferenceFragmentTest { intent.putExtra(EXTRA_IS_DEFERRED_SETUP, isInSuw); return intent; } + + private AccessibilityTarget generateAccessibilityTargetMock( + ComponentName componentName, String label) { + AccessibilityTarget target = mock(AccessibilityTarget.class); + when(target.getComponentName()).thenReturn(componentName); + when(target.getLabel()).thenReturn(label); + return target; + } } From 96343a9effe959782fefc2cf11be88f6d4a9ae65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Wilczy=C5=84ski?= Date: Fri, 16 Feb 2024 19:21:33 +0000 Subject: [PATCH 2/3] Refresh rate preference controllers aware of multiple displays Set mPeakRefreshRate in the preference controllers to the highest refresh rate among all the modes of all the displays. It'll then be used to determine two things: - if the setting is available - the summary of the setting This should only be done if the back up smooth display feature flag is enabled. If it's disabled, mPeakRefreshRate is passed to DisplayModeDirector and used for the votes. If the highest refresh rate of one display is 120 and that of the other is 130, we shouldn't set the vote to 130 for both displays. With the flag enabled, DisplayModeDirector figures out the highest refresh rate for each display. Bug: 310238382 Test: atest PeakRefreshRatePreferenceControllerTest Test: atest ForcePeakRefreshRatePreferenceControllerTest Test: atest RefreshRateSettingsUtilsTest Change-Id: I369927ba22df70958178505d8fc7c5747aaa8fdd --- ...cePeakRefreshRatePreferenceController.java | 5 +- .../PeakRefreshRatePreferenceController.java | 5 +- tests/robotests/Android.bp | 2 + ...akRefreshRatePreferenceControllerTest.java | 58 +++++++++++++++++-- ...akRefreshRatePreferenceControllerTest.java | 57 +++++++++++++++++- 5 files changed, 118 insertions(+), 9 deletions(-) diff --git a/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java b/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java index abeb94991fb..455f74f837a 100644 --- a/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java +++ b/src/com/android/settings/development/ForcePeakRefreshRatePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.development; import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; +import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays; import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.content.Context; @@ -47,7 +48,9 @@ public class ForcePeakRefreshRatePreferenceController extends DeveloperOptionsPr public ForcePeakRefreshRatePreferenceController(Context context) { super(context); - mPeakRefreshRate = findHighestRefreshRateForDefaultDisplay(context); + mPeakRefreshRate = Flags.backUpSmoothDisplayAndForcePeakRefreshRate() + ? findHighestRefreshRateAmongAllDisplays(context) + : findHighestRefreshRateForDefaultDisplay(context); Log.d(TAG, "DEFAULT_REFRESH_RATE : " + DEFAULT_REFRESH_RATE + " mPeakRefreshRate : " + mPeakRefreshRate); } diff --git a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java index 17d763ac42a..261eaf1316e 100644 --- a/src/com/android/settings/display/PeakRefreshRatePreferenceController.java +++ b/src/com/android/settings/display/PeakRefreshRatePreferenceController.java @@ -17,6 +17,7 @@ package com.android.settings.display; import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; +import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateAmongAllDisplays; import static com.android.internal.display.RefreshRateSettingsUtils.findHighestRefreshRateForDefaultDisplay; import android.content.Context; @@ -66,7 +67,9 @@ public class PeakRefreshRatePreferenceController extends TogglePreferenceControl updateState(mPreference); } }; - mPeakRefreshRate = Math.round(findHighestRefreshRateForDefaultDisplay(context)); + mPeakRefreshRate = Math.round(Flags.backUpSmoothDisplayAndForcePeakRefreshRate() + ? findHighestRefreshRateAmongAllDisplays(context) + : findHighestRefreshRateForDefaultDisplay(context)); Log.d( TAG, "DEFAULT_REFRESH_RATE : " diff --git a/tests/robotests/Android.bp b/tests/robotests/Android.bp index 56482904be8..1c6794d027f 100644 --- a/tests/robotests/Android.bp +++ b/tests/robotests/Android.bp @@ -71,10 +71,12 @@ android_robolectric_test { "Settings-testutils2", "notification_flags_lib", "com_android_server_accessibility_flags_lib", + "testables", ], libs: [ "ims-common", + "android.test.mock", ], java_resource_dirs: [ diff --git a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java index 314120aa126..c7c76b19809 100644 --- a/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/development/ForcePeakRefreshRatePreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.development; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; import static com.android.settings.development.ForcePeakRefreshRatePreferenceController.NO_CONFIG; @@ -24,15 +26,18 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import android.content.Context; +import android.hardware.display.DisplayManager; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import android.testing.TestableContext; +import android.view.Display; import androidx.preference.PreferenceScreen; import androidx.preference.SwitchPreference; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.display.feature.flags.Flags; @@ -43,7 +48,6 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.robolectric.RobolectricTestRunner; -import org.robolectric.RuntimeEnvironment; import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) @@ -53,17 +57,51 @@ public class ForcePeakRefreshRatePreferenceControllerTest { private SwitchPreference mPreference; @Mock private PreferenceScreen mScreen; + @Mock + private DisplayManager mDisplayManagerMock; + @Mock + private Display mDisplayMock; + @Mock + private Display mDisplayMock2; - private Context mContext; private ForcePeakRefreshRatePreferenceController mController; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock); + + Display.Mode[] modes = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 120), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 90) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + when(mDisplayMock.getSupportedModes()).thenReturn(modes); + + Display.Mode[] modes2 = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 70), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 130), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 80) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2); + when(mDisplayMock2.getSupportedModes()).thenReturn(modes2); + + when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 }); + mController = new ForcePeakRefreshRatePreferenceController(mContext); when(mScreen.findPreference(mController.getPreferenceKey())).thenReturn(mPreference); when(mPreference.getKey()).thenReturn(mController.getPreferenceKey()); @@ -153,4 +191,16 @@ public class ForcePeakRefreshRatePreferenceControllerTest { assertThat(mPreference.isChecked()).isFalse(); assertThat(mPreference.isEnabled()).isFalse(); } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() { + assertThat(mController.mPeakRefreshRate).isEqualTo(120); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() { + assertThat(mController.mPeakRefreshRate).isEqualTo(130); + } } diff --git a/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java b/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java index cb0963b19ba..f8e91bd09e9 100644 --- a/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/PeakRefreshRatePreferenceControllerTest.java @@ -16,6 +16,8 @@ package com.android.settings.display; +import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED; + import static com.android.internal.display.RefreshRateSettingsUtils.DEFAULT_REFRESH_RATE; import static com.android.settings.core.BasePreferenceController.AVAILABLE; import static com.android.settings.core.BasePreferenceController.UNSUPPORTED_ON_DEVICE; @@ -24,14 +26,17 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; -import android.content.Context; +import android.hardware.display.DisplayManager; import android.platform.test.annotations.RequiresFlagsDisabled; import android.platform.test.annotations.RequiresFlagsEnabled; import android.platform.test.flag.junit.CheckFlagsRule; import android.platform.test.flag.junit.DeviceFlagsValueProvider; import android.provider.Settings; +import android.testing.TestableContext; +import android.view.Display; import androidx.preference.SwitchPreference; +import androidx.test.platform.app.InstrumentationRegistry; import com.android.server.display.feature.flags.Flags; @@ -48,21 +53,55 @@ import org.robolectric.annotation.Config; @RunWith(RobolectricTestRunner.class) public class PeakRefreshRatePreferenceControllerTest { - private Context mContext; private PeakRefreshRatePreferenceController mController; private SwitchPreference mPreference; @Mock private PeakRefreshRatePreferenceController.DeviceConfigDisplaySettings mDeviceConfigDisplaySettings; + @Mock + private DisplayManager mDisplayManagerMock; + @Mock + private Display mDisplayMock; + @Mock + private Display mDisplayMock2; @Rule public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule(); + @Rule + public final TestableContext mContext = new TestableContext( + InstrumentationRegistry.getInstrumentation().getContext()); @Before public void setUp() { MockitoAnnotations.initMocks(this); - mContext = RuntimeEnvironment.application; + mContext.addMockSystemService(DisplayManager.class, mDisplayManagerMock); + + Display.Mode[] modes = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 60), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 120), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 90) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY)).thenReturn(mDisplayMock); + when(mDisplayMock.getSupportedModes()).thenReturn(modes); + + Display.Mode[] modes2 = new Display.Mode[]{ + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 70), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 130), + new Display.Mode(/* modeId= */ 0, /* width= */ 800, /* height= */ 600, + /* refreshRate= */ 80) + }; + when(mDisplayManagerMock.getDisplay(Display.DEFAULT_DISPLAY + 1)).thenReturn(mDisplayMock2); + when(mDisplayMock2.getSupportedModes()).thenReturn(modes2); + + when(mDisplayManagerMock.getDisplays(DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED)) + .thenReturn(new Display[]{ mDisplayMock, mDisplayMock2 }); + mController = new PeakRefreshRatePreferenceController(mContext, "key"); mController.injectDeviceConfigDisplaySettings(mDeviceConfigDisplaySettings); mPreference = new SwitchPreference(RuntimeEnvironment.application); @@ -152,4 +191,16 @@ public class PeakRefreshRatePreferenceControllerTest { assertThat(mController.isChecked()).isFalse(); } + + @Test + @RequiresFlagsDisabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfDefaultDisplay_featureFlagOff() { + assertThat(mController.mPeakRefreshRate).isEqualTo(120); + } + + @Test + @RequiresFlagsEnabled(Flags.FLAG_BACK_UP_SMOOTH_DISPLAY_AND_FORCE_PEAK_REFRESH_RATE) + public void peakRefreshRate_highestOfAllDisplays_featureFlagOn() { + assertThat(mController.mPeakRefreshRate).isEqualTo(130); + } } From 8925db1c5e7431150222213038e42ca92bcab6ab Mon Sep 17 00:00:00 2001 From: mrulhania Date: Fri, 23 Feb 2024 11:38:43 -0800 Subject: [PATCH 3/3] add sensitive content protection flag to developer option Bug: 316955558 Test: atest SensitiveContentProtectionPreferenceControllerTest Change-Id: Iedbbc9bd3bba00c6aaccc99758abe0b77306da01 --- ...SensitiveContentProtectionPreferenceController.kt | 2 ++ ...itiveContentProtectionPreferenceControllerTest.kt | 12 ++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt b/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt index e627f81a60d..8acd7006ce4 100644 --- a/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt +++ b/src/com/android/settings/development/SensitiveContentProtectionPreferenceController.kt @@ -18,6 +18,7 @@ package com.android.settings.development import android.content.Context import android.permission.flags.Flags.sensitiveNotificationAppProtection import android.provider.Settings +import android.view.flags.Flags.sensitiveContentAppProtection import androidx.annotation.VisibleForTesting import androidx.preference.Preference import androidx.preference.TwoStatePreference @@ -64,6 +65,7 @@ class SensitiveContentProtectionPreferenceController(val context: Context) : override fun isAvailable(): Boolean { return sensitiveNotificationAppProtection() || screenshareNotificationHiding() + || sensitiveContentAppProtection() } companion object { diff --git a/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt b/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt index 18acbbaba65..023572b9e28 100644 --- a/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt +++ b/tests/spa_unit/src/com/android/settings/development/SensitiveContentProtectionPreferenceControllerTest.kt @@ -22,6 +22,7 @@ import android.platform.test.annotations.RequiresFlagsEnabled import android.platform.test.flag.junit.DeviceFlagsValueProvider import android.provider.Settings import android.provider.Settings.Global.DISABLE_SCREEN_SHARE_PROTECTIONS_FOR_APPS_AND_NOTIFICATIONS +import android.view.flags.Flags.FLAG_SENSITIVE_CONTENT_APP_PROTECTION import androidx.preference.Preference import androidx.preference.PreferenceScreen import androidx.preference.SwitchPreference @@ -132,7 +133,8 @@ class SensitiveContentProtectionPreferenceControllerTest { @Test @RequiresFlagsDisabled( FLAG_SENSITIVE_NOTIFICATION_APP_PROTECTION, - FLAG_SCREENSHARE_NOTIFICATION_HIDING) + FLAG_SCREENSHARE_NOTIFICATION_HIDING, + FLAG_SENSITIVE_CONTENT_APP_PROTECTION) fun isAvailable_flagsDisabled_returnFalse() { assertFalse(controller.isAvailable) } @@ -148,4 +150,10 @@ class SensitiveContentProtectionPreferenceControllerTest { fun isAvailable_screenshareNotificationHidingEnabled_returnTrue() { assertTrue(controller.isAvailable) } -} \ No newline at end of file + + @Test + @RequiresFlagsEnabled(FLAG_SENSITIVE_CONTENT_APP_PROTECTION) + fun isAvailable_screenshareSensitiveContentHidingEnabled_returnTrue() { + assertTrue(controller.isAvailable) + } +}