Merge "Add SystemUiSystemPropertiesFlags" into tm-qpr-dev am: 39cb46ea1d am: 8eef61361b
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/21149318 Change-Id: Ibbb129cd2629afe75e1313e7668df87332ff89fb Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
@@ -0,0 +1,183 @@
|
||||
/**
|
||||
* 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.internal.config.sysui;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.os.Build;
|
||||
import android.os.SystemProperties;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* Provides a central definition of debug SystemUI's SystemProperties flags, and their defaults.
|
||||
*
|
||||
* The main feature of this class is that it encodes a system-wide default for each flag which can
|
||||
* be updated by engineers with a single-line CL.
|
||||
*
|
||||
* NOTE: Because flag values returned by this class are not cached, it is important that developers
|
||||
* understand the intricacies of changing values and how that applies to their own code.
|
||||
* Generally, the best practice is to set the property, and then restart the device so that any
|
||||
* processes with stale state can be updated. However, if your code has no state derived from the
|
||||
* flag value and queries it any time behavior is relevant, then it may be safe to change the flag
|
||||
* and not immediately reboot.
|
||||
*
|
||||
* To enable flags in debuggable builds, use the following commands:
|
||||
*
|
||||
* $ adb shell setprop persist.sysui.whatever_the_flag true
|
||||
* $ adb reboot
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class SystemUiSystemPropertiesFlags {
|
||||
|
||||
/** The interface used for resolving SystemUI SystemProperties Flags to booleans. */
|
||||
public interface FlagResolver {
|
||||
/** Is the flag enabled? */
|
||||
boolean isEnabled(Flag flag);
|
||||
}
|
||||
|
||||
/** The primary, immutable resolver returned by getResolver() */
|
||||
private static final FlagResolver
|
||||
MAIN_RESOLVER =
|
||||
Build.IS_DEBUGGABLE ? new DebugResolver() : new ProdResolver();
|
||||
|
||||
/**
|
||||
* On debuggable builds, this can be set to override the resolver returned by getResolver().
|
||||
* This can be useful to override flags when testing components that do not allow injecting the
|
||||
* SystemUiPropertiesFlags resolver they use.
|
||||
* Always set this to null when tests tear down.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static FlagResolver TEST_RESOLVER = null;
|
||||
|
||||
/** Get the resolver for this device configuration. */
|
||||
public static FlagResolver getResolver() {
|
||||
if (Build.IS_DEBUGGABLE && TEST_RESOLVER != null) {
|
||||
Log.i("SystemUiSystemPropertiesFlags", "Returning debug resolver " + TEST_RESOLVER);
|
||||
return TEST_RESOLVER;
|
||||
}
|
||||
return MAIN_RESOLVER;
|
||||
}
|
||||
|
||||
/** The teamfood flag allows multiple features to be opted into at once. */
|
||||
public static final Flag TEAMFOOD = devFlag("persist.sysui.teamfood");
|
||||
|
||||
/**
|
||||
* Flags related to notification features
|
||||
*/
|
||||
public static final class NotificationFlags {
|
||||
|
||||
/**
|
||||
* FOR DEVELOPMENT / TESTING ONLY!!!
|
||||
* Forcibly demote *ALL* FSI notifications as if no apps have the app op permission.
|
||||
*/
|
||||
public static final Flag FSI_FORCE_DEMOTE =
|
||||
devFlag("persist.sysui.notification.fsi_force_demote");
|
||||
|
||||
/** Gating the ability for users to dismiss ongoing event notifications */
|
||||
public static final Flag ALLOW_DISMISS_ONGOING =
|
||||
devFlag("persist.sysui.notification.ongoing_dismissal");
|
||||
|
||||
/** Gating the redaction of OTP notifications on the lockscreen */
|
||||
public static final Flag OTP_REDACTION =
|
||||
devFlag("persist.sysui.notification.otp_redaction");
|
||||
|
||||
}
|
||||
|
||||
//// == Everything below this line is the implementation == ////
|
||||
|
||||
/**
|
||||
* Creates a flag that is enabled by default in debuggable builds.
|
||||
* It can be enabled by setting this flag's SystemProperty to 1.
|
||||
*
|
||||
* This flag is ALWAYS disabled in release builds.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static Flag devFlag(String name) {
|
||||
return new Flag(name, false, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a flag that is disabled by default in debuggable builds.
|
||||
* It can be enabled or force-disabled by setting this flag's SystemProperty to 1 or 0.
|
||||
* If this flag's SystemProperty is not set, the flag can be enabled by setting the
|
||||
* TEAMFOOD flag's SystemProperty to 1.
|
||||
*
|
||||
* This flag is ALWAYS disabled in release builds.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static Flag teamfoodFlag(String name) {
|
||||
return new Flag(name, false, TEAMFOOD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a flag that is enabled by default in debuggable builds.
|
||||
* It can be enabled by setting this flag's SystemProperty to 0.
|
||||
*
|
||||
* This flag is ALWAYS enabled in release builds.
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static Flag releasedFlag(String name) {
|
||||
return new Flag(name, true, null);
|
||||
}
|
||||
|
||||
/** Represents a developer-switchable gate for a feature. */
|
||||
public static final class Flag {
|
||||
public final String mSysPropKey;
|
||||
public final boolean mDefaultValue;
|
||||
@Nullable
|
||||
public final Flag mDebugDefault;
|
||||
|
||||
/** constructs a new flag. only visible for testing the class */
|
||||
@VisibleForTesting
|
||||
public Flag(@NonNull String sysPropKey, boolean defaultValue, @Nullable Flag debugDefault) {
|
||||
mSysPropKey = sysPropKey;
|
||||
mDefaultValue = defaultValue;
|
||||
mDebugDefault = debugDefault;
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of the interface used in release builds. */
|
||||
@VisibleForTesting
|
||||
public static final class ProdResolver implements
|
||||
FlagResolver {
|
||||
@Override
|
||||
public boolean isEnabled(Flag flag) {
|
||||
return flag.mDefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
/** Implementation of the interface used in debuggable builds. */
|
||||
@VisibleForTesting
|
||||
public static class DebugResolver implements FlagResolver {
|
||||
@Override
|
||||
public final boolean isEnabled(Flag flag) {
|
||||
if (flag.mDebugDefault == null) {
|
||||
return getBoolean(flag.mSysPropKey, flag.mDefaultValue);
|
||||
}
|
||||
return getBoolean(flag.mSysPropKey, isEnabled(flag.mDebugDefault));
|
||||
}
|
||||
|
||||
/** Look up the value; overridable for tests to avoid needing to set SystemProperties */
|
||||
@VisibleForTesting
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
return SystemProperties.getBoolean(key, defaultValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
include /packages/SystemUI/OWNERS
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* 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.internal.config.sysui;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import androidx.test.filters.SmallTest;
|
||||
|
||||
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.Flag;
|
||||
import com.android.internal.config.sysui.SystemUiSystemPropertiesFlags.FlagResolver;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@SmallTest
|
||||
public class SystemUiSystemPropertiesFlagsTest extends TestCase {
|
||||
|
||||
public class TestableDebugResolver extends SystemUiSystemPropertiesFlags.DebugResolver {
|
||||
final Map<String, Boolean> mTestData = new HashMap<>();
|
||||
|
||||
@Override
|
||||
public boolean getBoolean(String key, boolean defaultValue) {
|
||||
Boolean testValue = mTestData.get(key);
|
||||
return testValue == null ? defaultValue : testValue;
|
||||
}
|
||||
|
||||
public void set(Flag flag, Boolean value) {
|
||||
mTestData.put(flag.mSysPropKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
private FlagResolver mProdResolver;
|
||||
private TestableDebugResolver mDebugResolver;
|
||||
|
||||
private Flag mReleasedFlag;
|
||||
private Flag mTeamfoodFlag;
|
||||
private Flag mDevFlag;
|
||||
|
||||
public void setUp() {
|
||||
mProdResolver = new SystemUiSystemPropertiesFlags.ProdResolver();
|
||||
mDebugResolver = new TestableDebugResolver();
|
||||
mReleasedFlag = SystemUiSystemPropertiesFlags.releasedFlag("mReleasedFlag");
|
||||
mTeamfoodFlag = SystemUiSystemPropertiesFlags.teamfoodFlag("mTeamfoodFlag");
|
||||
mDevFlag = SystemUiSystemPropertiesFlags.devFlag("mDevFlag");
|
||||
}
|
||||
|
||||
public void tearDown() {
|
||||
SystemUiSystemPropertiesFlags.TEST_RESOLVER = null;
|
||||
}
|
||||
|
||||
public void testProdResolverReturnsDefault() {
|
||||
assertThat(mProdResolver.isEnabled(mReleasedFlag)).isTrue();
|
||||
assertThat(mProdResolver.isEnabled(mTeamfoodFlag)).isFalse();
|
||||
assertThat(mProdResolver.isEnabled(mDevFlag)).isFalse();
|
||||
}
|
||||
|
||||
public void testDebugResolverAndReleasedFlag() {
|
||||
assertThat(mDebugResolver.isEnabled(mReleasedFlag)).isTrue();
|
||||
|
||||
mDebugResolver.set(mReleasedFlag, false);
|
||||
assertThat(mDebugResolver.isEnabled(mReleasedFlag)).isFalse();
|
||||
|
||||
mDebugResolver.set(mReleasedFlag, true);
|
||||
assertThat(mDebugResolver.isEnabled(mReleasedFlag)).isTrue();
|
||||
}
|
||||
|
||||
private void assertTeamfoodFlag(Boolean flagValue, Boolean teamfood, boolean expected) {
|
||||
mDebugResolver.set(mTeamfoodFlag, flagValue);
|
||||
mDebugResolver.set(SystemUiSystemPropertiesFlags.TEAMFOOD, teamfood);
|
||||
assertThat(mDebugResolver.isEnabled(mTeamfoodFlag)).isEqualTo(expected);
|
||||
}
|
||||
|
||||
public void testDebugResolverAndTeamfoodFlag() {
|
||||
assertTeamfoodFlag(null, null, false);
|
||||
assertTeamfoodFlag(true, null, true);
|
||||
assertTeamfoodFlag(false, null, false);
|
||||
assertTeamfoodFlag(null, true, true);
|
||||
assertTeamfoodFlag(true, true, true);
|
||||
assertTeamfoodFlag(false, true, false);
|
||||
assertTeamfoodFlag(null, false, false);
|
||||
assertTeamfoodFlag(true, false, true);
|
||||
assertTeamfoodFlag(false, false, false);
|
||||
}
|
||||
|
||||
public void testDebugResolverAndDevFlag() {
|
||||
assertThat(mDebugResolver.isEnabled(mDevFlag)).isFalse();
|
||||
|
||||
mDebugResolver.set(mDevFlag, true);
|
||||
assertThat(mDebugResolver.isEnabled(mDevFlag)).isTrue();
|
||||
|
||||
mDebugResolver.set(mDevFlag, false);
|
||||
assertThat(mDebugResolver.isEnabled(mDevFlag)).isFalse();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user