Moving various nav-bar configs out of feature flags
Bug: 332588958
Test: Presubmit
Flag: None
Change-Id: Ia4dc5b69bcf4d461e3444b9e37bb7334bb74aae4
diff --git a/OWNERS b/OWNERS
index dd2d00e..654493f 100644
--- a/OWNERS
+++ b/OWNERS
@@ -45,3 +45,6 @@
per-file FeatureFlags.java, globs = set noparent
per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com, captaincole@google.com
+
+per-file DeviceConfigWrapper.java, globs = set noparent
+per-file DeviceConfigWrapper.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index be532b4..0697f47 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -173,6 +173,7 @@
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map.Entry;
/**
* Manages the opening and closing app transitions from Launcher
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
new file mode 100644
index 0000000..6b44ca7
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DevOptionsUiHelper.kt
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2024 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.uioverrides.flags
+
+import android.os.Handler
+import android.provider.DeviceConfig
+import android.text.Html
+import android.view.inputmethod.EditorInfo
+import androidx.preference.Preference
+import androidx.preference.PreferenceGroup
+import androidx.preference.PreferenceViewHolder
+import androidx.preference.SwitchPreference
+import com.android.launcher3.ExtendedEditText
+import com.android.launcher3.R
+import com.android.quickstep.util.DeviceConfigHelper
+import com.android.quickstep.util.DeviceConfigHelper.Companion.NAMESPACE_LAUNCHER
+import com.android.quickstep.util.DeviceConfigHelper.DebugInfo
+
+/** Helper class to generate UI for Device Config */
+class DevOptionsUiHelper {
+
+ /** Inflates preferences for all server flags in the provider PreferenceGroup */
+ fun inflateServerFlags(parent: PreferenceGroup) {
+ val prefs = DeviceConfigHelper.prefs
+ // Sort the keys in the order of modified first followed by natural order
+ val allProps =
+ DeviceConfigHelper.allProps.values
+ .toList()
+ .sortedWith(
+ Comparator.comparingInt { prop: DebugInfo<*> ->
+ if (prefs.contains(prop.key)) 0 else 1
+ }
+ .thenComparing { prop: DebugInfo<*> -> prop.key }
+ )
+
+ // First add boolean flags
+ allProps.forEach {
+ if (it.isInt) return@forEach
+ val info = it as DebugInfo<Boolean>
+
+ val preference =
+ object : SwitchPreference(parent.context) {
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ holder.itemView.setOnLongClickListener {
+ prefs.edit().remove(key).apply()
+ setChecked(info.getBoolValue())
+ summary = info.getSummary()
+ true
+ }
+ }
+ }
+ preference.key = info.key
+ preference.isPersistent = false
+ preference.title = info.key
+ preference.summary = info.getSummary()
+ preference.setChecked(prefs.getBoolean(info.key, info.getBoolValue()))
+ preference.setOnPreferenceChangeListener { _, newVal ->
+ DeviceConfigHelper.prefs.edit().putBoolean(info.key, newVal as Boolean).apply()
+ preference.summary = info.getSummary()
+ true
+ }
+ parent.addPreference(preference)
+ }
+
+ // Apply Int flags
+ allProps.forEach {
+ if (!it.isInt) return@forEach
+ val info = it as DebugInfo<Int>
+
+ val preference =
+ object : Preference(parent.context) {
+ override fun onBindViewHolder(holder: PreferenceViewHolder) {
+ super.onBindViewHolder(holder)
+ val textView = holder.findViewById(R.id.pref_edit_text) as ExtendedEditText
+ textView.setText(info.getIntValueAsString())
+ textView.setOnEditorActionListener { _, actionId, _ ->
+ if (actionId == EditorInfo.IME_ACTION_DONE) {
+ DeviceConfigHelper.prefs
+ .edit()
+ .putInt(key, textView.text.toString().toInt())
+ .apply()
+ Handler().post { summary = info.getSummary() }
+ true
+ }
+ false
+ }
+ textView.setOnBackKeyListener {
+ textView.setText(info.getIntValueAsString())
+ true
+ }
+
+ holder.itemView.setOnLongClickListener {
+ prefs.edit().remove(key).apply()
+ textView.setText(info.getIntValueAsString())
+ summary = info.getSummary()
+ true
+ }
+ }
+ }
+ preference.key = info.key
+ preference.isPersistent = false
+ preference.title = info.key
+ preference.summary = info.getSummary()
+ preference.widgetLayoutResource = R.layout.develop_options_edit_text
+ parent.addPreference(preference)
+ }
+ }
+
+ /**
+ * Returns the summary to show the description and whether the flag overrides the default value.
+ */
+ private fun DebugInfo<*>.getSummary() =
+ Html.fromHtml(
+ (if (DeviceConfigHelper.prefs.contains(this.key))
+ "<font color='red'><b>[OVERRIDDEN]</b></font><br>"
+ else "") + this.desc
+ )
+
+ private fun DebugInfo<Boolean>.getBoolValue() =
+ DeviceConfigHelper.prefs.getBoolean(
+ this.key,
+ DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, this.key, this.valueInCode)
+ )
+
+ private fun DebugInfo<Int>.getIntValueAsString() =
+ DeviceConfigHelper.prefs
+ .getInt(this.key, DeviceConfig.getInt(NAMESPACE_LAUNCHER, this.key, this.valueInCode))
+ .toString()
+
+ companion object {
+ const val TAG = "DeviceConfigUIHelper"
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
index 6713964..fd6bf4d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
@@ -20,19 +20,8 @@
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
-import static com.android.launcher3.LauncherPrefs.PRIVATE_SPACE_APPS;
-import static com.android.launcher3.config.FeatureFlags.LPNH_EXTRA_TOUCH_WIDTH_DP;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_DELAY;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_END_SCALE_PERCENT;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_ITERATIONS;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_SCALE_EXPONENT;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_START_SCALE_PERCENT;
-import static com.android.launcher3.config.FeatureFlags.LPNH_SLOP_PERCENTAGE;
-import static com.android.launcher3.config.FeatureFlags.LPNH_TIMEOUT_MS;
import static com.android.launcher3.settings.SettingsActivity.EXTRA_FRAGMENT_HIGHLIGHT_KEY;
import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.PLUGIN_CHANGED;
-import static com.android.launcher3.uioverrides.plugins.PluginManagerWrapper.pluginEnabledKey;
import static com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_COUNT;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
@@ -51,7 +40,6 @@
import android.text.Editable;
import android.text.TextWatcher;
import android.util.ArrayMap;
-import android.util.Log;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
@@ -61,21 +49,18 @@
import androidx.preference.Preference;
import androidx.preference.PreferenceCategory;
-import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceScreen;
import androidx.preference.PreferenceViewHolder;
-import androidx.preference.SeekBarPreference;
import androidx.preference.SwitchPreference;
-import com.android.launcher3.ConstantItem;
-import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.secondarydisplay.SecondaryDisplayLauncher;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.systemui.shared.plugins.PluginEnabler;
import java.util.ArrayList;
import java.util.List;
@@ -96,8 +81,6 @@
private final PreferenceFragmentCompat mFragment;
private final PreferenceScreen mPreferenceScreen;
- private final FlagTogglerPrefUi mFlagTogglerPrefUi;
-
private PreferenceCategory mPluginsCategory;
public DeveloperOptionsUI(PreferenceFragmentCompat fragment, PreferenceCategory flags) {
@@ -112,20 +95,14 @@
parent.addView(topBar, parent.indexOfChild(listView));
initSearch(topBar.findViewById(R.id.filter_box));
- mFlagTogglerPrefUi = new FlagTogglerPrefUi(mFragment.requireActivity(),
- topBar.findViewById(R.id.flag_apply_btn));
- mFlagTogglerPrefUi.applyTo(flags);
+ new FlagTogglerPrefUi(mFragment.requireActivity(), topBar.findViewById(R.id.flag_apply_btn))
+ .applyTo(flags);
+ DevOptionsUiHelper uiHelper = new DevOptionsUiHelper();
+ uiHelper.inflateServerFlags(newCategory("Server flags"));
loadPluginPrefs();
maybeAddSandboxCategory();
addOnboardingPrefsCatergory();
- if (FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()) {
- addAllAppsFromOverviewCatergory();
- }
- addCustomLpnhCategory();
- if (Flags.enablePrivateSpace()) {
- addCustomPrivateAppsCategory();
- }
}
private void filterPreferences(String query, PreferenceGroup pg) {
@@ -205,7 +182,7 @@
new ArrayMap<>();
Set<String> pluginPermissionApps = pm.getPackagesHoldingPermissions(
- new String[]{PLUGIN_PERMISSION}, MATCH_DISABLED_COMPONENTS)
+ new String[]{PLUGIN_PERMISSION}, MATCH_DISABLED_COMPONENTS)
.stream()
.map(pi -> pi.packageName)
.collect(Collectors.toSet());
@@ -228,7 +205,7 @@
}
}
- PreferenceDataStore enabler = manager.getPluginEnabler();
+ PluginEnabler enabler = manager.getPluginEnabler();
plugins.forEach((key, si) -> {
String packageName = key.first;
List<ComponentName> componentNames = si.stream()
@@ -347,111 +324,10 @@
return onboardingPref;
}
- private void addAllAppsFromOverviewCatergory() {
- PreferenceCategory category = newCategory("All Apps from Overview Config");
- category.addPreference(createSeekBarPreference("Threshold to open All Apps from Overview",
- 105, 500, 100, ALL_APPS_OVERVIEW_THRESHOLD));
- }
-
- private void addCustomLpnhCategory() {
- PreferenceCategory category = newCategory("Long Press Nav Handle Config");
- if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
- category.addPreference(createSeekBarPreference(
- "Slop multiplier (applied to edge slop, "
- + "which is generally already 50% higher than touch slop)",
- 25, 200, 100, LPNH_SLOP_PERCENTAGE));
- category.addPreference(createSeekBarPreference(
- "Extra width DP (how far outside the sides of the nav bar to trigger)",
- // Stashed taskbar is currently 220dp; -86 (x2) would result in 48dp touch area.
- -86, 100, 1, LPNH_EXTRA_TOUCH_WIDTH_DP));
- category.addPreference(createSeekBarPreference("LPNH timeout",
- 100, 500, 1, LPNH_TIMEOUT_MS));
- }
- if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get()) {
- category.addPreference(
- createSeekBarPreference("Haptic hint start scale",
- 0, 100, 100, LPNH_HAPTIC_HINT_START_SCALE_PERCENT));
- category.addPreference(createSeekBarPreference("Haptic hint end scale",
- 0, 100, 100, LPNH_HAPTIC_HINT_END_SCALE_PERCENT));
- category.addPreference(
- createSeekBarPreference("Haptic hint scale exponent",
- 1, 5, 1, LPNH_HAPTIC_HINT_SCALE_EXPONENT));
- category.addPreference(
- createSeekBarPreference("Haptic hint iterations (12 ms each)",
- 0, 200, 1, LPNH_HAPTIC_HINT_ITERATIONS));
- category.addPreference(createSeekBarPreference("Haptic hint delay (ms)",
- 0, 400, 1, LPNH_HAPTIC_HINT_DELAY));
- }
- }
-
- private void addCustomPrivateAppsCategory() {
- PreferenceCategory category = newCategory("Apps in Private Space Config");
- category.addPreference(createSeekBarPreference(
- "Number of Apps to put in private region", 0, 100, 1, PRIVATE_SPACE_APPS));
- }
-
- private SeekBarPreference createSeekBarPreference(String title, int min,
- int max, int scale, FeatureFlags.IntFlag flag) {
- if (!(flag instanceof IntDebugFlag)) {
- Log.e(TAG, "Cannot create seekbar preference with IntFlag. Use a launcher preference "
- + "flag or pref-backed IntDebugFlag instead");
- return null;
- }
- IntDebugFlag debugflag = (IntDebugFlag) flag;
- if (debugflag.launcherPrefFlag == null) {
- Log.e(TAG, "Cannot create seekbar preference with IntDebugFlag. Use a launcher "
- + "preference flag or pref-backed IntDebugFlag instead");
- return null;
- }
- SeekBarPreference seekBarPref = createSeekBarPreference(title, min, max, scale,
- debugflag.launcherPrefFlag);
- int value = flag.get();
- seekBarPref.setValue(value);
- // For some reason the initial value is not triggering the summary update, so call manually.
- seekBarPref.setSummary(String.valueOf(scale == 1 ? value
- : value / (float) scale));
- return seekBarPref;
- }
-
- /**
- * Create a preference with text and a seek bar. Should be added to a PreferenceCategory.
- *
- * @param title text to show for this seek bar
- * @param min min value for the seek bar
- * @param max max value for the seek bar
- * @param scale how much to divide the value to convert int to float
- * @param launcherPref used to store the current value
- */
- private SeekBarPreference createSeekBarPreference(String title, int min, int max, int scale,
- ConstantItem<Integer> launcherPref) {
- SeekBarPreference seekBarPref = new SeekBarPreference(getContext());
- seekBarPref.setTitle(title);
- seekBarPref.setSingleLineTitle(false);
-
- seekBarPref.setMax(max);
- seekBarPref.setMin(min);
- seekBarPref.setUpdatesContinuously(true);
- seekBarPref.setIconSpaceReserved(false);
- // Don't directly save to shared prefs, use LauncherPrefs instead.
- seekBarPref.setPersistent(false);
- seekBarPref.setOnPreferenceChangeListener((preference, newValue) -> {
- LauncherPrefs.get(getContext()).put(launcherPref, newValue);
- preference.setSummary(String.valueOf(scale == 1 ? newValue
- : (int) newValue / (float) scale));
- mFlagTogglerPrefUi.updateMenu();
- return true;
- });
- int value = LauncherPrefs.get(getContext()).get(launcherPref);
- seekBarPref.setValue(value);
- // For some reason the initial value is not triggering the summary update, so call manually.
- seekBarPref.setSummary(String.valueOf(scale == 1 ? value
- : value / (float) scale));
- return seekBarPref;
- }
-
private String toName(String action) {
String str = action.replace("com.android.systemui.action.PLUGIN_", "")
.replace("com.android.launcher3.action.PLUGIN_", "");
+
StringBuilder b = new StringBuilder();
for (String s : str.split("_")) {
if (b.length() != 0) {
@@ -466,11 +342,11 @@
private static class PluginPreference extends SwitchPreference {
private final String mPackageName;
private final ResolveInfo mSettingsInfo;
- private final PreferenceDataStore mPluginEnabler;
+ private final PluginEnabler mPluginEnabler;
private final List<ComponentName> mComponentNames;
PluginPreference(Context prefContext, ResolveInfo pluginInfo,
- PreferenceDataStore pluginEnabler, List<ComponentName> componentNames) {
+ PluginEnabler pluginEnabler, List<ComponentName> componentNames) {
super(prefContext);
PackageManager pm = prefContext.getPackageManager();
mPackageName = pluginInfo.serviceInfo.applicationInfo.packageName;
@@ -495,14 +371,9 @@
setWidgetLayoutResource(R.layout.switch_preference_with_settings);
}
- private boolean isEnabled(ComponentName cn) {
- return mPluginEnabler.getBoolean(pluginEnabledKey(cn), true);
-
- }
-
private boolean isPluginEnabled() {
for (ComponentName componentName : mComponentNames) {
- if (!isEnabled(componentName)) {
+ if (!mPluginEnabler.isEnabled(componentName)) {
return false;
}
}
@@ -513,8 +384,9 @@
protected boolean persistBoolean(boolean isEnabled) {
boolean shouldSendBroadcast = false;
for (ComponentName componentName : mComponentNames) {
- if (isEnabled(componentName) != isEnabled) {
- mPluginEnabler.putBoolean(pluginEnabledKey(componentName), isEnabled);
+ if (mPluginEnabler.isEnabled(componentName) != isEnabled) {
+ mPluginEnabler.setDisabled(componentName,
+ isEnabled ? PluginEnabler.ENABLED : PluginEnabler.DISABLED_MANUALLY);
shouldSendBroadcast = true;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
index 4326c67..fc39ce4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagTogglerPrefUi.java
@@ -34,7 +34,6 @@
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreference;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
@@ -162,22 +161,12 @@
return mDataStore.getBoolean(flag.key, defaultValue);
}
- private int getIntFlagStateFromSharedPrefs(IntDebugFlag flag) {
- LauncherPrefs prefs = LauncherPrefs.get(mContext);
- return flag.launcherPrefFlag == null ? flag.get() : prefs.get(flag.launcherPrefFlag);
- }
-
private boolean anyChanged() {
for (DebugFlag flag : FlagsFactory.getDebugFlags()) {
if (getFlagStateFromSharedPrefs(flag) != flag.get()) {
return true;
}
}
- for (IntDebugFlag flag : FlagsFactory.getIntDebugFlags()) {
- if (getIntFlagStateFromSharedPrefs(flag) != flag.get()) {
- return true;
- }
- }
return false;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index 686ed64..7fd6344 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -23,8 +23,6 @@
import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static java.util.Collections.unmodifiableList;
-
import android.content.Context;
import android.content.SharedPreferences;
import android.provider.DeviceConfig;
@@ -32,13 +30,9 @@
import android.util.Log;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import com.android.launcher3.ConstantItem;
-import com.android.launcher3.LauncherPrefs;
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;
import java.io.PrintWriter;
@@ -62,7 +56,6 @@
public static final String NAMESPACE_LAUNCHER = "launcher";
private static final List<DebugFlag> sDebugFlags = new ArrayList<>();
- private static final List<IntDebugFlag> sIntDebugFlags = new ArrayList<>();
private static SharedPreferences sSharedPreferences;
static final BooleanFlag TEAMFOOD_FLAG = getReleaseFlag(
@@ -132,42 +125,6 @@
}
}
- /**
- * Creates a new integer flag. Integer flags are always release flags
- */
- public static IntFlag getIntFlag(
- int bugId, String key, int defaultValueInCode, String description) {
- return getIntFlag(bugId, key, defaultValueInCode, description, null);
- }
-
- /**
- * Creates a new integer flag.
- *
- * @param launcherPrefFlag Set launcherPrefFlag to non-null if you want
- * to modify the int flag in Launcher Developer Options and IntDebugFlag
- * will be backed up by LauncherPrefs. Modified int value will be saved
- * in LauncherPrefs.
- */
- public static IntFlag getIntFlag(
- int bugId, String key, int defaultValueInCode, String description,
- @Nullable ConstantItem<Integer> launcherPrefFlag) {
- INSTANCE.mKeySet.add(key);
- int defaultValue = DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, defaultValueInCode);
- if (IS_DEBUG_DEVICE) {
- int currentValue;
- if (launcherPrefFlag == null) {
- currentValue = defaultValue;
- } else {
- currentValue = LauncherPrefs.get(currentApplication()).get(launcherPrefFlag);
- }
- IntDebugFlag flag = new IntDebugFlag(key, currentValue, defaultValueInCode,
- launcherPrefFlag);
- sIntDebugFlags.add(flag);
- return flag;
- } else {
- return new IntFlag(defaultValue);
- }
- }
static List<DebugFlag> getDebugFlags() {
if (!IS_DEBUG_DEVICE) {
@@ -178,15 +135,6 @@
}
}
- static List<IntDebugFlag> getIntDebugFlags() {
- if (!IS_DEBUG_DEVICE) {
- return unmodifiableList(Collections.emptyList());
- }
- synchronized (sIntDebugFlags) {
- return unmodifiableList(sIntDebugFlags);
- }
- }
-
/** Returns the SharedPreferences instance backing Debug FeatureFlags. */
@NonNull
static SharedPreferences getSharedPreferences() {
@@ -214,12 +162,6 @@
}
}
}
- pw.println(" IntFlags:");
- synchronized (sIntDebugFlags) {
- for (IntFlag flag : sIntDebugFlags) {
- pw.println(" " + flag);
- }
- }
pw.println(" DebugFlags:");
synchronized (sDebugFlags) {
for (DebugFlag flag : sDebugFlags) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/IntDebugFlag.java b/quickstep/src/com/android/launcher3/uioverrides/flags/IntDebugFlag.java
deleted file mode 100644
index 1350aa8..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/IntDebugFlag.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * 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.launcher3.uioverrides.flags;
-
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.ConstantItem;
-import com.android.launcher3.config.FeatureFlags.IntFlag;
-
-public class IntDebugFlag extends IntFlag {
- public final String key;
- private final int mDefaultValueInCode;
- @Nullable
- public final ConstantItem<Integer> launcherPrefFlag;
-
- public IntDebugFlag(String key, int currentValue, int defaultValueInCode,
- @Nullable ConstantItem<Integer> launcherPrefFlag) {
- super(currentValue);
- this.key = key;
- mDefaultValueInCode = defaultValueInCode;
- this.launcherPrefFlag = launcherPrefFlag;
- }
-
- @Override
- public String toString() {
- return key + ": mCurrentValue=" + get() + ", defaultValueInCode=" + mDefaultValueInCode;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
index faa900b..4e09f1f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginEnablerImpl.java
@@ -18,12 +18,10 @@
import android.content.Context;
import android.content.SharedPreferences;
-import androidx.preference.PreferenceDataStore;
-
import com.android.launcher3.LauncherPrefs;
import com.android.systemui.shared.plugins.PluginEnabler;
-public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnabler {
+public class PluginEnablerImpl implements PluginEnabler {
private static final String PREFIX_PLUGIN_ENABLED = "PLUGIN_ENABLED_";
@@ -44,12 +42,12 @@
}
private void setState(ComponentName component, boolean enabled) {
- putBoolean(pluginEnabledKey(component), enabled);
+ mSharedPrefs.edit().putBoolean(pluginEnabledKey(component), enabled).apply();
}
@Override
public boolean isEnabled(ComponentName component) {
- return getBoolean(pluginEnabledKey(component), true);
+ return mSharedPrefs.getBoolean(pluginEnabledKey(component), true);
}
@Override
@@ -57,17 +55,7 @@
return isEnabled(componentName) ? ENABLED : DISABLED_MANUALLY;
}
- @Override
- public void putBoolean(String key, boolean value) {
- mSharedPrefs.edit().putBoolean(key, value).apply();
- }
-
- @Override
- public boolean getBoolean(String key, boolean defValue) {
- return mSharedPrefs.getBoolean(key, defValue);
- }
-
- static String pluginEnabledKey(ComponentName cn) {
+ private static String pluginEnabledKey(ComponentName cn) {
return PREFIX_PLUGIN_ENABLED + cn.flattenToString();
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
index 7f78713..a09d0a1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapper.java
@@ -98,13 +98,6 @@
return new PluginPrefs(mContext).getPluginList();
}
- /**
- * Returns the string key used to store plugin enabled/disabled setting
- */
- public static String pluginEnabledKey(ComponentName cn) {
- return PluginEnablerImpl.pluginEnabledKey(cn);
- }
-
public static boolean hasPlugins(Context context) {
return PluginPrefs.hasPlugins(context);
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 62e823a..7ee7751 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -22,8 +22,8 @@
import static android.widget.Toast.LENGTH_SHORT;
import static com.android.app.animation.Interpolators.ACCELERATE_DECELERATE;
-import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.DECELERATE;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.app.animation.Interpolators.OVERSHOOT_1_2;
import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
@@ -31,7 +31,6 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
-import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
import static com.android.launcher3.PagedView.INVALID_PAGE;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
@@ -100,7 +99,6 @@
import com.android.internal.util.LatencyTracker;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -892,7 +890,7 @@
@UiThread
@Override
public void onCurrentShiftUpdated() {
- float threshold = LauncherPrefs.get(mContext).get(ALL_APPS_OVERVIEW_THRESHOLD) / 100f;
+ float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f;
setIsInAllAppsRegion(mCurrentShift.value >= threshold);
updateSysUiFlags(mCurrentShift.value);
applyScrollAndTransform();
diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
new file mode 100644
index 0000000..678709c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2024 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.quickstep
+
+import com.android.quickstep.util.DeviceConfigHelper
+import com.android.quickstep.util.DeviceConfigHelper.PropReader
+import java.io.PrintWriter
+
+/** Various configurations specific to nav-bar functionalities */
+class DeviceConfigWrapper private constructor(propReader: PropReader) {
+
+ val customLpnhThresholds =
+ propReader.get(
+ "CUSTOM_LPNH_THRESHOLDS",
+ true,
+ "Add dev options and server side control to customize the LPNH trigger slop and milliseconds"
+ )
+
+ val customLphThresholds =
+ propReader.get(
+ "CUSTOM_LPH_THRESHOLDS",
+ false,
+ "Server side control to customize LPH timeout and touch slop"
+ )
+
+ val overrideLpnhLphThresholds =
+ propReader.get(
+ "OVERRIDE_LPNH_LPH_THRESHOLDS",
+ false,
+ "Enable AGSA override for LPNH and LPH timeout and touch slop"
+ )
+
+ val lpnhSlopPercentage =
+ propReader.get("LPNH_SLOP_PERCENTAGE", 100, "Controls touch slop percentage for lpnh")
+
+ val animateLpnh = propReader.get("ANIMATE_LPNH", false, "Animates navbar when long pressing")
+
+ val shrinkNavHandleOnPress =
+ propReader.get(
+ "SHRINK_NAV_HANDLE_ON_PRESS",
+ false,
+ "Shrinks navbar when long pressing if ANIMATE_LPNH is enabled"
+ )
+
+ val lpnhTimeoutMs =
+ propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds")
+
+ val enableLongPressNavHandle =
+ propReader.get(
+ "ENABLE_LONG_PRESS_NAV_HANDLE",
+ true,
+ "Enables long pressing on the bottom bar nav handle to trigger events."
+ )
+
+ val enableSearchHapticHint =
+ propReader.get(
+ "ENABLE_SEARCH_HAPTIC_HINT",
+ true,
+ "Enables haptic hint while long pressing on the bottom bar nav handle."
+ )
+
+ val enableSearchHapticCommit =
+ propReader.get(
+ "ENABLE_SEARCH_HAPTIC_COMMIT",
+ true,
+ "Enables haptic hint at end of long pressing on the bottom bar nav handle."
+ )
+
+ val lpnhHapticHintStartScalePercent =
+ propReader.get("LPNH_HAPTIC_HINT_START_SCALE_PERCENT", 0, "Haptic hint start scale.")
+
+ val lpnhHapticHintEndScalePercent =
+ propReader.get("LPNH_HAPTIC_HINT_END_SCALE_PERCENT", 100, "Haptic hint end scale.")
+
+ val lpnhHapticHintScaleExponent =
+ propReader.get("LPNH_HAPTIC_HINT_SCALE_EXPONENT", 1, "Haptic hint scale exponent.")
+
+ val lpnhHapticHintIterations =
+ propReader.get("LPNH_HAPTIC_HINT_ITERATIONS", 50, "Haptic hint number of iterations.")
+
+ val enableLpnhDeepPress =
+ propReader.get(
+ "ENABLE_LPNH_DEEP_PRESS",
+ true,
+ "Long press of nav handle is instantly triggered if deep press is detected."
+ )
+
+ val lpnhHapticHintDelay =
+ propReader.get("LPNH_HAPTIC_HINT_DELAY", 0, "Delay before haptic hint starts.")
+
+ val lpnhExtraTouchWidthDp =
+ propReader.get(
+ "LPNH_EXTRA_TOUCH_WIDTH_DP",
+ 0,
+ "Controls extra dp on the nav bar sides to trigger LPNH. Can be negative for a smaller touch region."
+ )
+
+ val allAppsOverviewThreshold =
+ propReader.get(
+ "ALL_APPS_OVERVIEW_THRESHOLD",
+ 180,
+ "Threshold to open All Apps from Overview"
+ )
+
+ /** Dump config values. */
+ fun dump(prefix: String, writer: PrintWriter) {
+ writer.println("$prefix DeviceConfigWrapper:")
+ writer.println("$prefix\tcustomLpnhThresholds=$customLpnhThresholds")
+ writer.println("$prefix\tcustomLphThresholds=$customLphThresholds")
+ writer.println("$prefix\toverrideLpnhLphThresholds=$overrideLpnhLphThresholds")
+ writer.println("$prefix\tlpnhSlopPercentage=$lpnhSlopPercentage")
+ writer.println("$prefix\tanimateLpnh=$animateLpnh")
+ writer.println("$prefix\tshrinkNavHandleOnPress=$shrinkNavHandleOnPress")
+ writer.println("$prefix\tlpnhTimeoutMs=$lpnhTimeoutMs")
+ writer.println("$prefix\tenableLongPressNavHandle=$enableLongPressNavHandle")
+ writer.println("$prefix\tenableSearchHapticHint=$enableSearchHapticHint")
+ writer.println("$prefix\tenableSearchHapticCommit=$enableSearchHapticCommit")
+ writer.println("$prefix\tlpnhHapticHintStartScalePercent=$lpnhHapticHintStartScalePercent")
+ writer.println("$prefix\tlpnhHapticHintEndScalePercent=$lpnhHapticHintEndScalePercent")
+ writer.println("$prefix\tlpnhHapticHintScaleExponent=$lpnhHapticHintScaleExponent")
+ writer.println("$prefix\tlpnhHapticHintIterations=$lpnhHapticHintIterations")
+ writer.println("$prefix\tenableLpnhDeepPress=$enableLpnhDeepPress")
+ writer.println("$prefix\tlpnhHapticHintDelay=$lpnhHapticHintDelay")
+ writer.println("$prefix\tlpnhExtraTouchWidthDp=$lpnhExtraTouchWidthDp")
+ writer.println("$prefix\tallAppsOverviewThreshold=$allAppsOverviewThreshold")
+ }
+
+ companion object {
+ val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
+
+ @JvmStatic fun get() = configHelper.config
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index c56a621..43e564c 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -60,7 +60,6 @@
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
@@ -588,9 +587,8 @@
: QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON;
float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
- float customSlopMultiplier =
- FeatureFlags.LPNH_SLOP_PERCENTAGE.get() / 100f;
+ if (DeviceConfigWrapper.get().getCustomLpnhThresholds()) {
+ float customSlopMultiplier = DeviceConfigWrapper.get().getLpnhSlopPercentage() / 100f;
return customSlopMultiplier * slopMultiplier * touchSlop;
} else {
return slopMultiplier * touchSlop;
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 66d7144..f2ee3f1 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -1456,6 +1456,7 @@
pw.println("AssistStateManager:");
AssistStateManager.INSTANCE.get(this).dump(" ", pw);
SystemUiProxy.INSTANCE.get(this).dump(pw);
+ DeviceConfigWrapper.get().dump(" ", pw);
}
private AbsSwipeUpHandler createLauncherSwipeHandler(
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index e22703b..5ab2fcc 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -27,9 +27,9 @@
import android.view.ViewConfiguration;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.DeviceConfigWrapper;
import com.android.quickstep.InputConsumer;
import com.android.quickstep.NavHandle;
import com.android.quickstep.RecentsAnimationDeviceState;
@@ -64,7 +64,7 @@
NavHandle navHandle) {
super(delegate, inputMonitor);
mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
- mDeepPressEnabled = FeatureFlags.ENABLE_LPNH_DEEP_PRESS.get();
+ mDeepPressEnabled = DeviceConfigWrapper.get().getEnableLpnhDeepPress();
AssistStateManager assistStateManager = AssistStateManager.INSTANCE.get(context);
if (assistStateManager.getLPNHDurationMillis().isPresent()) {
mLongPressTimeout = assistStateManager.getLPNHDurationMillis().get().intValue();
@@ -181,8 +181,9 @@
private boolean isInNavBarHorizontalArea(float x) {
float areaFromMiddle = mNavHandleWidth / 2.0f;
- if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
- areaFromMiddle += Utilities.dpToPx(FeatureFlags.LPNH_EXTRA_TOUCH_WIDTH_DP.get());
+ if (DeviceConfigWrapper.get().getCustomLpnhThresholds()) {
+ areaFromMiddle += Utilities.dpToPx(
+ DeviceConfigWrapper.get().getLpnhExtraTouchWidthDp());
}
int minAccessibleSize = Utilities.dpToPx(24); // Half of 48dp because this is per side.
if (areaFromMiddle < minAccessibleSize) {
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index 16f2065..561e951 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -18,7 +18,6 @@
import static com.android.app.animation.Interpolators.DECELERATE;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
-import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -35,7 +34,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -44,6 +42,7 @@
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
+import com.android.quickstep.DeviceConfigWrapper;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.views.RecentsView;
@@ -191,7 +190,7 @@
recentsOrientedState.getOrientationHandler());
float dragLengthFactor = (float) dp.heightPx / transitionDragLength;
// -1s are because 0-1 is reserved for the normal transition.
- float threshold = LauncherPrefs.get(context).get(ALL_APPS_OVERVIEW_THRESHOLD) / 100f;
+ float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f;
return (threshold - 1) / (dragLengthFactor - 1);
}
diff --git a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
new file mode 100644
index 0000000..f601fee
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 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.quickstep.util
+
+import android.app.ActivityThread
+import android.content.Context
+import android.content.SharedPreferences
+import android.content.SharedPreferences.*
+import android.provider.DeviceConfig
+import android.provider.DeviceConfig.OnPropertiesChangedListener
+import android.provider.DeviceConfig.Properties
+import androidx.annotation.WorkerThread
+import com.android.launcher3.BuildConfig
+import com.android.launcher3.uioverrides.flags.FlagsFactory
+import com.android.launcher3.util.Executors
+
+/** Utility class to manage a set of device configurations */
+class DeviceConfigHelper<ConfigType>(private val factory: (PropReader) -> ConfigType) {
+
+ var config: ConfigType
+ private set
+ private val allKeys: Set<String>
+ private val propertiesListener = OnPropertiesChangedListener { onDevicePropsChanges(it) }
+ private val sharedPrefChangeListener = OnSharedPreferenceChangeListener { _, _ ->
+ recreateConfig()
+ }
+
+ private val changeListeners = mutableListOf<Runnable>()
+
+ init {
+ // Initialize the default config once.
+ allKeys = HashSet()
+ config =
+ factory(
+ PropReader(
+ object : PropProvider {
+ override fun <T : Any> get(key: String, fallback: T): T {
+ if (fallback is Int)
+ return DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, fallback) as T
+ else if (fallback is Boolean)
+ return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, fallback)
+ as T
+ else return fallback
+ }
+ }
+ )
+ )
+
+ DeviceConfig.addOnPropertiesChangedListener(
+ NAMESPACE_LAUNCHER,
+ Executors.UI_HELPER_EXECUTOR,
+ propertiesListener
+ )
+ if (BuildConfig.IS_DEBUG_DEVICE) {
+ prefs.registerOnSharedPreferenceChangeListener(sharedPrefChangeListener)
+ }
+ }
+
+ @WorkerThread
+ private fun onDevicePropsChanges(properties: Properties) {
+ if (NAMESPACE_LAUNCHER != properties.namespace) return
+ if (!allKeys.any(properties.keyset::contains)) return
+ recreateConfig()
+ }
+
+ private fun recreateConfig() {
+ val myProps =
+ DeviceConfig.getProperties(
+ FlagsFactory.NAMESPACE_LAUNCHER,
+ *allKeys.toTypedArray<String>()
+ )
+ config =
+ factory(
+ PropReader(
+ object : PropProvider {
+ override fun <T : Any> get(key: String, fallback: T): T {
+ if (fallback is Int) return myProps.getInt(key, fallback) as T
+ else if (fallback is Boolean)
+ return myProps.getBoolean(key, fallback) as T
+ else return fallback
+ }
+ }
+ )
+ )
+ Executors.MAIN_EXECUTOR.execute { changeListeners.forEach(Runnable::run) }
+ }
+
+ /** Adds a listener for property changes */
+ fun addChangeListener(r: Runnable) = changeListeners.add(r)
+
+ /** Removes a previously added listener */
+ fun removeChangeListener(r: Runnable) = changeListeners.remove(r)
+
+ fun close() {
+ DeviceConfig.removeOnPropertiesChangedListener(propertiesListener)
+ if (BuildConfig.IS_DEBUG_DEVICE) {
+ prefs.unregisterOnSharedPreferenceChangeListener(sharedPrefChangeListener)
+ }
+ }
+
+ internal interface PropProvider {
+ fun <T : Any> get(key: String, fallback: T): T
+ }
+
+ /** The reader is sent to the config for initialization */
+ class PropReader internal constructor(private val f: PropProvider) {
+
+ @JvmOverloads
+ fun <T : Any> get(key: String, fallback: T, desc: String? = null): T {
+ val v = f.get(key, fallback)
+ if (BuildConfig.IS_DEBUG_DEVICE && desc != null) {
+ if (v is Int) {
+ allProps[key] = DebugInfo(key, desc, true, fallback)
+ return prefs.getInt(key, v) as T
+ } else if (v is Boolean) {
+ allProps[key] = DebugInfo(key, desc, false, fallback)
+ return prefs.getBoolean(key, v) as T
+ }
+ }
+ return v
+ }
+ }
+
+ class DebugInfo<T>(
+ val key: String,
+ val desc: String,
+ val isInt: Boolean,
+ val valueInCode: T,
+ )
+
+ companion object {
+ const val NAMESPACE_LAUNCHER = "launcher"
+
+ val allProps = mutableMapOf<String, DebugInfo<*>>()
+
+ private const val FLAGS_PREF_NAME = "featureFlags"
+
+ val prefs: SharedPreferences by lazy {
+ ActivityThread.currentApplication()
+ .createDeviceProtectedStorageContext()
+ .getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+ }
+ }
+}
diff --git a/res/layout/develop_options_edit_text.xml b/res/layout/develop_options_edit_text.xml
new file mode 100644
index 0000000..5e44228
--- /dev/null
+++ b/res/layout/develop_options_edit_text.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 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.
+ -->
+
+<com.android.launcher3.ExtendedEditText
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:minWidth="100dp"
+ android:inputType="numberSigned"
+ android:id="@+id/pref_edit_text"
+ android:selectAllOnFocus="true"
+ android:imeOptions="actionDone"
+ android:maxLines="1" />
\ No newline at end of file
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index cb19b14..875c407 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -297,64 +297,7 @@
@JvmField
val ICON_STATE =
nonRestorableItem("pref_icon_shape_path", "", EncryptionType.MOVE_TO_DEVICE_PROTECTED)
- @JvmField
- val ALL_APPS_OVERVIEW_THRESHOLD =
- nonRestorableItem(
- "pref_all_apps_overview_threshold",
- 180,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
- nonRestorableItem("LPNH_SLOP_PERCENTAGE", 100, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
- @JvmField
- val LONG_PRESS_NAV_HANDLE_EXTRA_TOUCH_WIDTH_DP =
- nonRestorableItem(
- "LPNH_EXTRA_TOUCH_WIDTH_DP",
- 0,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
- nonRestorableItem(
- "LPNH_TIMEOUT_MS",
- 450,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT =
- nonRestorableItem(
- "LPNH_HAPTIC_HINT_START_SCALE_PERCENT",
- 0,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT =
- nonRestorableItem(
- "LPNH_HAPTIC_HINT_END_SCALE_PERCENT",
- 100,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT =
- nonRestorableItem(
- "LPNH_HAPTIC_HINT_SCALE_EXPONENT",
- 1,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS =
- nonRestorableItem(
- "LPNH_HAPTIC_HINT_ITERATIONS",
- 50,
- EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
- @JvmField
- val LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY =
- nonRestorableItem("LPNH_HAPTIC_HINT_DELAY", 0, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
- @JvmField
- val PRIVATE_SPACE_APPS =
- nonRestorableItem("pref_private_space_apps", 0, EncryptionType.MOVE_TO_DEVICE_PROTECTED)
+
@JvmField
val ENABLE_TWOLINE_ALLAPPS_TOGGLE = backedUpItem("pref_enable_two_line_toggle", false)
@JvmField
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index e476138..d6ce2b3 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -17,14 +17,6 @@
package com.android.launcher3.config;
import static com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_EXTRA_TOUCH_WIDTH_DP;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
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;
@@ -38,10 +30,8 @@
import com.android.launcher3.BuildConfig;
import com.android.launcher3.Flags;
-import com.android.launcher3.uioverrides.flags.FlagsFactory;
import java.util.function.Predicate;
-import java.util.function.ToIntFunction;
/**
* Defines a set of flags used to control various launcher behaviors.
@@ -52,8 +42,6 @@
@VisibleForTesting
public static Predicate<BooleanFlag> sBooleanReader = f -> f.mCurrentValue;
- @VisibleForTesting
- public static ToIntFunction<IntFlag> sIntReader = f -> f.mCurrentValue;
private FeatureFlags() { }
@@ -130,42 +118,6 @@
getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
"Allow entering All Apps from Overview (e.g. long swipe up from app)");
- public static final BooleanFlag CUSTOM_LPNH_THRESHOLDS =
- getReleaseFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", ENABLED,
- "Add dev options and server side control to customize the LPNH "
- + "trigger slop and milliseconds");
-
- public static final BooleanFlag CUSTOM_LPH_THRESHOLDS = getReleaseFlag(331800576,
- "CUSTOM_LPH_THRESHOLDS", DISABLED,
- "Server side control to customize LPH timeout and touch slop");
-
- public static final BooleanFlag OVERRIDE_LPNH_LPH_THRESHOLDS = getReleaseFlag(331799727,
- "OVERRIDE_LPNH_LPH_THRESHOLDS", DISABLED,
- "Enable AGSA override for LPNH and LPH timeout and touch slop");
-
- public static final BooleanFlag ANIMATE_LPNH =
- getReleaseFlag(308693847, "ANIMATE_LPNH", TEAMFOOD,
- "Animates navbar when long pressing");
-
- public static final BooleanFlag SHRINK_NAV_HANDLE_ON_PRESS =
- getReleaseFlag(314158312, "SHRINK_NAV_HANDLE_ON_PRESS", DISABLED,
- "Shrinks navbar when long pressing if ANIMATE_LPNH is enabled");
-
- public static final IntFlag LPNH_SLOP_PERCENTAGE =
- FlagsFactory.getIntFlag(301680992, "LPNH_SLOP_PERCENTAGE", 100,
- "Controls touch slop percentage for lpnh",
- LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE);
-
- public static final IntFlag LPNH_EXTRA_TOUCH_WIDTH_DP =
- FlagsFactory.getIntFlag(301680992, "LPNH_EXTRA_TOUCH_WIDTH_DP", 0,
- "Controls extra dp on the nav bar sides to trigger LPNH."
- + " Can be negative for a smaller touch region.",
- LONG_PRESS_NAV_HANDLE_EXTRA_TOUCH_WIDTH_DP);
-
- public static final IntFlag LPNH_TIMEOUT_MS =
- FlagsFactory.getIntFlag(301680992, "LPNH_TIMEOUT_MS", 450,
- "Controls lpnh timeout in milliseconds", LONG_PRESS_NAV_HANDLE_TIMEOUT_MS);
-
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
"Enable option to show keyboard when going to all-apps");
@@ -296,49 +248,6 @@
"INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED,
"Inject fallback app corpus result when AiAi fails to return it.");
- public static final BooleanFlag ENABLE_LONG_PRESS_NAV_HANDLE =
- getReleaseFlag(299682306, "ENABLE_LONG_PRESS_NAV_HANDLE", ENABLED,
- "Enables long pressing on the bottom bar nav handle to trigger events.");
-
- public static final BooleanFlag ENABLE_SEARCH_HAPTIC_HINT =
- getReleaseFlag(314005131, "ENABLE_SEARCH_HAPTIC_HINT", ENABLED,
- "Enables haptic hint while long pressing on the bottom bar nav handle.");
-
- public static final BooleanFlag ENABLE_SEARCH_HAPTIC_COMMIT =
- getReleaseFlag(314005577, "ENABLE_SEARCH_HAPTIC_COMMIT", ENABLED,
- "Enables haptic hint at end of long pressing on the bottom bar nav handle.");
-
- public static final IntFlag LPNH_HAPTIC_HINT_START_SCALE_PERCENT =
- FlagsFactory.getIntFlag(309972570,
- "LPNH_HAPTIC_HINT_START_SCALE_PERCENT", 0,
- "Haptic hint start scale.",
- LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_START_SCALE_PERCENT);
-
- public static final IntFlag LPNH_HAPTIC_HINT_END_SCALE_PERCENT =
- FlagsFactory.getIntFlag(309972570,
- "LPNH_HAPTIC_HINT_END_SCALE_PERCENT", 100,
- "Haptic hint end scale.", LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_END_SCALE_PERCENT);
-
- public static final IntFlag LPNH_HAPTIC_HINT_SCALE_EXPONENT =
- FlagsFactory.getIntFlag(309972570,
- "LPNH_HAPTIC_HINT_SCALE_EXPONENT", 1,
- "Haptic hint scale exponent.",
- LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_SCALE_EXPONENT);
-
- public static final IntFlag LPNH_HAPTIC_HINT_ITERATIONS =
- FlagsFactory.getIntFlag(309972570, "LPNH_HAPTIC_HINT_ITERATIONS",
- 50,
- "Haptic hint number of iterations.",
- LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_ITERATIONS);
-
- public static final BooleanFlag ENABLE_LPNH_DEEP_PRESS =
- getReleaseFlag(310952290, "ENABLE_LPNH_DEEP_PRESS", ENABLED,
- "Long press of nav handle is instantly triggered if deep press is detected.");
-
- public static final IntFlag LPNH_HAPTIC_HINT_DELAY =
- FlagsFactory.getIntFlag(309972570, "LPNH_HAPTIC_HINT_DELAY", 0,
- "Delay before haptic hint starts.", LONG_PRESS_NAV_HANDLE_HAPTIC_HINT_DELAY);
-
// TODO(Block 17): Clean up flags
// Aconfig migration complete for ENABLE_TASKBAR_PINNING.
private static final BooleanFlag ENABLE_TASKBAR_PINNING = getDebugFlag(296231746,
@@ -515,22 +424,6 @@
}
/**
- * Class representing an integer flag
- */
- public static class IntFlag {
-
- private final int mCurrentValue;
-
- public IntFlag(int currentValue) {
- mCurrentValue = currentValue;
- }
-
- public int get() {
- return sIntReader.applyAsInt(this);
- }
- }
-
- /**
* Enabled state for a flag
*/
public enum FlagState {
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index e1695e9..cd60c1d 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -19,11 +19,6 @@
import static android.os.VibrationEffect.createPredefined;
import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_DELAY;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_END_SCALE_PERCENT;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_ITERATIONS;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_SCALE_EXPONENT;
-import static com.android.launcher3.config.FeatureFlags.LPNH_HAPTIC_HINT_START_SCALE_PERCENT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -40,7 +35,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
@@ -71,9 +65,6 @@
@Nullable
private final VibrationEffect mBumpEffect;
- @Nullable
- private final VibrationEffect mSearchEffect;
-
private long mLastDragTime;
private final int mThresholdUntilNextDragCallMillis;
@@ -133,25 +124,6 @@
mBumpEffect = null;
mThresholdUntilNextDragCallMillis = 0;
}
-
- if (mVibrator.areAllPrimitivesSupported(
- VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
- VibrationEffect.Composition.PRIMITIVE_TICK)) {
- if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get()) {
- mSearchEffect = VibrationEffect.startComposition()
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1f)
- .compose();
- } else {
- // quiet ramp, short pause, then sharp tick
- mSearchEffect = VibrationEffect.startComposition()
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE, 0.25f)
- .addPrimitive(VibrationEffect.Composition.PRIMITIVE_TICK, 1f, 50)
- .compose();
- }
- } else {
- // fallback for devices without composition support
- mSearchEffect = VibrationEffect.createPredefined(VibrationEffect.EFFECT_HEAVY_CLICK);
- }
}
/**
@@ -233,13 +205,6 @@
}
}
- /** Indicates that search has been invoked. */
- public void vibrateForSearch() {
- if (mSearchEffect != null) {
- vibrate(mSearchEffect);
- }
- }
-
/** Indicates that Taskbar has been invoked. */
public void vibrateForTaskbarUnstash() {
if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
@@ -251,32 +216,4 @@
vibrate(primitiveLowTickEffect);
}
}
-
- /** Indicates that search will be invoked if the current gesture is maintained. */
- public void vibrateForSearchHint() {
- if (FeatureFlags.ENABLE_SEARCH_HAPTIC_HINT.get() && Utilities.ATLEAST_S
- && mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
- float startScale = LPNH_HAPTIC_HINT_START_SCALE_PERCENT.get() / 100f;
- float endScale = LPNH_HAPTIC_HINT_END_SCALE_PERCENT.get() / 100f;
- int scaleExponent = LPNH_HAPTIC_HINT_SCALE_EXPONENT.get();
- int iterations = LPNH_HAPTIC_HINT_ITERATIONS.get();
- int delayMs = LPNH_HAPTIC_HINT_DELAY.get();
-
- VibrationEffect.Composition composition = VibrationEffect.startComposition();
- for (int i = 0; i < iterations; i++) {
- float t = i / (iterations - 1f);
- float scale = (float) Math.pow((1 - t) * startScale + t * endScale,
- scaleExponent);
- if (i == 0) {
- // Adds a delay before the ramp starts
- composition.addPrimitive(PRIMITIVE_LOW_TICK, scale,
- delayMs);
- } else {
- composition.addPrimitive(PRIMITIVE_LOW_TICK, scale);
- }
- }
-
- vibrate(composition.compose());
- }
- }
}
diff --git a/src_no_quickstep/com/android/launcher3/uioverrides/flags/FlagsFactory.java b/src_no_quickstep/com/android/launcher3/uioverrides/flags/FlagsFactory.java
index b193d37..02e0de0 100644
--- a/src_no_quickstep/com/android/launcher3/uioverrides/flags/FlagsFactory.java
+++ b/src_no_quickstep/com/android/launcher3/uioverrides/flags/FlagsFactory.java
@@ -18,12 +18,8 @@
import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
-import androidx.annotation.Nullable;
-
-import com.android.launcher3.ConstantItem;
import com.android.launcher3.config.FeatureFlags.BooleanFlag;
import com.android.launcher3.config.FeatureFlags.FlagState;
-import com.android.launcher3.config.FeatureFlags.IntFlag;
import java.io.PrintWriter;
@@ -50,23 +46,6 @@
}
/**
- * Creates a new integer flag. Integer flags are always release flags
- */
- public static IntFlag getIntFlag(
- int bugId, String key, int defaultValueInCode, String description) {
- return new IntFlag(defaultValueInCode);
- }
-
- /**
- * Creates a new debug integer flag and it is saved in LauncherPrefs.
- */
- public static IntFlag getIntFlag(
- int bugId, String key, int defaultValueInCode, String description,
- @Nullable ConstantItem<Integer> launcherPrefFlag) {
- return new IntFlag(defaultValueInCode);
- }
-
- /**
* Dumps the current flags state to the print writer
*/
public static void dump(PrintWriter pw) { }
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
index 95444ba..2a0f614 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
@@ -48,7 +48,6 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.config.FeatureFlags.BooleanFlag;
-import com.android.launcher3.config.FeatureFlags.IntFlag;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.util.rule.TestStabilityRule;
@@ -67,7 +66,6 @@
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Predicate;
-import java.util.function.ToIntFunction;
public class TestUtil {
private static final String TAG = "TestUtil";
@@ -169,21 +167,6 @@
};
}
- /**
- * Utility class to override a int flag during test. Note that the returned SafeCloseable
- * must be closed to restore the original state
- */
- public static SafeCloseable overrideFlag(IntFlag flag, int value) {
- ToIntFunction<IntFlag> originalProxy = FeatureFlags.sIntReader;
- ToIntFunction<IntFlag> testProxy = f -> f == flag ? value : originalProxy.applyAsInt(f);
- FeatureFlags.sIntReader = testProxy;
- return () -> {
- if (FeatureFlags.sIntReader == testProxy) {
- FeatureFlags.sIntReader = originalProxy;
- }
- };
- }
-
public static void uninstallDummyApp() throws IOException {
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
"pm uninstall " + DUMMY_PACKAGE);