2017-07-24 01:02:38 -07:00
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2017 The Android Open Source Project
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package com.android.launcher3.config;
|
|
|
|
|
|
2018-10-12 14:14:16 -04:00
|
|
|
import static androidx.core.util.Preconditions.checkNotNull;
|
2019-01-29 11:01:22 -08:00
|
|
|
|
2018-10-12 14:14:16 -04:00
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.SharedPreferences;
|
2019-01-29 11:01:22 -08:00
|
|
|
|
2018-11-04 11:39:08 -05:00
|
|
|
import androidx.annotation.GuardedBy;
|
|
|
|
|
import androidx.annotation.Keep;
|
2019-08-13 15:57:15 -07:00
|
|
|
import androidx.annotation.VisibleForTesting;
|
2018-10-12 14:14:16 -04:00
|
|
|
|
2019-09-11 16:51:50 -07:00
|
|
|
import com.android.launcher3.BuildConfig;
|
2019-08-26 14:36:02 -07:00
|
|
|
import com.android.launcher3.Utilities;
|
2019-08-13 15:57:15 -07:00
|
|
|
import com.android.launcher3.uioverrides.TogglableFlag;
|
2019-08-26 14:36:02 -07:00
|
|
|
|
2018-10-12 14:14:16 -04:00
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
import java.util.SortedMap;
|
|
|
|
|
import java.util.TreeMap;
|
|
|
|
|
|
2017-07-24 01:02:38 -07:00
|
|
|
/**
|
|
|
|
|
* Defines a set of flags used to control various launcher behaviors.
|
|
|
|
|
*
|
2018-10-03 13:32:01 -04:00
|
|
|
* <p>All the flags should be defined here with appropriate default values.
|
2017-07-24 01:02:38 -07:00
|
|
|
*/
|
2018-10-12 14:14:16 -04:00
|
|
|
@Keep
|
2019-09-11 16:51:50 -07:00
|
|
|
public final class FeatureFlags {
|
2017-07-24 01:02:38 -07:00
|
|
|
|
2018-10-12 14:14:16 -04:00
|
|
|
private static final Object sLock = new Object();
|
|
|
|
|
@GuardedBy("sLock")
|
|
|
|
|
private static final List<TogglableFlag> sFlags = new ArrayList<>();
|
|
|
|
|
|
|
|
|
|
static final String FLAGS_PREF_NAME = "featureFlags";
|
2018-10-03 13:32:01 -04:00
|
|
|
|
2019-09-11 16:51:50 -07:00
|
|
|
private FeatureFlags() { }
|
2018-10-12 14:14:16 -04:00
|
|
|
|
2018-10-22 16:31:28 -04:00
|
|
|
public static boolean showFlagTogglerUi(Context context) {
|
2019-05-15 14:01:30 -07:00
|
|
|
return Utilities.IS_DEBUG_DEVICE && Utilities.isDevelopersOptionsEnabled(context);
|
2018-10-03 13:32:01 -04:00
|
|
|
}
|
2017-07-24 01:02:38 -07:00
|
|
|
|
2019-09-11 16:51:50 -07:00
|
|
|
public static final boolean IS_DOGFOOD_BUILD = BuildConfig.DEBUG;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Enable moving the QSB on the 0th screen of the workspace. This is not a configuration feature
|
|
|
|
|
* and should be modified at a project level.
|
|
|
|
|
*/
|
|
|
|
|
public static final boolean QSB_ON_FIRST_SCREEN = true;
|
|
|
|
|
|
2017-07-24 01:02:38 -07:00
|
|
|
|
2019-09-11 16:51:50 -07:00
|
|
|
/**
|
|
|
|
|
* Feature flag to handle define config changes dynamically instead of killing the process.
|
|
|
|
|
*
|
|
|
|
|
*
|
|
|
|
|
* To add a new flag that can be toggled through the flags UI:
|
|
|
|
|
*
|
2019-12-03 12:00:44 -08:00
|
|
|
* Declare a new ToggleableFlag below. Give it a unique key (e.g. "QSB_ON_FIRST_SCREEN"),
|
2019-09-11 16:51:50 -07:00
|
|
|
* and set a default value for the flag. This will be the default value on Debug builds.
|
|
|
|
|
*/
|
2017-07-24 01:02:38 -07:00
|
|
|
// When enabled the promise icon is visible in all apps while installation an app.
|
2019-09-11 16:51:50 -07:00
|
|
|
public static final TogglableFlag PROMISE_APPS_IN_ALL_APPS = new TogglableFlag(
|
|
|
|
|
"PROMISE_APPS_IN_ALL_APPS", false, "Add promise icon in all-apps");
|
2017-07-24 01:02:38 -07:00
|
|
|
|
2019-08-19 13:32:09 -07:00
|
|
|
// When enabled a promise icon is added to the home screen when install session is active.
|
|
|
|
|
public static final TogglableFlag PROMISE_APPS_NEW_INSTALLS =
|
|
|
|
|
new TogglableFlag("PROMISE_APPS_NEW_INSTALLS", true,
|
|
|
|
|
"Adds a promise icon to the home screen for new install sessions.");
|
|
|
|
|
|
2018-10-12 11:42:33 -07:00
|
|
|
public static final TogglableFlag APPLY_CONFIG_AT_RUNTIME = new TogglableFlag(
|
2018-12-04 15:43:16 -08:00
|
|
|
"APPLY_CONFIG_AT_RUNTIME", true, "Apply display changes dynamically");
|
2018-10-12 11:42:33 -07:00
|
|
|
|
2019-01-08 16:01:57 -08:00
|
|
|
public static final TogglableFlag QUICKSTEP_SPRINGS = new TogglableFlag("QUICKSTEP_SPRINGS",
|
|
|
|
|
false, "Enable springs for quickstep animations");
|
|
|
|
|
|
2019-02-19 15:34:41 -08:00
|
|
|
public static final TogglableFlag ADAPTIVE_ICON_WINDOW_ANIM = new TogglableFlag(
|
2019-03-06 10:40:13 -08:00
|
|
|
"ADAPTIVE_ICON_WINDOW_ANIM", true,
|
2019-02-19 15:34:41 -08:00
|
|
|
"Use adaptive icons for window animations.");
|
|
|
|
|
|
2018-10-29 16:08:29 -04:00
|
|
|
public static final TogglableFlag ENABLE_QUICKSTEP_LIVE_TILE = new TogglableFlag(
|
|
|
|
|
"ENABLE_QUICKSTEP_LIVE_TILE", false, "Enable live tile in Quickstep overview");
|
|
|
|
|
|
2019-02-11 13:07:04 -05:00
|
|
|
public static final TogglableFlag ENABLE_HINTS_IN_OVERVIEW = new TogglableFlag(
|
2019-07-23 17:34:34 -07:00
|
|
|
"ENABLE_HINTS_IN_OVERVIEW", true,
|
2019-02-11 13:07:04 -05:00
|
|
|
"Show chip hints and gleams on the overview screen");
|
|
|
|
|
|
2019-04-30 12:04:37 -07:00
|
|
|
public static final TogglableFlag FAKE_LANDSCAPE_UI = new TogglableFlag(
|
2019-06-19 14:24:38 -07:00
|
|
|
"FAKE_LANDSCAPE_UI", false,
|
2019-04-30 12:04:37 -07:00
|
|
|
"Rotate launcher UI instead of using transposed layout");
|
|
|
|
|
|
2019-10-10 23:11:12 -07:00
|
|
|
public static final TogglableFlag FOLDER_NAME_SUGGEST = new TogglableFlag(
|
|
|
|
|
"FOLDER_NAME_SUGGEST", true,
|
|
|
|
|
"Suggests folder names instead of blank text.");
|
|
|
|
|
|
2019-08-08 12:22:26 -07:00
|
|
|
public static final TogglableFlag APP_SEARCH_IMPROVEMENTS = new TogglableFlag(
|
|
|
|
|
"APP_SEARCH_IMPROVEMENTS", false,
|
|
|
|
|
"Adds localized title and keyword search and ranking");
|
|
|
|
|
|
2019-08-09 16:16:06 -07:00
|
|
|
public static final TogglableFlag ENABLE_PREDICTION_DISMISS = new TogglableFlag(
|
|
|
|
|
"ENABLE_PREDICTION_DISMISS", false, "Allow option to dimiss apps from predicted list");
|
|
|
|
|
|
2019-09-19 16:17:55 -07:00
|
|
|
public static final TogglableFlag ENABLE_QUICK_CAPTURE_GESTURE = new TogglableFlag(
|
|
|
|
|
"ENABLE_QUICK_CAPTURE_GESTURE", false, "Swipe from right to left to quick capture");
|
2019-08-09 16:16:06 -07:00
|
|
|
|
2019-10-17 11:59:53 -07:00
|
|
|
public static final TogglableFlag ASSISTANT_GIVES_LAUNCHER_FOCUS = new TogglableFlag(
|
|
|
|
|
"ASSISTANT_GIVES_LAUNCHER_FOCUS", false,
|
|
|
|
|
"Allow Launcher to handle nav bar gestures while Assistant is running over it");
|
|
|
|
|
|
2019-10-21 02:02:40 -07:00
|
|
|
public static final TogglableFlag ENABLE_HYBRID_HOTSEAT = new TogglableFlag(
|
|
|
|
|
"ENABLE_HYBRID_HOTSEAT", false, "Fill gaps in hotseat with predicted apps");
|
|
|
|
|
|
2019-10-23 17:47:28 +00:00
|
|
|
public static final TogglableFlag ENABLE_DEEP_SHORTCUT_ICON_CACHE = new TogglableFlag(
|
|
|
|
|
"ENABLE_DEEP_SHORTCUT_ICON_CACHE", true, "R/W deep shortcut in IconCache");
|
|
|
|
|
|
2018-10-12 14:14:16 -04:00
|
|
|
public static void initialize(Context context) {
|
2018-10-22 16:31:28 -04:00
|
|
|
// Avoid the disk read for user builds
|
|
|
|
|
if (Utilities.IS_DEBUG_DEVICE) {
|
2018-10-12 14:14:16 -04:00
|
|
|
synchronized (sLock) {
|
2019-08-13 15:57:15 -07:00
|
|
|
for (BaseTogglableFlag flag : sFlags) {
|
2018-11-04 11:39:08 -05:00
|
|
|
flag.initialize(context);
|
2018-10-12 14:14:16 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static List<TogglableFlag> getTogglableFlags() {
|
|
|
|
|
// By Java Language Spec 12.4.2
|
|
|
|
|
// https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2, the
|
2019-09-11 16:51:50 -07:00
|
|
|
// TogglableFlag instances on FeatureFlags will be created before those on the FeatureFlags
|
2018-10-12 14:14:16 -04:00
|
|
|
// subclass. This code handles flags that are redeclared in FeatureFlags, ensuring the
|
|
|
|
|
// FeatureFlags one takes priority.
|
|
|
|
|
SortedMap<String, TogglableFlag> flagsByKey = new TreeMap<>();
|
|
|
|
|
synchronized (sLock) {
|
|
|
|
|
for (TogglableFlag flag : sFlags) {
|
2019-09-11 16:51:50 -07:00
|
|
|
flagsByKey.put(flag.getKey(), flag);
|
2018-10-12 14:14:16 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return new ArrayList<>(flagsByKey.values());
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-13 15:57:15 -07:00
|
|
|
public static abstract class BaseTogglableFlag {
|
2018-10-12 14:14:16 -04:00
|
|
|
private final String key;
|
2019-09-09 23:32:17 -07:00
|
|
|
// should be value that is hardcoded in client side.
|
|
|
|
|
// Comparatively, getDefaultValue() can be overridden.
|
2018-10-12 14:14:16 -04:00
|
|
|
private final boolean defaultValue;
|
|
|
|
|
private final String description;
|
|
|
|
|
private boolean currentValue;
|
|
|
|
|
|
2019-08-13 15:57:15 -07:00
|
|
|
public BaseTogglableFlag(
|
2018-10-12 14:14:16 -04:00
|
|
|
String key,
|
|
|
|
|
boolean defaultValue,
|
|
|
|
|
String description) {
|
|
|
|
|
this.key = checkNotNull(key);
|
2019-09-09 23:32:17 -07:00
|
|
|
this.currentValue = this.defaultValue = defaultValue;
|
2018-10-12 14:14:16 -04:00
|
|
|
this.description = checkNotNull(description);
|
2019-09-09 23:32:17 -07:00
|
|
|
|
2018-10-12 14:14:16 -04:00
|
|
|
synchronized (sLock) {
|
2019-08-13 15:57:15 -07:00
|
|
|
sFlags.add((TogglableFlag)this);
|
2018-10-12 14:14:16 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-08 11:30:14 -05:00
|
|
|
/** Set the value of this flag. This should only be used in tests. */
|
|
|
|
|
@VisibleForTesting
|
|
|
|
|
void setForTests(boolean value) {
|
|
|
|
|
currentValue = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public String getKey() {
|
2018-10-12 14:14:16 -04:00
|
|
|
return key;
|
|
|
|
|
}
|
2019-08-13 15:57:15 -07:00
|
|
|
|
2019-09-09 23:32:17 -07:00
|
|
|
protected void initialize(Context context) {
|
|
|
|
|
currentValue = getFromStorage(context, getDefaultValue());
|
2018-11-04 11:39:08 -05:00
|
|
|
}
|
|
|
|
|
|
2019-09-09 23:32:17 -07:00
|
|
|
protected abstract boolean getOverridenDefaultValue(boolean value);
|
|
|
|
|
|
|
|
|
|
protected abstract void addChangeListener(Context context, Runnable r);
|
2019-08-13 15:57:15 -07:00
|
|
|
|
2019-03-11 16:23:45 -07:00
|
|
|
public void updateStorage(Context context, boolean value) {
|
2018-11-04 11:39:08 -05:00
|
|
|
SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME,
|
|
|
|
|
Context.MODE_PRIVATE).edit();
|
2019-09-09 23:32:17 -07:00
|
|
|
if (value == getDefaultValue()) {
|
2018-11-04 11:39:08 -05:00
|
|
|
editor.remove(key).apply();
|
|
|
|
|
} else {
|
|
|
|
|
editor.putBoolean(key, value).apply();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
boolean getFromStorage(Context context, boolean defaultValue) {
|
|
|
|
|
return context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE)
|
2019-09-09 23:32:17 -07:00
|
|
|
.getBoolean(key, getDefaultValue());
|
2018-11-04 11:39:08 -05:00
|
|
|
}
|
2018-10-12 14:14:16 -04:00
|
|
|
|
|
|
|
|
boolean getDefaultValue() {
|
2019-09-09 23:32:17 -07:00
|
|
|
return getOverridenDefaultValue(defaultValue);
|
2018-10-12 14:14:16 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Returns the value of the flag at process start, including any overrides present. */
|
|
|
|
|
public boolean get() {
|
|
|
|
|
return currentValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
String getDescription() {
|
|
|
|
|
return description;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public String toString() {
|
|
|
|
|
return "TogglableFlag{"
|
|
|
|
|
+ "key=" + key + ", "
|
|
|
|
|
+ "defaultValue=" + defaultValue + ", "
|
2019-09-09 23:32:17 -07:00
|
|
|
+ "overriddenDefaultValue=" + getOverridenDefaultValue(defaultValue) + ", "
|
|
|
|
|
+ "currentValue=" + currentValue + ", "
|
2018-10-12 14:14:16 -04:00
|
|
|
+ "description=" + description
|
|
|
|
|
+ "}";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean equals(Object o) {
|
|
|
|
|
if (o == this) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
if (o instanceof TogglableFlag) {
|
2019-08-13 15:57:15 -07:00
|
|
|
BaseTogglableFlag that = (BaseTogglableFlag) o;
|
2018-10-12 14:14:16 -04:00
|
|
|
return (this.key.equals(that.getKey()))
|
2019-09-09 23:32:17 -07:00
|
|
|
&& (this.getDefaultValue() == that.getDefaultValue())
|
2018-10-12 14:14:16 -04:00
|
|
|
&& (this.description.equals(that.getDescription()));
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public int hashCode() {
|
2019-09-25 09:08:16 -07:00
|
|
|
return key.hashCode();
|
2018-10-12 14:14:16 -04:00
|
|
|
}
|
|
|
|
|
}
|
2017-07-24 01:02:38 -07:00
|
|
|
}
|