diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java b/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java index 16d2e6b47a54c..93531ddea005b 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/AlwaysOnMagnificationFeatureFlag.java @@ -16,76 +16,31 @@ package com.android.server.accessibility.magnification; -import android.annotation.NonNull; import android.provider.DeviceConfig; -import com.android.internal.annotations.VisibleForTesting; - -import java.util.concurrent.Executor; - /** * Encapsulates the feature flags for always on magnification. {@see DeviceConfig} * * @hide */ -public class AlwaysOnMagnificationFeatureFlag { +public class AlwaysOnMagnificationFeatureFlag extends MagnificationFeatureFlagBase { private static final String NAMESPACE = DeviceConfig.NAMESPACE_WINDOW_MANAGER; private static final String FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION = "AlwaysOnMagnifier__enable_always_on_magnifier"; - private AlwaysOnMagnificationFeatureFlag() {} - - /** Returns true if the feature flag is enabled for always on magnification */ - public static boolean isAlwaysOnMagnificationEnabled() { - return DeviceConfig.getBoolean( - NAMESPACE, - FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION, - /* defaultValue= */ false); + @Override + String getNamespace() { + return NAMESPACE; } - /** Sets the feature flag. Only used for testing; requires shell permissions. */ - @VisibleForTesting - public static boolean setAlwaysOnMagnificationEnabled(boolean isEnabled) { - return DeviceConfig.setProperty( - NAMESPACE, - FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION, - Boolean.toString(isEnabled), - /* makeDefault= */ false); + @Override + String getFeatureName() { + return FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION; } - /** - * Adds a listener for when the feature flag changes. - * - *

{@see DeviceConfig#addOnPropertiesChangedListener( - * String, Executor, DeviceConfig.OnPropertiesChangedListener)} - */ - @NonNull - public static DeviceConfig.OnPropertiesChangedListener addOnChangedListener( - @NonNull Executor executor, @NonNull Runnable listener) { - DeviceConfig.OnPropertiesChangedListener onChangedListener = - properties -> { - if (properties.getKeyset().contains( - FEATURE_NAME_ENABLE_ALWAYS_ON_MAGNIFICATION)) { - listener.run(); - } - }; - DeviceConfig.addOnPropertiesChangedListener( - NAMESPACE, - executor, - onChangedListener); - - return onChangedListener; - } - - /** - * Remove a listener for when the feature flag changes. - * - *

{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor, - * DeviceConfig.OnPropertiesChangedListener)} - */ - public static void removeOnChangedListener( - @NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) { - DeviceConfig.removeOnPropertiesChangedListener(onChangedListener); + @Override + boolean getDefaultValue() { + return false; } } diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java index 22e742bc09731..1055ba23b10fe 100644 --- a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationController.java @@ -93,6 +93,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb private final SparseArray mMagnificationEndRunnableSparseArray = new SparseArray(); + private final AlwaysOnMagnificationFeatureFlag mAlwaysOnMagnificationFeatureFlag; private final MagnificationScaleProvider mScaleProvider; private FullScreenMagnificationController mFullScreenMagnificationController; private WindowMagnificationManager mWindowMagnificationMgr; @@ -151,7 +152,8 @@ public class MagnificationController implements WindowMagnificationManager.Callb mSupportWindowMagnification = context.getPackageManager().hasSystemFeature( FEATURE_WINDOW_MAGNIFICATION); - AlwaysOnMagnificationFeatureFlag.addOnChangedListener( + mAlwaysOnMagnificationFeatureFlag = new AlwaysOnMagnificationFeatureFlag(); + mAlwaysOnMagnificationFeatureFlag.addOnChangedListener( ConcurrentUtils.DIRECT_EXECUTOR, mAms::updateAlwaysOnMagnification); } @@ -698,7 +700,7 @@ public class MagnificationController implements WindowMagnificationManager.Callb } public boolean isAlwaysOnMagnificationFeatureFlagEnabled() { - return AlwaysOnMagnificationFeatureFlag.isAlwaysOnMagnificationEnabled(); + return mAlwaysOnMagnificationFeatureFlag.isFeatureFlagEnabled(); } private DisableMagnificationCallback getDisableMagnificationEndRunnableLocked( diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java new file mode 100644 index 0000000000000..2965887d8eb3c --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/magnification/MagnificationFeatureFlagBase.java @@ -0,0 +1,115 @@ +/* + * Copyright (C) 2023 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.server.accessibility.magnification; + +import android.annotation.NonNull; +import android.os.Binder; +import android.provider.DeviceConfig; + +import com.android.internal.annotations.VisibleForTesting; + +import java.util.concurrent.Executor; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Abstract base class to encapsulates the feature flags for magnification features. + * {@see DeviceConfig} + * + * @hide + */ +abstract class MagnificationFeatureFlagBase { + + abstract String getNamespace(); + abstract String getFeatureName(); + abstract boolean getDefaultValue(); + + private void clearCallingIdentifyAndTryCatch(Runnable tryBlock, Runnable catchBlock) { + try { + Binder.withCleanCallingIdentity(() -> tryBlock.run()); + } catch (Throwable throwable) { + catchBlock.run(); + } + } + + /** Returns true iff the feature flag is readable and enabled */ + public boolean isFeatureFlagEnabled() { + AtomicBoolean isEnabled = new AtomicBoolean(getDefaultValue()); + + clearCallingIdentifyAndTryCatch( + () -> isEnabled.set(DeviceConfig.getBoolean( + getNamespace(), + getFeatureName(), + getDefaultValue())), + () -> isEnabled.set(getDefaultValue())); + + return isEnabled.get(); + } + + /** Sets the feature flag. Only used for testing; requires shell permissions. */ + @VisibleForTesting + public boolean setFeatureFlagEnabled(boolean isEnabled) { + AtomicBoolean success = new AtomicBoolean(getDefaultValue()); + + clearCallingIdentifyAndTryCatch( + () -> success.set(DeviceConfig.setProperty( + getNamespace(), + getFeatureName(), + Boolean.toString(isEnabled), + /* makeDefault= */ false)), + () -> success.set(getDefaultValue())); + + return success.get(); + } + + /** + * Adds a listener for when the feature flag changes. + * + *

{@see DeviceConfig#addOnPropertiesChangedListener( + * String, Executor, DeviceConfig.OnPropertiesChangedListener)} + */ + @NonNull + public DeviceConfig.OnPropertiesChangedListener addOnChangedListener( + @NonNull Executor executor, @NonNull Runnable listener) { + DeviceConfig.OnPropertiesChangedListener onChangedListener = + properties -> { + if (properties.getKeyset().contains( + getFeatureName())) { + listener.run(); + } + }; + + clearCallingIdentifyAndTryCatch( + () -> DeviceConfig.addOnPropertiesChangedListener( + getNamespace(), + executor, + onChangedListener), + () -> {}); + + return onChangedListener; + } + + /** + * Remove a listener for when the feature flag changes. + * + *

{@see DeviceConfig#addOnPropertiesChangedListener(String, Executor, + * DeviceConfig.OnPropertiesChangedListener)} + */ + public void removeOnChangedListener( + @NonNull DeviceConfig.OnPropertiesChangedListener onChangedListener) { + DeviceConfig.removeOnPropertiesChangedListener(onChangedListener); + } +}