Removing flag overrides. All flags should be defined as togglable flags instead.
Change-Id: Ia7b9ff84413096cd5b0c4a9a81a232019f2522d2
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
new file mode 100644
index 0000000..80b6fa7
--- /dev/null
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2017 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.launcher3.config;
+
+import static androidx.core.util.Preconditions.checkNotNull;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import androidx.annotation.GuardedBy;
+import androidx.annotation.Keep;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.launcher3.BuildConfig;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.uioverrides.TogglableFlag;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+/**
+ * Defines a set of flags used to control various launcher behaviors.
+ *
+ * <p>All the flags should be defined here with appropriate default values.
+ */
+@Keep
+public final class FeatureFlags {
+
+ private static final Object sLock = new Object();
+ @GuardedBy("sLock")
+ private static final List<TogglableFlag> sFlags = new ArrayList<>();
+
+ static final String FLAGS_PREF_NAME = "featureFlags";
+
+ private FeatureFlags() { }
+
+ public static boolean showFlagTogglerUi(Context context) {
+ return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
+ }
+
+ public static final boolean IS_DOGFOOD_BUILD = BuildConfig.DEBUG;
+
+ /**
+ * Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
+ * and should be modified at a project level.
+ */
+ public static final boolean QSB_ON_FIRST_SCREEN = true;
+
+
+ /**
+ * Feature flag to handle define config changes dynamically instead of killing the process.
+ *
+ *
+ * To add a new flag that can be toggled through the flags UI:
+ *
+ * 1. Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"),
+ * and set a default value for the flag. This will be the default value on Debug builds.
+ *
+ * 2. Add your flag to mTogglableFlags.
+ *
+ * 3. Create a getter method (an 'is' method) for the flag by copying an existing one.
+ *
+ * 4. Create a getter method with the same name in the release flags copy of FeatureFlags.java.
+ * This should returns a constant (true/false). This will be the value of the flag used on
+ * release builds.
+ */
+ // When enabled the promise icon is visible in all apps while installation an app.
+ public static final TogglableFlag PROMISE_APPS_IN_ALL_APPS = new TogglableFlag(
+ "PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps");
+
+ // When enabled a promise icon is added to the home screen when install session is active.
+ public static final TogglableFlag PROMISE_APPS_NEW_INSTALLS =
+ new TogglableFlag("PROMISE_APPS_NEW_INSTALLS", true,
+ "Adds a promise icon to the home screen for new install sessions.");
+
+ public static final TogglableFlag APPLY_CONFIG_AT_RUNTIME = new TogglableFlag(
+ "APPLY_CONFIG_AT_RUNTIME", true, "Apply display changes dynamically");
+
+ public static final TogglableFlag QUICKSTEP_SPRINGS = new TogglableFlag("QUICKSTEP_SPRINGS",
+ false, "Enable springs for quickstep animations");
+
+ public static final TogglableFlag ADAPTIVE_ICON_WINDOW_ANIM = new TogglableFlag(
+ "ADAPTIVE_ICON_WINDOW_ANIM", true,
+ "Use adaptive icons for window animations.");
+
+ public static final TogglableFlag ENABLE_QUICKSTEP_LIVE_TILE = new TogglableFlag(
+ "ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
+
+ public static final TogglableFlag ENABLE_HINTS_IN_OVERVIEW = new TogglableFlag(
+ "ENABLE_HINTS_IN_OVERVIEW", true,
+ "Show chip hints and gleams on the overview screen");
+
+ public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
+ "FAKE_LANDSCAPE_UI", false,
+ "Rotate launcher UI instead of using transposed layout");
+
+ public static final TogglableFlag APP_SEARCH_IMPROVEMENTS = new TogglableFlag(
+ "APP_SEARCH_IMPROVEMENTS", false,
+ "Adds localized title and keyword search and ranking");
+
+ public static final TogglableFlag ENABLE_PREDICTION_DISMISS = new TogglableFlag(
+ "ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
+
+
+ public static void initialize(Context context) {
+ // Avoid the disk read for user builds
+ if (Utilities.IS_DEBUG_DEVICE) {
+ synchronized (sLock) {
+ for (BaseTogglableFlag flag : sFlags) {
+ flag.initialize(context);
+ }
+ }
+ }
+ }
+
+ static List<TogglableFlag> getTogglableFlags() {
+ // By Java Language Spec 12.4.2
+ // https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2, the
+ // TogglableFlag instances on FeatureFlags will be created before those on the FeatureFlags
+ // subclass. This code handles flags that are redeclared in FeatureFlags, ensuring the
+ // FeatureFlags one takes priority.
+ SortedMap<String, TogglableFlag> flagsByKey = new TreeMap<>();
+ synchronized (sLock) {
+ for (TogglableFlag flag : sFlags) {
+ flagsByKey.put(flag.getKey(), flag);
+ }
+ }
+ return new ArrayList<>(flagsByKey.values());
+ }
+
+ public static abstract class BaseTogglableFlag {
+ private final String key;
+ private final boolean defaultValue;
+ private final String description;
+ private boolean currentValue;
+
+ public BaseTogglableFlag(
+ String key,
+ boolean defaultValue,
+ String description) {
+ this.key = checkNotNull(key);
+ this.currentValue = this.defaultValue = getInitialValue(defaultValue);
+ this.description = checkNotNull(description);
+ synchronized (sLock) {
+ sFlags.add((TogglableFlag)this);
+ }
+ }
+
+ /** Set the value of this flag. This should only be used in tests. */
+ @VisibleForTesting
+ void setForTests(boolean value) {
+ currentValue = value;
+ }
+
+ public String getKey() {
+ return key;
+ }
+
+ void initialize(Context context) {
+ currentValue = getFromStorage(context, defaultValue);
+ }
+
+ protected abstract boolean getInitialValue(boolean value);
+
+ public void updateStorage(Context context, boolean value) {
+ SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME,
+ Context.MODE_PRIVATE).edit();
+ if (value == defaultValue) {
+ editor.remove(key).apply();
+ } else {
+ editor.putBoolean(key, value).apply();
+ }
+ }
+
+ boolean getFromStorage(Context context, boolean defaultValue) {
+ return context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+ .getBoolean(key, defaultValue);
+ }
+
+ boolean getDefaultValue() {
+ return defaultValue;
+ }
+
+ /** Returns the value of the flag at process start, including any overrides present. */
+ public boolean get() {
+ return currentValue;
+ }
+
+ String getDescription() {
+ return description;
+ }
+
+ @Override
+ public String toString() {
+ return "TogglableFlag{"
+ + "key=" + key + ", "
+ + "defaultValue=" + defaultValue + ", "
+ + "description=" + description
+ + "}";
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ }
+ if (o instanceof TogglableFlag) {
+ BaseTogglableFlag that = (BaseTogglableFlag) o;
+ return (this.key.equals(that.getKey()))
+ && (this.defaultValue == that.getDefaultValue())
+ && (this.description.equals(that.getDescription()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ int h$ = 1;
+ h$ *= 1000003;
+ h$ ^= key.hashCode();
+ h$ *= 1000003;
+ h$ ^= defaultValue ? 1231 : 1237;
+ h$ *= 1000003;
+ h$ ^= description.hashCode();
+ return h$;
+ }
+ }
+}