diff --git a/res/values/strings.xml b/res/values/strings.xml
index 4edc3b505ea..bec50d4f7d8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -3972,6 +3972,10 @@
Magnify typing
Magnifier follows text as you type
+
+ Always On
+
+ Instead of deactivating magnification when changing apps, it simply zooms out to normal size. Pinch to zoom back in whenever you want.
About magnification
diff --git a/src/com/android/settings/accessibility/MagnificationAlwaysOnPreferenceController.java b/src/com/android/settings/accessibility/MagnificationAlwaysOnPreferenceController.java
new file mode 100644
index 00000000000..b0a6abc8349
--- /dev/null
+++ b/src/com/android/settings/accessibility/MagnificationAlwaysOnPreferenceController.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2022 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.accessibility;
+
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.OnLifecycleEvent;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+
+import com.android.settings.R;
+import com.android.settings.core.TogglePreferenceController;
+
+/**
+ * Controller that accesses and switches the preference status of the magnification always on
+ * feature, where the magnifier will not deactivate on Activity transitions; it will only zoom out
+ * to 100%.
+ */
+public class MagnificationAlwaysOnPreferenceController extends TogglePreferenceController
+ implements LifecycleObserver {
+
+ private static final String TAG =
+ MagnificationAlwaysOnPreferenceController.class.getSimpleName();
+ static final String PREF_KEY = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED;
+
+ private SwitchPreference mSwitchPreference;
+
+ public MagnificationAlwaysOnPreferenceController(Context context, String preferenceKey) {
+ super(context, preferenceKey);
+ }
+
+ @Override
+ public int getAvailabilityStatus() {
+ return AVAILABLE;
+ }
+
+ @Override
+ public boolean isChecked() {
+ return Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED, ON) == ON;
+ }
+
+ @Override
+ public boolean setChecked(boolean isChecked) {
+ return Settings.Secure.putInt(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED,
+ (isChecked ? ON : OFF));
+ }
+
+ @Override
+ public int getSliceHighlightMenuRes() {
+ return R.string.menu_key_accessibility;
+ }
+
+ @Override
+ public void displayPreference(PreferenceScreen screen) {
+ super.displayPreference(screen);
+ mSwitchPreference = screen.findPreference(getPreferenceKey());
+ }
+
+ // TODO(b/186731461): Remove it when this controller is used in DashBoardFragment only.
+ @OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
+ void onResume() {
+ updateState();
+ }
+
+ /**
+ * Updates the state of preference components which has been displayed by
+ * {@link MagnificationAlwaysOnPreferenceController#displayPreference}.
+ */
+ void updateState() {
+ updateState(mSwitchPreference);
+ }
+}
diff --git a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
index 935c3cb452f..979c941489f 100644
--- a/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
+++ b/src/com/android/settings/accessibility/ToggleScreenMagnificationPreferenceFragment.java
@@ -31,6 +31,7 @@ import android.content.pm.PackageManager;
import android.icu.text.CaseMap;
import android.net.Uri;
import android.os.Bundle;
+import android.provider.DeviceConfig;
import android.provider.Settings;
import android.text.TextUtils;
import android.view.LayoutInflater;
@@ -212,6 +213,32 @@ public class ToggleScreenMagnificationPreferenceFragment extends
getContext(), MagnificationFollowTypingPreferenceController.PREF_KEY);
getSettingsLifecycle().addObserver(mFollowTypingPreferenceController);
mFollowTypingPreferenceController.displayPreference(getPreferenceScreen());
+
+ addAlwaysOnSetting(generalCategory);
+ }
+
+ private void addAlwaysOnSetting(PreferenceCategory generalCategory) {
+ if (!DeviceConfig.getBoolean(
+ DeviceConfig.NAMESPACE_WINDOW_MANAGER,
+ "AlwaysOnMagnifier__enable_always_on_magnifier",
+ false
+ )) {
+ return;
+ }
+
+ var alwaysOnPreference = new SwitchPreference(getPrefContext());
+ alwaysOnPreference.setTitle(
+ R.string.accessibility_screen_magnification_always_on_title);
+ alwaysOnPreference.setSummary(
+ R.string.accessibility_screen_magnification_always_on_summary);
+ alwaysOnPreference.setKey(
+ MagnificationAlwaysOnPreferenceController.PREF_KEY);
+ generalCategory.addPreference(alwaysOnPreference);
+
+ var alwaysOnPreferenceController = new MagnificationAlwaysOnPreferenceController(
+ getContext(), MagnificationAlwaysOnPreferenceController.PREF_KEY);
+ getSettingsLifecycle().addObserver(alwaysOnPreferenceController);
+ alwaysOnPreferenceController.displayPreference(getPreferenceScreen());
}
@Override
diff --git a/tests/robotests/src/com/android/settings/accessibility/MagnificationAlwaysOnPreferenceControllerTest.java b/tests/robotests/src/com/android/settings/accessibility/MagnificationAlwaysOnPreferenceControllerTest.java
new file mode 100644
index 00000000000..e8015c5afcf
--- /dev/null
+++ b/tests/robotests/src/com/android/settings/accessibility/MagnificationAlwaysOnPreferenceControllerTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2022 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.accessibility;
+
+import static com.android.settings.accessibility.AccessibilityUtil.State.OFF;
+import static com.android.settings.accessibility.AccessibilityUtil.State.ON;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.content.Context;
+import android.provider.Settings;
+
+import androidx.preference.PreferenceManager;
+import androidx.preference.PreferenceScreen;
+import androidx.preference.SwitchPreference;
+import androidx.test.core.app.ApplicationProvider;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+@RunWith(RobolectricTestRunner.class)
+public class MagnificationAlwaysOnPreferenceControllerTest {
+
+ private static final String KEY_ALWAYS_ON =
+ Settings.Secure.ACCESSIBILITY_MAGNIFICATION_ALWAYS_ON_ENABLED;
+
+ private final Context mContext = ApplicationProvider.getApplicationContext();
+ private final SwitchPreference mSwitchPreference = spy(new SwitchPreference(mContext));
+ private final MagnificationAlwaysOnPreferenceController mController =
+ new MagnificationAlwaysOnPreferenceController(mContext,
+ MagnificationAlwaysOnPreferenceController.PREF_KEY);
+
+ @Before
+ public void setUp() {
+ final PreferenceManager preferenceManager = new PreferenceManager(mContext);
+ final PreferenceScreen screen = preferenceManager.createPreferenceScreen(mContext);
+ mSwitchPreference.setKey(MagnificationAlwaysOnPreferenceController.PREF_KEY);
+ screen.addPreference(mSwitchPreference);
+ mController.displayPreference(screen);
+ }
+
+ @Test
+ public void isChecked_defaultStateForAlwaysOn_onResumeShouldReturnTrue() {
+ mController.onResume();
+
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void isChecked_enableAlwaysOn_onResumeShouldReturnTrue() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ALWAYS_ON, ON);
+ mController.onResume();
+
+ assertThat(mController.isChecked()).isTrue();
+ assertThat(mSwitchPreference.isChecked()).isTrue();
+ }
+
+ @Test
+ public void isChecked_disableAlwaysOn_onResumeShouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ALWAYS_ON, OFF);
+ mController.onResume();
+
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void performClick_switchDefaultStateForAlwaysOn_shouldReturnFalse() {
+ mController.onResume();
+
+ mSwitchPreference.performClick();
+
+ verify(mSwitchPreference).setChecked(false);
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+
+ @Test
+ public void updateState_disableAlwaysOn_shouldReturnFalse() {
+ Settings.Secure.putInt(mContext.getContentResolver(), KEY_ALWAYS_ON, OFF);
+
+ mController.updateState();
+
+ verify(mSwitchPreference).setChecked(false);
+ assertThat(mController.isChecked()).isFalse();
+ assertThat(mSwitchPreference.isChecked()).isFalse();
+ }
+}