Moving various nav-bar configs out of feature flags
Bug: 332588958 Test: Presubmit Flag: None Change-Id: Ia4dc5b69bcf4d461e3444b9e37bb7334bb74aae4
This commit is contained in:
@@ -45,3 +45,6 @@ zakcohen@google.com
|
||||
|
||||
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
|
||||
|
||||
@@ -173,6 +173,7 @@ import java.lang.ref.WeakReference;
|
||||
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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
@@ -20,19 +20,8 @@ import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
|
||||
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.provider.Settings;
|
||||
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 android.widget.Toast;
|
||||
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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 @@ public class DeveloperOptionsUI {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,6 @@ import androidx.preference.PreferenceGroup;
|
||||
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 @@ public final class FlagTogglerPrefUi implements ActivityLifecycleCallbacksAdapte
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,6 @@ import static com.android.launcher3.config.FeatureFlags.FlagState.DISABLED;
|
||||
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.provider.DeviceConfig.Properties;
|
||||
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 class FlagsFactory {
|
||||
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 @@ public class FlagsFactory {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 @@ public class FlagsFactory {
|
||||
}
|
||||
}
|
||||
|
||||
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 @@ public class FlagsFactory {
|
||||
}
|
||||
}
|
||||
}
|
||||
pw.println(" IntFlags:");
|
||||
synchronized (sIntDebugFlags) {
|
||||
for (IntFlag flag : sIntDebugFlags) {
|
||||
pw.println(" " + flag);
|
||||
}
|
||||
}
|
||||
pw.println(" DebugFlags:");
|
||||
synchronized (sDebugFlags) {
|
||||
for (DebugFlag flag : sDebugFlags) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -18,12 +18,10 @@ import android.content.ComponentName;
|
||||
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 @@ public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnab
|
||||
}
|
||||
|
||||
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 @@ public class PluginEnablerImpl extends PreferenceDataStore implements PluginEnab
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -98,13 +98,6 @@ public class PluginManagerWrapper {
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -22,8 +22,8 @@ import static android.view.Surface.ROTATION_90;
|
||||
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.EVENT_STARTED;
|
||||
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.jank.Cuj;
|
||||
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 @@ public abstract class AbsSwipeUpHandler<T extends StatefulActivity<S>,
|
||||
@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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -60,7 +60,6 @@ import androidx.annotation.NonNull;
|
||||
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 @@ public class RecentsAnimationDeviceState implements DisplayInfoChangeListener, E
|
||||
: 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;
|
||||
|
||||
@@ -1456,6 +1456,7 @@ public class TouchInteractionService extends Service {
|
||||
pw.println("AssistStateManager:");
|
||||
AssistStateManager.INSTANCE.get(this).dump(" ", pw);
|
||||
SystemUiProxy.INSTANCE.get(this).dump(pw);
|
||||
DeviceConfigWrapper.get().dump(" ", pw);
|
||||
}
|
||||
|
||||
private AbsSwipeUpHandler createLauncherSwipeHandler(
|
||||
|
||||
+5
-4
@@ -27,9 +27,9 @@ import android.view.MotionEvent;
|
||||
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 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer {
|
||||
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 @@ public class NavHandleLongPressInputConsumer extends DelegateInputConsumer {
|
||||
|
||||
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) {
|
||||
|
||||
@@ -18,7 +18,6 @@ package com.android.quickstep.util;
|
||||
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 androidx.annotation.Nullable;
|
||||
|
||||
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.StateManager;
|
||||
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 @@ public class AnimatorControllerWithResistance {
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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" />
|
||||
@@ -297,64 +297,7 @@ class LauncherPrefs(private val encryptedContext: Context) {
|
||||
@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
|
||||
|
||||
@@ -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 androidx.annotation.VisibleForTesting;
|
||||
|
||||
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 @@ public final class FeatureFlags {
|
||||
|
||||
@VisibleForTesting
|
||||
public static Predicate<BooleanFlag> sBooleanReader = f -> f.mCurrentValue;
|
||||
@VisibleForTesting
|
||||
public static ToIntFunction<IntFlag> sIntReader = f -> f.mCurrentValue;
|
||||
|
||||
private FeatureFlags() { }
|
||||
|
||||
@@ -130,42 +118,6 @@ public final class FeatureFlags {
|
||||
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 @@ public final class FeatureFlags {
|
||||
"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,
|
||||
@@ -514,22 +423,6 @@ public final class FeatureFlags {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
@@ -19,11 +19,6 @@ import static android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
|
||||
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 android.provider.Settings;
|
||||
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 @@ public class VibratorWrapper {
|
||||
@Nullable
|
||||
private final VibrationEffect mBumpEffect;
|
||||
|
||||
@Nullable
|
||||
private final VibrationEffect mSearchEffect;
|
||||
|
||||
private long mLastDragTime;
|
||||
private final int mThresholdUntilNextDragCallMillis;
|
||||
|
||||
@@ -133,25 +124,6 @@ public class VibratorWrapper {
|
||||
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 @@ public class VibratorWrapper {
|
||||
}
|
||||
}
|
||||
|
||||
/** 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 @@ public class VibratorWrapper {
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,12 +18,8 @@ package com.android.launcher3.uioverrides.flags;
|
||||
|
||||
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;
|
||||
|
||||
@@ -49,23 +45,6 @@ public class FlagsFactory {
|
||||
return new BooleanFlag(flagState == ENABLED);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
|
||||
@@ -48,7 +48,6 @@ import androidx.test.uiautomator.UiDevice;
|
||||
|
||||
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.FutureTask;
|
||||
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 @@ public class TestUtil {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
Reference in New Issue
Block a user