diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java index d3950ee1396..5c2dec21810 100644 --- a/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java +++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingController.java @@ -35,7 +35,6 @@ import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.settingslib.search.SearchIndexableRaw; import java.util.List; @@ -46,7 +45,7 @@ public class DeviceStateAutoRotateSettingController extends TogglePreferenceCont private TwoStatePreference mPreference; - private final DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager; + private final DeviceStateAutoRotateSettingManager mAutoRotateSettingsManager; private final int mOrder; private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference); @@ -62,7 +61,8 @@ public class DeviceStateAutoRotateSettingController extends TogglePreferenceCont mMetricsFeatureProvider = metricsFeatureProvider; mDeviceState = deviceState; mDeviceStateDescription = deviceStateDescription; - mAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance(context); + mAutoRotateSettingsManager = + DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(context); mOrder = order; } diff --git a/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProvider.kt b/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProvider.kt new file mode 100644 index 00000000000..906ffe4b566 --- /dev/null +++ b/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProvider.kt @@ -0,0 +1,62 @@ +/* + * 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.display + +import android.content.Context +import android.hardware.devicestate.DeviceStateManager +import android.os.Build +import android.os.Handler +import android.os.Looper +import com.android.internal.annotations.VisibleForTesting +import com.android.settingslib.devicestate.AndroidSecureSettings +import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager +import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManagerProvider.createInstance +import com.android.settingslib.devicestate.PosturesHelper +import com.android.settingslib.utils.ThreadUtils +import com.android.window.flags.Flags + +/** + * Provides appropriate instance of [DeviceStateAutoRotateSettingManager], based on the value of + * [Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR]. + */ +object DeviceStateAutoRotateSettingManagerProvider { + private var nullableSingletonSettingManager: DeviceStateAutoRotateSettingManager? = null + + /** + * Provides a singleton instance of [DeviceStateAutoRotateSettingManager], based on the + * value of[Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR]. It is supposed to + * be used by apps that don't support dagger to provide and manager instance. + */ + @JvmStatic + fun getSingletonInstance(context: Context) = + nullableSingletonSettingManager ?: createInstance( + context, + ThreadUtils.getBackgroundExecutor(), + AndroidSecureSettings(context.contentResolver), + Handler(Looper.getMainLooper()), + PosturesHelper(context, context.getSystemService(DeviceStateManager::class.java)) + ).also { + nullableSingletonSettingManager = it + } + + /** Resets the singleton instance of [DeviceStateAutoRotateSettingManager]. */ + @JvmStatic + @VisibleForTesting + fun resetInstance() { + nullableSingletonSettingManager = null + } +} diff --git a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java index 3bf9def2316..7b285248e1c 100644 --- a/src/com/android/settings/display/DeviceStateAutoRotationHelper.java +++ b/src/com/android/settings/display/DeviceStateAutoRotationHelper.java @@ -16,6 +16,8 @@ package com.android.settings.display; +import static com.android.settingslib.devicestate.DeviceStateAutoRotateSettingUtils.isDeviceStateRotationLockEnabled; + import android.content.Context; import android.util.Log; @@ -25,7 +27,6 @@ import com.android.internal.view.RotationPolicy; import com.android.settings.R; import com.android.settings.core.BasePreferenceController; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import com.android.settingslib.devicestate.SettableDeviceState; import com.android.settingslib.search.SearchIndexableRaw; @@ -51,8 +52,8 @@ public class DeviceStateAutoRotationHelper { static ImmutableList createPreferenceControllers( Context context) { - List settableDeviceStates = DeviceStateRotationLockSettingsManager - .getInstance(context).getSettableDeviceStates(); + List settableDeviceStates = DeviceStateAutoRotateSettingManagerProvider + .getSingletonInstance(context).getSettableDeviceStates(); int numDeviceStates = settableDeviceStates.size(); if (numDeviceStates == 0) { return ImmutableList.of(); @@ -99,7 +100,7 @@ public class DeviceStateAutoRotationHelper { /** Returns whether the device state based auto-rotation settings are enabled. */ public static boolean isDeviceStateRotationEnabled(Context context) { return RotationPolicy.isRotationLockToggleVisible(context) - && DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context); + && isDeviceStateRotationLockEnabled(context); } /** @@ -108,6 +109,6 @@ public class DeviceStateAutoRotationHelper { */ public static boolean isDeviceStateRotationEnabledForA11y(Context context) { return RotationPolicy.isRotationSupported(context) - && DeviceStateRotationLockSettingsManager.isDeviceStateRotationLockEnabled(context); + && isDeviceStateRotationLockEnabled(context); } } diff --git a/src/com/android/settings/display/SmartAutoRotateController.java b/src/com/android/settings/display/SmartAutoRotateController.java index c99b2f853ca..4bc28ff41e0 100644 --- a/src/com/android/settings/display/SmartAutoRotateController.java +++ b/src/com/android/settings/display/SmartAutoRotateController.java @@ -47,7 +47,6 @@ import com.android.settings.core.TogglePreferenceController; import com.android.settings.overlay.FeatureFactory; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; /** * SmartAutoRotateController controls whether auto rotation is enabled @@ -75,7 +74,7 @@ public class SmartAutoRotateController extends TogglePreferenceController implem } }; - private final DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager; + private final DeviceStateAutoRotateSettingManager mDeviceStateAutoRotateSettingsManager; private final DeviceStateAutoRotateSettingManager.DeviceStateAutoRotateSettingListener mDeviceStateAutoRotateSettingListener = () -> updateState(mPreference); private RotationPolicy.RotationPolicyListener mRotationPolicyListener; @@ -85,8 +84,9 @@ public class SmartAutoRotateController extends TogglePreferenceController implem mMetricsFeatureProvider = FeatureFactory.getFeatureFactory().getMetricsFeatureProvider(); mPrivacyManager = SensorPrivacyManager.getInstance(context); mPowerManager = context.getSystemService(PowerManager.class); - mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance( - context); + mDeviceStateAutoRotateSettingsManager = + DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance( + context); } @Override diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java index d1c32a2281f..6fce9a83390 100644 --- a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateDetailsFragmentTest.java @@ -39,7 +39,6 @@ import android.hardware.devicestate.DeviceStateManager; import com.android.settings.R; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import org.junit.Before; import org.junit.Test; @@ -144,16 +143,15 @@ public class DeviceStateAutoRotateDetailsFragmentTest { } private void enableDeviceStateSettableRotationStates(String[] settableStates, - String[] settableStatesDescriptions) { + String[] settableStatesDescriptions) { when(mResources.getStringArray( com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)).thenReturn( settableStates); when(mResources.getStringArray( R.array.config_settableAutoRotationDeviceStatesDescriptions)).thenReturn( settableStatesDescriptions); - DeviceStateRotationLockSettingsManager.resetInstance(); - DeviceStateRotationLockSettingsManager.getInstance(mContext) - .resetStateForTesting(mResources); + DeviceStateAutoRotateSettingManagerProvider.resetInstance(); + when(mContext.getResources()).thenReturn(mResources); } // Sets up posture mappings for PosturesHelper diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java index cb1be85f881..72a8cd58d42 100644 --- a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingControllerTest.java @@ -37,7 +37,7 @@ import com.android.settings.R; import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settingslib.core.instrumentation.MetricsFeatureProvider; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; +import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager; import com.android.settingslib.search.SearchIndexableRaw; import org.junit.Before; @@ -66,7 +66,7 @@ public class DeviceStateAutoRotateSettingControllerTest { private static final int DEFAULT_ORDER = -10; private final Context mContext = Mockito.spy(RuntimeEnvironment.application); - private DeviceStateRotationLockSettingsManager mAutoRotateSettingsManager; + private DeviceStateAutoRotateSettingManager mAutoRotateSettingsManager; @Mock private MetricsFeatureProvider mMetricsFeatureProvider; @Mock private DeviceStateManager mDeviceStateManager; @@ -82,7 +82,7 @@ public class DeviceStateAutoRotateSettingControllerTest { doReturn(List.of(DEFAULT_DEVICE_STATE)).when( mDeviceStateManager).getSupportedDeviceStates(); mAutoRotateSettingsManager = - DeviceStateRotationLockSettingsManager.getInstance(mContext); + DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mContext); mController = new DeviceStateAutoRotateSettingController( mContext, DEFAULT_DEVICE_STATE.getIdentifier(), diff --git a/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProviderTest.kt b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProviderTest.kt new file mode 100644 index 00000000000..f2e59c5a005 --- /dev/null +++ b/tests/robotests/src/com/android/settings/display/DeviceStateAutoRotateSettingManagerProviderTest.kt @@ -0,0 +1,111 @@ +/* + * 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.display; + +import android.content.Context +import android.content.res.Resources +import android.hardware.devicestate.DeviceStateManager +import android.platform.test.annotations.DisableFlags +import android.platform.test.annotations.EnableFlags +import android.platform.test.flag.junit.SetFlagsRule +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.internal.R +import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManagerImpl +import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager +import com.android.window.flags.Flags +import com.google.common.truth.Truth.assertThat +import org.junit.After +import org.junit.Before +import org.junit.Assert.assertNotSame +import org.junit.Assert.assertSame +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.junit.MockitoJUnit +import org.mockito.Mockito.`when` as whenever + +@SmallTest +@RunWith(AndroidJUnit4::class) +class DeviceStateAutoRotateSettingManagerProviderTest { + + @get:Rule + val setFlagsRule: SetFlagsRule = SetFlagsRule() + @get:Rule + val rule = MockitoJUnit.rule() + + @Mock + private lateinit var mockContext: Context + @Mock + private lateinit var mockDeviceStateManager: DeviceStateManager + @Mock + private lateinit var mockResources: Resources + + private val context: Context = ApplicationProvider.getApplicationContext() + + @Before + fun setup() { + whenever(mockContext.contentResolver).thenReturn(context.contentResolver) + whenever(mockContext.getSystemService(DeviceStateManager::class.java)).thenReturn( + mockDeviceStateManager + ) + whenever(mockContext.resources).thenReturn(mockResources) + whenever(mockResources.getStringArray(R.array.config_perDeviceStateRotationLockDefaults)) + .thenReturn(arrayOf()) + } + + @After + fun tearDown() { + DeviceStateAutoRotateSettingManagerProvider.resetInstance() + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR) + fun getSingletonInstance_refactorFlagEnabled_returnsRefactoredManager() { + val manager = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext) + + assertThat(manager).isInstanceOf(DeviceStateAutoRotateSettingManagerImpl::class.java) + } + + @Test + @DisableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR) + fun getSingletonInstance_refactorFlagDisabled_returnsLegacyManager() { + val manager = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext) + + assertThat(manager).isInstanceOf(DeviceStateRotationLockSettingsManager::class.java) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR) + fun getSingletonInstance_resetInstance_returnsNewInstance() { + val manager1 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext) + DeviceStateAutoRotateSettingManagerProvider.resetInstance() + val manager2 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext) + + assertNotSame(manager1, manager2) + } + + @Test + @EnableFlags(Flags.FLAG_ENABLE_DEVICE_STATE_AUTO_ROTATE_SETTING_REFACTOR) + fun getSingletonInstance_getInstanceTwice_returnsSameInstance() { + val manager1 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext) + val manager2 = DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(mockContext) + + assertSame(manager1, manager2) + } +} diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java index e2542b0d55b..525c20ec3d9 100644 --- a/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java +++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotateControllerTest.java @@ -45,7 +45,7 @@ import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettin import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settings.testutils.shadow.ShadowSensorPrivacyManager; import com.android.settings.testutils.shadow.ShadowSystemSettings; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; +import com.android.settingslib.devicestate.DeviceStateAutoRotateSettingManager; import org.junit.Before; import org.junit.Test; @@ -74,7 +74,7 @@ public class SmartAutoRotateControllerTest { @Mock private DeviceStateManager mDeviceStateManager; private ContentResolver mContentResolver; - private DeviceStateRotationLockSettingsManager mDeviceStateAutoRotateSettingsManager; + private DeviceStateAutoRotateSettingManager mDeviceStateAutoRotateSettingManager; @Before public void setUp() { @@ -91,8 +91,8 @@ public class SmartAutoRotateControllerTest { doReturn(context).when(context).getApplicationContext(); doReturn(mDeviceStateManager).when(context).getSystemService(DeviceStateManager.class); doReturn(getDeviceStateList()).when(mDeviceStateManager).getSupportedDeviceStates(); - mDeviceStateAutoRotateSettingsManager = DeviceStateRotationLockSettingsManager.getInstance( - context); + mDeviceStateAutoRotateSettingManager = + DeviceStateAutoRotateSettingManagerProvider.getSingletonInstance(context); mController = Mockito.spy(new SmartAutoRotateController(context, "test_key")); when(mController.isCameraLocked()).thenReturn(false); @@ -187,13 +187,13 @@ public class SmartAutoRotateControllerTest { private void lockDeviceStateRotation() { ShadowDeviceStateRotationLockSettingsManager shadowManager = - Shadow.extract(mDeviceStateAutoRotateSettingsManager); + Shadow.extract(mDeviceStateAutoRotateSettingManager); shadowManager.setRotationLockedForAllStates(true); } private void unlockDeviceStateRotation() { ShadowDeviceStateRotationLockSettingsManager shadowManager = - Shadow.extract(mDeviceStateAutoRotateSettingsManager); + Shadow.extract(mDeviceStateAutoRotateSettingManager); shadowManager.setRotationLockedForAllStates(false); } diff --git a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java index 16155384cf8..4b95aedd3a9 100644 --- a/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java +++ b/tests/robotests/src/com/android/settings/display/SmartAutoRotatePreferenceFragmentTest.java @@ -58,7 +58,6 @@ import com.android.settings.testutils.ResolveInfoBuilder; import com.android.settings.testutils.shadow.ShadowDeviceStateRotationLockSettingsManager; import com.android.settings.testutils.shadow.ShadowRotationPolicy; import com.android.settingslib.core.AbstractPreferenceController; -import com.android.settingslib.devicestate.DeviceStateRotationLockSettingsManager; import org.junit.Before; import org.junit.Test; @@ -258,15 +257,14 @@ public class SmartAutoRotatePreferenceFragmentTest { private void enableDeviceStateSettableRotationStates( String[] settableStates, String[] settableStatesDescriptions) { when(mResources.getStringArray( - com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)) + com.android.internal.R.array.config_perDeviceStateRotationLockDefaults)) .thenReturn(settableStates); when(mResources.getStringArray(R.array.config_settableAutoRotationDeviceStatesDescriptions)) .thenReturn(settableStatesDescriptions); when(mResources.getBoolean(R.bool.config_auto_rotate_face_detection_available)) .thenReturn(true); - DeviceStateRotationLockSettingsManager.resetInstance(); - DeviceStateRotationLockSettingsManager.getInstance(mContext) - .resetStateForTesting(mResources); + DeviceStateAutoRotateSettingManagerProvider.resetInstance(); + when(mContext.getResources()).thenReturn(mResources); } // Sets up posture mappings for PosturesHelper