Merge "Add SystemUiSystemPropertiesFlags" into tm-qpr-dev
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