Make flags UI available on release build of launcher
The UI will only be shown on eng/userdebug platform builds. Bug: 117223984 Change-Id: I27843f2d856a4a19f3fe53c4d306606eaa5714a2
This commit is contained in:
parent
cf7715511e
commit
fa530cd23f
|
@ -22,14 +22,10 @@ import android.content.Context;
|
|||
* Defines a set of flags used to control various launcher behaviors
|
||||
*/
|
||||
public final class FeatureFlags extends BaseFlags {
|
||||
private static FeatureFlags instance = new FeatureFlags();
|
||||
|
||||
public static FeatureFlags getInstance(Context context) {
|
||||
return instance;
|
||||
private FeatureFlags() {
|
||||
// Prevent instantiation
|
||||
}
|
||||
|
||||
private FeatureFlags() {}
|
||||
|
||||
// Features to control Launcher3Go behavior
|
||||
public static final boolean GO_DISABLE_WIDGETS = true;
|
||||
public static final boolean LAUNCHER3_SPRING_ICONS = false;
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
/*
|
||||
* Copyright (C) 2018 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.
|
||||
*/
|
||||
-->
|
||||
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:key="feature_flags"
|
||||
android:persistent="false">
|
||||
|
||||
</PreferenceScreen>
|
|
@ -52,4 +52,10 @@
|
|||
android:defaultValue=""
|
||||
android:persistent="false" />
|
||||
|
||||
<PreferenceScreen
|
||||
android:fragment="com.android.launcher3.config.FlagTogglerPreferenceFragment"
|
||||
android:key="flag_toggler"
|
||||
android:persistent="false"
|
||||
android:title="Feature flags"/>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
|
|
@ -1753,12 +1753,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||
@Override
|
||||
public void bindScreens(IntArray orderedScreenIds) {
|
||||
// Make sure the first screen is always at the start.
|
||||
if (FeatureFlags.getInstance(this).isQsbOnFirstScreenEnabled() &&
|
||||
if (FeatureFlags.QSB_ON_FIRST_SCREEN.get() &&
|
||||
orderedScreenIds.indexOf(Workspace.FIRST_SCREEN_ID) != 0) {
|
||||
orderedScreenIds.removeValue(Workspace.FIRST_SCREEN_ID);
|
||||
orderedScreenIds.add(0, Workspace.FIRST_SCREEN_ID);
|
||||
LauncherModel.updateWorkspaceScreenOrder(this, orderedScreenIds);
|
||||
} else if (!FeatureFlags.getInstance(this).isQsbOnFirstScreenEnabled()
|
||||
} else if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get()
|
||||
&& orderedScreenIds.isEmpty()) {
|
||||
// If there are no screens, we need to have an empty screen
|
||||
mWorkspace.addExtraEmptyScreen();
|
||||
|
@ -1775,8 +1775,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns,
|
|||
int count = orderedScreenIds.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
int screenId = orderedScreenIds.get(i);
|
||||
if (!FeatureFlags.getInstance(this).isQsbOnFirstScreenEnabled()
|
||||
|| screenId != Workspace.FIRST_SCREEN_ID) {
|
||||
if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get() || screenId != Workspace.FIRST_SCREEN_ID) {
|
||||
// No need to bind the first screen, as its always bound.
|
||||
mWorkspace.insertNewWorkspaceScreenBeforeEmptyScreen(screenId);
|
||||
}
|
||||
|
|
|
@ -70,9 +70,6 @@ import java.io.PrintWriter;
|
|||
import java.net.URISyntaxException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
public class LauncherProvider extends ContentProvider {
|
||||
private static final String TAG = "LauncherProvider";
|
||||
|
@ -793,7 +790,7 @@ public class LauncherProvider extends ContentProvider {
|
|||
convertShortcutsToLauncherActivities(db);
|
||||
case 26:
|
||||
// QSB was moved to the grid. Clear the first row on screen 0.
|
||||
if (FeatureFlags.getInstance(mContext).isQsbOnFirstScreenEnabled() &&
|
||||
if (FeatureFlags.QSB_ON_FIRST_SCREEN.get() &&
|
||||
!LauncherDbUtils.prepareScreenZeroToHostQsb(mContext, db)) {
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ package com.android.launcher3;
|
|||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.IconShapeOverride;
|
||||
import com.android.launcher3.logging.FileLog;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
@ -35,6 +36,7 @@ public class MainProcessInitializer implements ResourceBasedOverride {
|
|||
|
||||
protected void init(Context context) {
|
||||
FileLog.setDir(context.getApplicationContext().getFilesDir());
|
||||
FeatureFlags.initialize(context);
|
||||
IconShapeOverride.apply(context);
|
||||
SessionCommitReceiver.applyDefaultUserPrefs(context);
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import android.view.View;
|
|||
import android.widget.Adapter;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.graphics.IconShapeOverride;
|
||||
import com.android.launcher3.notification.NotificationListener;
|
||||
import com.android.launcher3.util.ListViewHighlighter;
|
||||
|
@ -57,6 +58,8 @@ import java.util.Objects;
|
|||
public class SettingsActivity extends Activity
|
||||
implements PreferenceFragment.OnPreferenceStartFragmentCallback {
|
||||
|
||||
private static final String FLAGS_PREFERENCE_KEY = "flag_toggler";
|
||||
|
||||
private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
|
||||
/** Hidden field Settings.Secure.NOTIFICATION_BADGING */
|
||||
public static final String NOTIFICATION_BADGING = "notification_badging";
|
||||
|
@ -126,6 +129,12 @@ public class SettingsActivity extends Activity
|
|||
getPreferenceManager().setSharedPreferencesName(LauncherFiles.SHARED_PREFERENCES_KEY);
|
||||
addPreferencesFromResource(R.xml.launcher_preferences);
|
||||
|
||||
// Only show flag toggler UI if this build variant implements that.
|
||||
Preference flagToggler = findPreference(FLAGS_PREFERENCE_KEY);
|
||||
if (flagToggler != null && !FeatureFlags.showFlagTogglerUi()) {
|
||||
getPreferenceScreen().removePreference(flagToggler);
|
||||
}
|
||||
|
||||
ContentResolver resolver = getActivity().getContentResolver();
|
||||
|
||||
ButtonPreference iconBadgingPref =
|
||||
|
|
|
@ -480,7 +480,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
* @param qsb an existing qsb to recycle or null.
|
||||
*/
|
||||
public void bindAndInitFirstWorkspaceScreen(View qsb) {
|
||||
if (!FeatureFlags.getInstance(getContext()).isQsbOnFirstScreenEnabled()) {
|
||||
if (!FeatureFlags.QSB_ON_FIRST_SCREEN.get()) {
|
||||
return;
|
||||
}
|
||||
// Add the first page
|
||||
|
@ -779,9 +779,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator>
|
|||
int id = mWorkspaceScreens.keyAt(i);
|
||||
CellLayout cl = mWorkspaceScreens.valueAt(i);
|
||||
// FIRST_SCREEN_ID can never be removed.
|
||||
boolean qsbFirstScreenEnabled =
|
||||
FeatureFlags.getInstance(getContext()).isQsbOnFirstScreenEnabled();
|
||||
if ((!qsbFirstScreenEnabled || id > FIRST_SCREEN_ID)
|
||||
if ((!FeatureFlags.QSB_ON_FIRST_SCREEN.get() || id > FIRST_SCREEN_ID)
|
||||
&& cl.getShortcutsAndWidgets().getChildCount() == 0) {
|
||||
removeScreens.add(id);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,21 @@
|
|||
|
||||
package com.android.launcher3.config;
|
||||
|
||||
import static androidx.core.util.Preconditions.checkNotNull;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import androidx.annotation.GuardedBy;
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
|
||||
/**
|
||||
* Defines a set of flags used to control various launcher behaviors.
|
||||
*
|
||||
|
@ -23,11 +38,21 @@ package com.android.launcher3.config;
|
|||
*
|
||||
* <p>This class is kept package-private to prevent direct access.
|
||||
*/
|
||||
@Keep
|
||||
abstract class BaseFlags {
|
||||
|
||||
private static final String TAG = "FeatureFlags";
|
||||
private static final Object sLock = new Object();
|
||||
@GuardedBy("sLock")
|
||||
private static final List<TogglableFlag> sFlags = new ArrayList<>();
|
||||
|
||||
static final String FLAGS_PREF_NAME = "featureFlags";
|
||||
|
||||
BaseFlags() {
|
||||
throw new UnsupportedOperationException("Don't instantiate BaseFlags");
|
||||
}
|
||||
|
||||
public static boolean showFlagTogglerUi() {
|
||||
return Utilities.IS_DEBUG_DEVICE;
|
||||
}
|
||||
|
||||
public static final boolean IS_DOGFOOD_BUILD = false;
|
||||
|
@ -36,10 +61,12 @@ abstract class BaseFlags {
|
|||
// When enabled the promise icon is visible in all apps while installation an app.
|
||||
public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
|
||||
|
||||
/** Feature flag to enable moving the QSB on the 0th screen of the workspace. */
|
||||
public boolean isQsbOnFirstScreenEnabled() {
|
||||
return true;
|
||||
}
|
||||
public static final TogglableFlag QSB_ON_FIRST_SCREEN = new TogglableFlag("QSB_ON_FIRST_SCREEN",
|
||||
true,
|
||||
"Enable moving the QSB on the 0th screen of the workspace");
|
||||
|
||||
public static final TogglableFlag EXAMPLE_FLAG = new TogglableFlag("EXAMPLE_FLAG", true,
|
||||
"An example flag that doesn't do anything. Useful for testing");
|
||||
|
||||
//Feature flag to enable pulling down navigation shade from workspace.
|
||||
public static final boolean PULL_DOWN_STATUS_BAR = true;
|
||||
|
@ -56,4 +83,110 @@ abstract class BaseFlags {
|
|||
// When true, overview shows screenshots in the orientation they were taken rather than
|
||||
// trying to make them fit the orientation the device is in.
|
||||
public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
|
||||
|
||||
public static void initialize(Context context) {
|
||||
// Avoid the disk read for builds without the flags UI.
|
||||
if (showFlagTogglerUi()) {
|
||||
SharedPreferences sharedPreferences =
|
||||
context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE);
|
||||
synchronized (sLock) {
|
||||
for (TogglableFlag flag : sFlags) {
|
||||
flag.currentValue = sharedPreferences.getBoolean(flag.key, flag.defaultValue);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
synchronized (sLock) {
|
||||
for (TogglableFlag flag : sFlags) {
|
||||
flag.currentValue = flag.defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static List<TogglableFlag> getTogglableFlags() {
|
||||
// By Java Language Spec 12.4.2
|
||||
// https://docs.oracle.com/javase/specs/jls/se7/html/jls-12.html#jls-12.4.2, the
|
||||
// TogglableFlag instances on BaseFlags will be created before those on the FeatureFlags
|
||||
// subclass. This code handles flags that are redeclared in FeatureFlags, ensuring the
|
||||
// FeatureFlags one takes priority.
|
||||
SortedMap<String, TogglableFlag> flagsByKey = new TreeMap<>();
|
||||
synchronized (sLock) {
|
||||
for (TogglableFlag flag : sFlags) {
|
||||
flagsByKey.put(flag.key, flag);
|
||||
}
|
||||
}
|
||||
return new ArrayList<>(flagsByKey.values());
|
||||
}
|
||||
|
||||
public static final class TogglableFlag {
|
||||
private final String key;
|
||||
private final boolean defaultValue;
|
||||
private final String description;
|
||||
private boolean currentValue;
|
||||
|
||||
TogglableFlag(
|
||||
String key,
|
||||
boolean defaultValue,
|
||||
String description) {
|
||||
this.key = checkNotNull(key);
|
||||
this.defaultValue = defaultValue;
|
||||
this.description = checkNotNull(description);
|
||||
synchronized (sLock) {
|
||||
sFlags.add(this);
|
||||
}
|
||||
}
|
||||
|
||||
String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
boolean getDefaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/** Returns the value of the flag at process start, including any overrides present. */
|
||||
public boolean get() {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
String getDescription() {
|
||||
return description;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "TogglableFlag{"
|
||||
+ "key=" + key + ", "
|
||||
+ "defaultValue=" + defaultValue + ", "
|
||||
+ "description=" + description
|
||||
+ "}";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (o == this) {
|
||||
return true;
|
||||
}
|
||||
if (o instanceof TogglableFlag) {
|
||||
TogglableFlag that = (TogglableFlag) o;
|
||||
return (this.key.equals(that.getKey()))
|
||||
&& (this.defaultValue == that.getDefaultValue())
|
||||
&& (this.description.equals(that.getDescription()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int h$ = 1;
|
||||
h$ *= 1000003;
|
||||
h$ ^= key.hashCode();
|
||||
h$ *= 1000003;
|
||||
h$ ^= defaultValue ? 1231 : 1237;
|
||||
h$ *= 1000003;
|
||||
h$ ^= description.hashCode();
|
||||
return h$;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright (C) 2018 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher3.config;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.os.Process;
|
||||
import android.preference.PreferenceDataStore;
|
||||
import android.preference.PreferenceFragment;
|
||||
import android.preference.SwitchPreference;
|
||||
import android.util.Log;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.BaseFlags.TogglableFlag;
|
||||
|
||||
/**
|
||||
* Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}.
|
||||
*/
|
||||
public final class FlagTogglerPreferenceFragment extends PreferenceFragment {
|
||||
private static final String TAG = "FlagTogglerPrefFrag";
|
||||
|
||||
private SharedPreferences mSharedPreferences;
|
||||
private MenuItem saveButton;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
addPreferencesFromResource(R.xml.flag_preferences);
|
||||
mSharedPreferences = getContext().getSharedPreferences(
|
||||
FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE);
|
||||
|
||||
// For flag overrides we only want to store when the engineer chose to override the
|
||||
// flag with a different value than the default. That way, when we flip flags in
|
||||
// future, engineers will pick up the new value immediately. To accomplish this, we use a
|
||||
// custom preference data store.
|
||||
getPreferenceManager().setPreferenceDataStore(new PreferenceDataStore() {
|
||||
@Override
|
||||
public void putBoolean(String key, boolean value) {
|
||||
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
|
||||
if (flag.getKey().equals(key)) {
|
||||
if (value == flag.getDefaultValue()) {
|
||||
mSharedPreferences.edit().remove(key).apply();
|
||||
} else {
|
||||
mSharedPreferences.edit().putBoolean(key, value).apply();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
|
||||
SwitchPreference switchPreference = new SwitchPreference(getContext());
|
||||
switchPreference.setKey(flag.getKey());
|
||||
switchPreference.setDefaultValue(flag.getDefaultValue());
|
||||
switchPreference.setChecked(getFlagStateFromSharedPrefs(flag));
|
||||
switchPreference.setTitle(flag.getKey());
|
||||
switchPreference.setSummaryOn(flag.getDefaultValue() ? "" : "overridden");
|
||||
switchPreference.setSummaryOff(flag.getDefaultValue() ? "overridden" : "");
|
||||
getPreferenceScreen().addPreference(switchPreference);
|
||||
}
|
||||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
saveButton = menu.add("Apply");
|
||||
saveButton.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
if (item == saveButton) {
|
||||
mSharedPreferences.edit().commit();
|
||||
Log.e(TAG,
|
||||
"Killing launcher process " + Process.myPid() + " to apply new flag values");
|
||||
System.exit(0);
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
boolean anyChanged = false;
|
||||
for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) {
|
||||
anyChanged = anyChanged ||
|
||||
getFlagStateFromSharedPrefs(flag) != flag.get();
|
||||
}
|
||||
|
||||
if (anyChanged) {
|
||||
Toast.makeText(
|
||||
getContext(),
|
||||
"Flag won't be applied until you restart launcher",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
private boolean getFlagStateFromSharedPrefs(TogglableFlag flag) {
|
||||
return mSharedPreferences.getBoolean(flag.getKey(), flag.getDefaultValue());
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ import android.database.Cursor;
|
|||
import android.graphics.Point;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.ItemInfo;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
|
@ -109,6 +110,7 @@ public class GridSizeMigrationTask {
|
|||
|
||||
/**
|
||||
* Applied all the pending DB operations
|
||||
*
|
||||
* @return true if any DB operation was commited.
|
||||
*/
|
||||
private boolean applyOperations() throws Exception {
|
||||
|
@ -135,6 +137,7 @@ public class GridSizeMigrationTask {
|
|||
* entries is more than what can fit in the new hotseat, we drop the entries with least weight.
|
||||
* For weight calculation {@see #WT_SHORTCUT}, {@see #WT_APPLICATION}
|
||||
* & {@see #WT_FOLDER_FACTOR}.
|
||||
*
|
||||
* @return true if any DB change was made
|
||||
*/
|
||||
protected boolean migrateHotseat() throws Exception {
|
||||
|
@ -235,7 +238,8 @@ public class GridSizeMigrationTask {
|
|||
int screenId = allScreens.get(i);
|
||||
v.put(LauncherSettings.WorkspaceScreens._ID, screenId);
|
||||
v.put(LauncherSettings.WorkspaceScreens.SCREEN_RANK, i);
|
||||
mUpdateOperations.add(ContentProviderOperation.newInsert(uri).withValues(v).build());
|
||||
mUpdateOperations.add(ContentProviderOperation.newInsert(uri).withValues(
|
||||
v).build());
|
||||
}
|
||||
}
|
||||
return applyOperations();
|
||||
|
@ -254,8 +258,7 @@ public class GridSizeMigrationTask {
|
|||
protected void migrateScreen(int screenId) {
|
||||
// If we are migrating the first screen, do not touch the first row.
|
||||
int startY =
|
||||
(FeatureFlags.getInstance(mContext).isQsbOnFirstScreenEnabled()
|
||||
&& screenId == Workspace.FIRST_SCREEN_ID)
|
||||
(FeatureFlags.QSB_ON_FIRST_SCREEN.get() && screenId == Workspace.FIRST_SCREEN_ID)
|
||||
? 1 : 0;
|
||||
|
||||
ArrayList<DbEntry> items = loadWorkspaceEntries(screenId);
|
||||
|
@ -280,9 +283,11 @@ public class GridSizeMigrationTask {
|
|||
for (int y = mSrcY - 1; y >= startY; y--) {
|
||||
// Use a deep copy when trying out a particular combination as it can change
|
||||
// the underlying object.
|
||||
ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items), outLoss);
|
||||
ArrayList<DbEntry> itemsOnScreen = tryRemove(x, y, startY, deepCopy(items),
|
||||
outLoss);
|
||||
|
||||
if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1] < moveWt))) {
|
||||
if ((outLoss[0] < removeWt) || ((outLoss[0] == removeWt) && (outLoss[1]
|
||||
< moveWt))) {
|
||||
removeWt = outLoss[0];
|
||||
moveWt = outLoss[1];
|
||||
removedCol = mShouldRemoveX ? x : removedCol;
|
||||
|
@ -363,6 +368,7 @@ public class GridSizeMigrationTask {
|
|||
|
||||
/**
|
||||
* Tries the remove the provided row and column.
|
||||
*
|
||||
* @param items all the items on the screen under operation
|
||||
* @param outLoss array of size 2. The first entry is filled with weight loss, and the second
|
||||
* with the overall item movement.
|
||||
|
@ -438,6 +444,7 @@ public class GridSizeMigrationTask {
|
|||
|
||||
/**
|
||||
* Recursively finds a placement for the provided items.
|
||||
*
|
||||
* @param index the position in {@link #itemsToPlace} to start looking at.
|
||||
* @param weightLoss total weight loss upto this point
|
||||
* @param moveCost total move cost upto this point
|
||||
|
@ -550,7 +557,8 @@ public class GridSizeMigrationTask {
|
|||
for (int x = 0; x < mTrgX; x++) {
|
||||
if (!occupied.cells[x][y]) {
|
||||
int dist = ignoreMove ? 0 :
|
||||
((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY - y));
|
||||
((me.cellX - x) * (me.cellX - x) + (me.cellY - y) * (me.cellY
|
||||
- y));
|
||||
if (dist < newDistance) {
|
||||
newX = x;
|
||||
newY = y;
|
||||
|
@ -815,7 +823,8 @@ public class GridSizeMigrationTask {
|
|||
|
||||
public float weight;
|
||||
|
||||
public DbEntry() { }
|
||||
public DbEntry() {
|
||||
}
|
||||
|
||||
public DbEntry copy() {
|
||||
DbEntry entry = new DbEntry();
|
||||
|
@ -887,6 +896,7 @@ public class GridSizeMigrationTask {
|
|||
|
||||
/**
|
||||
* Migrates the workspace and hotseat in case their sizes changed.
|
||||
*
|
||||
* @return false if the migration failed.
|
||||
*/
|
||||
public static boolean migrateGridIfNeeded(Context context) {
|
||||
|
@ -896,7 +906,8 @@ public class GridSizeMigrationTask {
|
|||
String gridSizeString = getPointString(idp.numColumns, idp.numRows);
|
||||
|
||||
if (gridSizeString.equals(prefs.getString(KEY_MIGRATION_SRC_WORKSPACE_SIZE, "")) &&
|
||||
idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons)) {
|
||||
idp.numHotseatIcons == prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
|
||||
idp.numHotseatIcons)) {
|
||||
// Skip if workspace and hotseat sizes have not changed.
|
||||
return true;
|
||||
}
|
||||
|
@ -907,7 +918,8 @@ public class GridSizeMigrationTask {
|
|||
|
||||
HashSet<String> validPackages = getValidPackages(context);
|
||||
// Hotseat
|
||||
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT, idp.numHotseatIcons);
|
||||
int srcHotseatCount = prefs.getInt(KEY_MIGRATION_SRC_HOTSEAT_COUNT,
|
||||
idp.numHotseatIcons);
|
||||
if (srcHotseatCount != idp.numHotseatIcons) {
|
||||
// Migrate hotseat.
|
||||
|
||||
|
@ -920,7 +932,8 @@ public class GridSizeMigrationTask {
|
|||
Point sourceSize = parsePoint(prefs.getString(
|
||||
KEY_MIGRATION_SRC_WORKSPACE_SIZE, gridSizeString));
|
||||
|
||||
if (new MultiStepMigrationTask(validPackages, context).migrate(sourceSize, targetSize)) {
|
||||
if (new MultiStepMigrationTask(validPackages, context).migrate(sourceSize,
|
||||
targetSize)) {
|
||||
dbChanged = true;
|
||||
}
|
||||
|
||||
|
@ -970,9 +983,11 @@ public class GridSizeMigrationTask {
|
|||
|
||||
/**
|
||||
* Removes any broken item from the hotseat.
|
||||
*
|
||||
* @return a map with occupied hotseat position set to non-null value.
|
||||
*/
|
||||
public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context) throws Exception {
|
||||
public static IntSparseArrayMap<Object> removeBrokenHotseatItems(Context context)
|
||||
throws Exception {
|
||||
GridSizeMigrationTask task = new GridSizeMigrationTask(
|
||||
context, LauncherAppState.getIDP(context), getValidPackages(context),
|
||||
Integer.MAX_VALUE, Integer.MAX_VALUE);
|
||||
|
|
|
@ -441,7 +441,7 @@ public class LoaderCursor extends CursorWrapper {
|
|||
// Mark the first row as occupied (if the feature is enabled)
|
||||
// in order to account for the QSB.
|
||||
screen.markCells(0, 0, countX + 1, 1,
|
||||
FeatureFlags.getInstance(mContext).isQsbOnFirstScreenEnabled());
|
||||
FeatureFlags.QSB_ON_FIRST_SCREEN.get());
|
||||
}
|
||||
occupied.put(item.screenId, screen);
|
||||
}
|
||||
|
|
|
@ -136,7 +136,7 @@ public class ImportDataTask {
|
|||
.getSerialNumberForUser(Process.myUserHandle()));
|
||||
|
||||
boolean createEmptyRowOnFirstScreen;
|
||||
if (FeatureFlags.getInstance(mContext).isQsbOnFirstScreenEnabled()) {
|
||||
if (FeatureFlags.QSB_ON_FIRST_SCREEN.get()) {
|
||||
try (Cursor c = mContext.getContentResolver().query(mOtherFavoritesUri, null,
|
||||
// get items on the first row of the first screen
|
||||
"profileId = ? AND container = -100 AND screen = ? AND cellY = 0",
|
||||
|
|
|
@ -213,7 +213,7 @@ public class QsbContainerView extends FrameLayout {
|
|||
}
|
||||
|
||||
public boolean isQsbEnabled() {
|
||||
return FeatureFlags.getInstance(getContext()).isQsbOnFirstScreenEnabled();
|
||||
return FeatureFlags.QSB_ON_FIRST_SCREEN.get();
|
||||
}
|
||||
|
||||
protected Bundle createBindOptions() {
|
||||
|
|
|
@ -22,11 +22,7 @@ import android.content.Context;
|
|||
* Defines a set of flags used to control various launcher behaviors
|
||||
*/
|
||||
public final class FeatureFlags extends BaseFlags {
|
||||
private static FeatureFlags instance = new FeatureFlags();
|
||||
|
||||
public static FeatureFlags getInstance(Context context) {
|
||||
return instance;
|
||||
private FeatureFlags() {
|
||||
// Prevent instantiation
|
||||
}
|
||||
|
||||
private FeatureFlags() {}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue