Loading quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java +6 −2 Original line number Diff line number Diff line Loading @@ -15,16 +15,20 @@ */ package com.android.launcher3.uioverrides.flags; import androidx.annotation.NonNull; import com.android.launcher3.config.FeatureFlags.BooleanFlag; import com.android.launcher3.config.FeatureFlags.FlagState; class DebugFlag extends BooleanFlag { public final String key; public final String description; public final boolean defaultValue; @NonNull public final FlagState defaultValue; public DebugFlag(String key, String description, boolean defaultValue, boolean currentValue) { DebugFlag(String key, String description, FlagState defaultValue, boolean currentValue) { super(currentValue); this.key = key; this.defaultValue = defaultValue; Loading quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java +9 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.ArrayMap; import android.util.Pair; Loading Loading @@ -182,9 +183,16 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { } private PreferenceCategory newCategory(String title) { return newCategory(title, null); } private PreferenceCategory newCategory(String title, @Nullable String summary) { PreferenceCategory category = new PreferenceCategory(getContext()); category.setOrder(Preference.DEFAULT_ORDER); category.setTitle(title); if (!TextUtils.isEmpty(summary)) { category.setSummary(summary); } mPreferenceScreen.addPreference(category); return category; } Loading @@ -195,7 +203,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { } mFlagTogglerPrefUi = new FlagTogglerPrefUi(this); mFlagTogglerPrefUi.applyTo(newCategory("Feature flags")); mFlagTogglerPrefUi.applyTo(newCategory("Feature flags", "Long press to reset")); } @Override Loading quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,11 +16,13 @@ package com.android.launcher3.uioverrides.flags; import com.android.launcher3.config.FeatureFlags.FlagState; class DeviceFlag extends DebugFlag { private final boolean mDefaultValueInCode; public DeviceFlag(String key, String description, boolean defaultValue, DeviceFlag(String key, String description, FlagState defaultValue, boolean currentValue, boolean defaultValueInCode) { super(key, description, defaultValue, currentValue); mDefaultValueInCode = defaultValueInCode; Loading quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java +42 −13 Original line number Diff line number Diff line Loading @@ -17,11 +17,15 @@ package com.android.launcher3.uioverrides.flags; import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME; import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Process; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; Loading @@ -30,6 +34,7 @@ import android.widget.Toast; import androidx.preference.PreferenceDataStore; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceViewHolder; import androidx.preference.SwitchPreference; import com.android.launcher3.R; Loading Loading @@ -59,12 +64,7 @@ public final class FlagTogglerPrefUi { @Override public boolean getBoolean(String key, boolean defaultValue) { for (DebugFlag flag : FlagsFactory.getDebugFlags()) { if (flag.key.equals(key)) { return mSharedPreferences.getBoolean(key, flag.defaultValue); } } return defaultValue; return mSharedPreferences.getBoolean(key, defaultValue); } }; Loading @@ -87,18 +87,41 @@ public final class FlagTogglerPrefUi { : f1.key.compareToIgnoreCase(f2.key); }); // Ensure that teamfood flag comes on the top if (flags.remove(TEAMFOOD_FLAG)) { flags.add(0, (DebugFlag) TEAMFOOD_FLAG); } // For flag overrides we only want to store when the engineer chose to override the // flag with a different value than the default. That way, when we flip flags in // future, engineers will pick up the new value immediately. To accomplish this, we use a // custom preference data store. for (DebugFlag flag : flags) { SwitchPreference switchPreference = new SwitchPreference(mContext); SwitchPreference switchPreference = new SwitchPreference(mContext) { @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); holder.itemView.setOnLongClickListener(v -> { mSharedPreferences.edit().remove(flag.key).apply(); setChecked(getFlagStateFromSharedPrefs(flag)); updateSummary(this, flag); updateMenu(); return true; }); } }; switchPreference.setKey(flag.key); switchPreference.setDefaultValue(flag.defaultValue); switchPreference.setDefaultValue(FlagsFactory.getEnabledValue(flag.defaultValue)); switchPreference.setChecked(getFlagStateFromSharedPrefs(flag)); switchPreference.setTitle(flag.key); updateSummary(switchPreference, flag); switchPreference.setPreferenceDataStore(mDataStore); switchPreference.setOnPreferenceChangeListener((p, v) -> { new Handler().post(() -> updateSummary(switchPreference, flag)); return true; }); parent.addPreference(switchPreference); } updateMenu(); Loading @@ -108,10 +131,15 @@ public final class FlagTogglerPrefUi { * Updates the summary to show the description and whether the flag overrides the default value. */ private void updateSummary(SwitchPreference switchPreference, DebugFlag flag) { String onWarning = flag.defaultValue ? "" : "<b>OVERRIDDEN</b><br>"; String offWarning = flag.defaultValue ? "<b>OVERRIDDEN</b><br>" : ""; switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.description)); switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.description)); String summary = flag.defaultValue == TEAMFOOD ? "<font color='blue'><b>[TEAMFOOD]</b> </font>" : ""; if (mSharedPreferences.contains(flag.key)) { summary += "<font color='red'><b>[OVERRIDDEN]</b> </font>"; } if (!TextUtils.isEmpty(summary)) { summary += "<br>"; } switchPreference.setSummary(Html.fromHtml(summary + flag.description)); } private void updateMenu() { Loading Loading @@ -143,7 +171,8 @@ public final class FlagTogglerPrefUi { } private boolean getFlagStateFromSharedPrefs(DebugFlag flag) { return mDataStore.getBoolean(flag.key, flag.defaultValue); boolean defaultValue = FlagsFactory.getEnabledValue(flag.defaultValue); return mDataStore.getBoolean(flag.key, defaultValue); } private boolean anyChanged() { Loading quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java +38 −12 Original line number Diff line number Diff line Loading @@ -18,6 +18,10 @@ package com.android.launcher3.uioverrides.flags; import static android.app.ActivityThread.currentApplication; import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE; import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED; import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED; import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.content.Context; Loading @@ -26,8 +30,8 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.util.Log; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags.BooleanFlag; import com.android.launcher3.config.FeatureFlags.FlagState; import com.android.launcher3.config.FeatureFlags.IntFlag; import com.android.launcher3.util.ScreenOnTracker; Loading @@ -53,6 +57,9 @@ public class FlagsFactory { private static final List<DebugFlag> sDebugFlags = new ArrayList<>(); static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag( 0, "LAUNCHER_TEAMFOOD", DISABLED, "Enable this flag to opt-in all team food flags"); private final Set<String> mKeySet = new HashSet<>(); private boolean mRestartRequested = false; Loading @@ -64,35 +71,54 @@ public class FlagsFactory { NAMESPACE_LAUNCHER, UI_HELPER_EXECUTOR, this::onPropertiesChanged); } static boolean getEnabledValue(FlagState flagState) { if (IS_DEBUG_DEVICE) { switch (flagState) { case ENABLED: return true; case TEAMFOOD: return TEAMFOOD_FLAG.get(); default: return false; } } else { return flagState == ENABLED; } } /** * Creates a new debug flag * Creates a new debug flag. Debug flags always take their default value in release builds. On * dogfood builds, they can be manually turned on using the flag toggle UI. */ public static BooleanFlag getDebugFlag( int bugId, String key, boolean defaultValue, String description) { if (Utilities.IS_DEBUG_DEVICE) { int bugId, String key, FlagState flagState, String description) { if (IS_DEBUG_DEVICE) { SharedPreferences prefs = currentApplication() .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); boolean defaultValue = getEnabledValue(flagState); boolean currentValue = prefs.getBoolean(key, defaultValue); DebugFlag flag = new DebugFlag(key, description, defaultValue, currentValue); DebugFlag flag = new DebugFlag(key, description, flagState, currentValue); sDebugFlags.add(flag); return flag; } else { return new BooleanFlag(defaultValue); return new BooleanFlag(getEnabledValue(flagState)); } } /** * Creates a new release flag * Creates a new release flag. Release flags can be rolled out using server configurations and * also allow manual overrides on debug builds. */ public static BooleanFlag getReleaseFlag( int bugId, String key, boolean defaultValueInCode, String description) { int bugId, String key, FlagState flagState, String description) { INSTANCE.mKeySet.add(key); boolean defaultValueInCode = getEnabledValue(flagState); boolean defaultValue = DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValueInCode); if (Utilities.IS_DEBUG_DEVICE) { if (IS_DEBUG_DEVICE) { SharedPreferences prefs = currentApplication() .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); boolean currentValue = prefs.getBoolean(key, defaultValue); DebugFlag flag = new DeviceFlag(key, description, defaultValue, currentValue, DebugFlag flag = new DeviceFlag(key, description, flagState, currentValue, defaultValueInCode); sDebugFlags.add(flag); return flag; Loading @@ -111,7 +137,7 @@ public class FlagsFactory { } static List<DebugFlag> getDebugFlags() { if (!Utilities.IS_DEBUG_DEVICE) { if (!IS_DEBUG_DEVICE) { return Collections.emptyList(); } synchronized (sDebugFlags) { Loading @@ -123,7 +149,7 @@ public class FlagsFactory { * Dumps the current flags state to the print writer */ public static void dump(PrintWriter pw) { if (!Utilities.IS_DEBUG_DEVICE) { if (!IS_DEBUG_DEVICE) { return; } pw.println("DeviceFlags:"); Loading Loading
quickstep/src/com/android/launcher3/uioverrides/flags/DebugFlag.java +6 −2 Original line number Diff line number Diff line Loading @@ -15,16 +15,20 @@ */ package com.android.launcher3.uioverrides.flags; import androidx.annotation.NonNull; import com.android.launcher3.config.FeatureFlags.BooleanFlag; import com.android.launcher3.config.FeatureFlags.FlagState; class DebugFlag extends BooleanFlag { public final String key; public final String description; public final boolean defaultValue; @NonNull public final FlagState defaultValue; public DebugFlag(String key, String description, boolean defaultValue, boolean currentValue) { DebugFlag(String key, String description, FlagState defaultValue, boolean currentValue) { super(currentValue); this.key = key; this.defaultValue = defaultValue; Loading
quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsFragment.java +9 −1 Original line number Diff line number Diff line Loading @@ -39,6 +39,7 @@ import android.os.Build; import android.os.Bundle; import android.provider.Settings; import android.text.Editable; import android.text.TextUtils; import android.text.TextWatcher; import android.util.ArrayMap; import android.util.Pair; Loading Loading @@ -182,9 +183,16 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { } private PreferenceCategory newCategory(String title) { return newCategory(title, null); } private PreferenceCategory newCategory(String title, @Nullable String summary) { PreferenceCategory category = new PreferenceCategory(getContext()); category.setOrder(Preference.DEFAULT_ORDER); category.setTitle(title); if (!TextUtils.isEmpty(summary)) { category.setSummary(summary); } mPreferenceScreen.addPreference(category); return category; } Loading @@ -195,7 +203,7 @@ public class DeveloperOptionsFragment extends PreferenceFragmentCompat { } mFlagTogglerPrefUi = new FlagTogglerPrefUi(this); mFlagTogglerPrefUi.applyTo(newCategory("Feature flags")); mFlagTogglerPrefUi.applyTo(newCategory("Feature flags", "Long press to reset")); } @Override Loading
quickstep/src/com/android/launcher3/uioverrides/flags/DeviceFlag.java +3 −1 Original line number Diff line number Diff line Loading @@ -16,11 +16,13 @@ package com.android.launcher3.uioverrides.flags; import com.android.launcher3.config.FeatureFlags.FlagState; class DeviceFlag extends DebugFlag { private final boolean mDefaultValueInCode; public DeviceFlag(String key, String description, boolean defaultValue, DeviceFlag(String key, String description, FlagState defaultValue, boolean currentValue, boolean defaultValueInCode) { super(key, description, defaultValue, currentValue); mDefaultValueInCode = defaultValueInCode; Loading
quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java +42 −13 Original line number Diff line number Diff line Loading @@ -17,11 +17,15 @@ package com.android.launcher3.uioverrides.flags; import static com.android.launcher3.config.FeatureFlags.FLAGS_PREF_NAME; import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; import static com.android.launcher3.uioverrides.flags.FlagsFactory.TEAMFOOD_FLAG; import android.content.Context; import android.content.SharedPreferences; import android.os.Handler; import android.os.Process; import android.text.Html; import android.text.TextUtils; import android.util.Log; import android.view.Menu; import android.view.MenuItem; Loading @@ -30,6 +34,7 @@ import android.widget.Toast; import androidx.preference.PreferenceDataStore; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceGroup; import androidx.preference.PreferenceViewHolder; import androidx.preference.SwitchPreference; import com.android.launcher3.R; Loading Loading @@ -59,12 +64,7 @@ public final class FlagTogglerPrefUi { @Override public boolean getBoolean(String key, boolean defaultValue) { for (DebugFlag flag : FlagsFactory.getDebugFlags()) { if (flag.key.equals(key)) { return mSharedPreferences.getBoolean(key, flag.defaultValue); } } return defaultValue; return mSharedPreferences.getBoolean(key, defaultValue); } }; Loading @@ -87,18 +87,41 @@ public final class FlagTogglerPrefUi { : f1.key.compareToIgnoreCase(f2.key); }); // Ensure that teamfood flag comes on the top if (flags.remove(TEAMFOOD_FLAG)) { flags.add(0, (DebugFlag) TEAMFOOD_FLAG); } // For flag overrides we only want to store when the engineer chose to override the // flag with a different value than the default. That way, when we flip flags in // future, engineers will pick up the new value immediately. To accomplish this, we use a // custom preference data store. for (DebugFlag flag : flags) { SwitchPreference switchPreference = new SwitchPreference(mContext); SwitchPreference switchPreference = new SwitchPreference(mContext) { @Override public void onBindViewHolder(PreferenceViewHolder holder) { super.onBindViewHolder(holder); holder.itemView.setOnLongClickListener(v -> { mSharedPreferences.edit().remove(flag.key).apply(); setChecked(getFlagStateFromSharedPrefs(flag)); updateSummary(this, flag); updateMenu(); return true; }); } }; switchPreference.setKey(flag.key); switchPreference.setDefaultValue(flag.defaultValue); switchPreference.setDefaultValue(FlagsFactory.getEnabledValue(flag.defaultValue)); switchPreference.setChecked(getFlagStateFromSharedPrefs(flag)); switchPreference.setTitle(flag.key); updateSummary(switchPreference, flag); switchPreference.setPreferenceDataStore(mDataStore); switchPreference.setOnPreferenceChangeListener((p, v) -> { new Handler().post(() -> updateSummary(switchPreference, flag)); return true; }); parent.addPreference(switchPreference); } updateMenu(); Loading @@ -108,10 +131,15 @@ public final class FlagTogglerPrefUi { * Updates the summary to show the description and whether the flag overrides the default value. */ private void updateSummary(SwitchPreference switchPreference, DebugFlag flag) { String onWarning = flag.defaultValue ? "" : "<b>OVERRIDDEN</b><br>"; String offWarning = flag.defaultValue ? "<b>OVERRIDDEN</b><br>" : ""; switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.description)); switchPreference.setSummaryOff(Html.fromHtml(offWarning + flag.description)); String summary = flag.defaultValue == TEAMFOOD ? "<font color='blue'><b>[TEAMFOOD]</b> </font>" : ""; if (mSharedPreferences.contains(flag.key)) { summary += "<font color='red'><b>[OVERRIDDEN]</b> </font>"; } if (!TextUtils.isEmpty(summary)) { summary += "<br>"; } switchPreference.setSummary(Html.fromHtml(summary + flag.description)); } private void updateMenu() { Loading Loading @@ -143,7 +171,8 @@ public final class FlagTogglerPrefUi { } private boolean getFlagStateFromSharedPrefs(DebugFlag flag) { return mDataStore.getBoolean(flag.key, flag.defaultValue); boolean defaultValue = FlagsFactory.getEnabledValue(flag.defaultValue); return mDataStore.getBoolean(flag.key, defaultValue); } private boolean anyChanged() { Loading
quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java +38 −12 Original line number Diff line number Diff line Loading @@ -18,6 +18,10 @@ package com.android.launcher3.uioverrides.flags; import static android.app.ActivityThread.currentApplication; import static com.android.launcher3.BuildConfig.IS_DEBUG_DEVICE; import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED; import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED; import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import android.content.Context; Loading @@ -26,8 +30,8 @@ import android.provider.DeviceConfig; import android.provider.DeviceConfig.Properties; import android.util.Log; import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags.BooleanFlag; import com.android.launcher3.config.FeatureFlags.FlagState; import com.android.launcher3.config.FeatureFlags.IntFlag; import com.android.launcher3.util.ScreenOnTracker; Loading @@ -53,6 +57,9 @@ public class FlagsFactory { private static final List<DebugFlag> sDebugFlags = new ArrayList<>(); static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag( 0, "LAUNCHER_TEAMFOOD", DISABLED, "Enable this flag to opt-in all team food flags"); private final Set<String> mKeySet = new HashSet<>(); private boolean mRestartRequested = false; Loading @@ -64,35 +71,54 @@ public class FlagsFactory { NAMESPACE_LAUNCHER, UI_HELPER_EXECUTOR, this::onPropertiesChanged); } static boolean getEnabledValue(FlagState flagState) { if (IS_DEBUG_DEVICE) { switch (flagState) { case ENABLED: return true; case TEAMFOOD: return TEAMFOOD_FLAG.get(); default: return false; } } else { return flagState == ENABLED; } } /** * Creates a new debug flag * Creates a new debug flag. Debug flags always take their default value in release builds. On * dogfood builds, they can be manually turned on using the flag toggle UI. */ public static BooleanFlag getDebugFlag( int bugId, String key, boolean defaultValue, String description) { if (Utilities.IS_DEBUG_DEVICE) { int bugId, String key, FlagState flagState, String description) { if (IS_DEBUG_DEVICE) { SharedPreferences prefs = currentApplication() .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); boolean defaultValue = getEnabledValue(flagState); boolean currentValue = prefs.getBoolean(key, defaultValue); DebugFlag flag = new DebugFlag(key, description, defaultValue, currentValue); DebugFlag flag = new DebugFlag(key, description, flagState, currentValue); sDebugFlags.add(flag); return flag; } else { return new BooleanFlag(defaultValue); return new BooleanFlag(getEnabledValue(flagState)); } } /** * Creates a new release flag * Creates a new release flag. Release flags can be rolled out using server configurations and * also allow manual overrides on debug builds. */ public static BooleanFlag getReleaseFlag( int bugId, String key, boolean defaultValueInCode, String description) { int bugId, String key, FlagState flagState, String description) { INSTANCE.mKeySet.add(key); boolean defaultValueInCode = getEnabledValue(flagState); boolean defaultValue = DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, defaultValueInCode); if (Utilities.IS_DEBUG_DEVICE) { if (IS_DEBUG_DEVICE) { SharedPreferences prefs = currentApplication() .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE); boolean currentValue = prefs.getBoolean(key, defaultValue); DebugFlag flag = new DeviceFlag(key, description, defaultValue, currentValue, DebugFlag flag = new DeviceFlag(key, description, flagState, currentValue, defaultValueInCode); sDebugFlags.add(flag); return flag; Loading @@ -111,7 +137,7 @@ public class FlagsFactory { } static List<DebugFlag> getDebugFlags() { if (!Utilities.IS_DEBUG_DEVICE) { if (!IS_DEBUG_DEVICE) { return Collections.emptyList(); } synchronized (sDebugFlags) { Loading @@ -123,7 +149,7 @@ public class FlagsFactory { * Dumps the current flags state to the print writer */ public static void dump(PrintWriter pw) { if (!Utilities.IS_DEBUG_DEVICE) { if (!IS_DEBUG_DEVICE) { return; } pw.println("DeviceFlags:"); Loading