Bug 967742 - Consolidate API to edit HomeConfig state (r=margaret)

This commit is contained in:
Lucas Rocha 2014-03-07 17:15:31 +00:00
Родитель 62e731fdff
Коммит b9b49b223e
6 изменённых файлов: 468 добавлений и 210 удалений

Просмотреть файл

@ -6,6 +6,7 @@
package org.mozilla.gecko.home;
import org.mozilla.gecko.R;
import org.mozilla.gecko.util.ThreadUtils;
import org.json.JSONArray;
import org.json.JSONException;
@ -17,7 +18,11 @@ import android.os.Parcelable;
import android.text.TextUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
public final class HomeConfig {
@ -265,7 +270,7 @@ public final class HomeConfig {
return mFlags.contains(Flags.DEFAULT_PANEL);
}
public void setIsDefault(boolean isDefault) {
private void setIsDefault(boolean isDefault) {
if (isDefault) {
mFlags.add(Flags.DEFAULT_PANEL);
} else {
@ -277,7 +282,7 @@ public final class HomeConfig {
return mFlags.contains(Flags.DISABLED_PANEL);
}
public void setIsDisabled(boolean isDisabled) {
private void setIsDisabled(boolean isDisabled) {
if (isDisabled) {
mFlags.add(Flags.DISABLED_PANEL);
} else {
@ -692,6 +697,374 @@ public final class HomeConfig {
};
}
/**
* Immutable representation of the current state of {@code HomeConfig}.
* This is what HomeConfig returns from a load() call and takes as
* input to save a new state.
*
* Users of {@code State} should use an {@code Iterator} to iterate
* through the contained {@code PanelConfig} instances.
*
* {@code State} is immutable i.e. you can't add, remove, or update
* contained elements directly. You have to use an {@code Editor} to
* change the state, which can be created through the {@code edit()}
* method.
*/
public static class State implements Iterable<PanelConfig> {
private final HomeConfig mHomeConfig;
private final List<PanelConfig> mPanelConfigs;
private State(HomeConfig homeConfig, List<PanelConfig> panelConfigs) {
mHomeConfig = homeConfig;
mPanelConfigs = Collections.unmodifiableList(panelConfigs);
}
@Override
public Iterator<PanelConfig> iterator() {
return mPanelConfigs.iterator();
}
/**
* Creates an {@code Editor} for this state.
*/
public Editor edit() {
return new Editor(mHomeConfig, this);
}
}
/**
* {@code Editor} allows you to make changes to a {@code State}. You
* can create {@code Editor} by calling {@code edit()} on the target
* {@code State} instance.
*
* {@code Editor} works on a copy of the {@code State} that originated
* it. This means that adding, removing, or updating panels in an
* {@code Editor} will never change the {@code State} which you
* created the {@code Editor} from. Calling {@code commit()} or
* {@code apply()} will cause the new {@code State} instance to be
* created and saved using the {@code HomeConfig} instance that
* created the source {@code State}.
*
* {@code Editor} is *not* thread-safe. You can only make calls on it
* from the thread where it was originally created. It will throw an
* exception if you don't follow this invariant.
*/
public static class Editor implements Iterable<PanelConfig> {
private final HomeConfig mHomeConfig;
private final HashMap<String, PanelConfig> mConfigMap;
private final Thread mOriginalThread;
private PanelConfig mDefaultPanel;
private int mEnabledCount;
private Editor(HomeConfig homeConfig, State configState) {
mHomeConfig = homeConfig;
mOriginalThread = Thread.currentThread();
mConfigMap = new LinkedHashMap<String, PanelConfig>();
mEnabledCount = 0;
initFromState(configState);
}
/**
* Initialize the initial state of the editor from the given
* {@sode State}. A LinkedHashMap is used to represent the list of
* panels as it provides fast access to specific panels from IDs
* while also being order-aware. We keep a reference to the
* default panel and the number of enabled panels to avoid iterating
* through the map every time we need those.
*
* @param configState The source State to load the editor from.
*/
private void initFromState(State configState) {
for (PanelConfig panelConfig : configState) {
final PanelConfig panelCopy = new PanelConfig(panelConfig);
if (!panelCopy.isDisabled()) {
mEnabledCount++;
}
if (panelCopy.isDefault()) {
if (mDefaultPanel == null) {
mDefaultPanel = panelCopy;
} else {
throw new IllegalStateException("Multiple default panels in HomeConfig state");
}
}
mConfigMap.put(panelConfig.getId(), panelCopy);
}
// We should always have a defined default panel if there's
// at least one enabled panel around.
if (mEnabledCount > 0 && mDefaultPanel == null) {
throw new IllegalStateException("Default panel in HomeConfig state is undefined");
}
}
private PanelConfig getPanelOrThrow(String panelId) {
final PanelConfig panelConfig = mConfigMap.get(panelId);
if (panelConfig == null) {
throw new IllegalStateException("Tried to access non-existing panel: " + panelId);
}
return panelConfig;
}
private boolean isCurrentDefaultPanel(PanelConfig panelConfig) {
if (mDefaultPanel == null) {
return false;
}
return mDefaultPanel.equals(panelConfig);
}
private void findNewDefault() {
// Pick the first panel that is neither disabled nor currently
// set as default.
for (PanelConfig panelConfig : mConfigMap.values()) {
if (!panelConfig.isDefault() && !panelConfig.isDisabled()) {
setDefault(panelConfig.getId());
return;
}
}
mDefaultPanel = null;
}
private List<PanelConfig> makeDeepCopy() {
List<PanelConfig> copiedList = new ArrayList<PanelConfig>();
for (PanelConfig panelConfig : mConfigMap.values()) {
copiedList.add(new PanelConfig(panelConfig));
}
return copiedList;
}
private void setPanelIsDisabled(PanelConfig panelConfig, boolean disabled) {
if (panelConfig.isDisabled() == disabled) {
return;
}
panelConfig.setIsDisabled(disabled);
mEnabledCount += (disabled ? -1 : 1);
}
/**
* Gets the ID of the current default panel.
*/
public String getDefaultPanelId() {
ThreadUtils.assertOnThread(mOriginalThread);
if (mDefaultPanel == null) {
return null;
}
return mDefaultPanel.getId();
}
/**
* Set a new default panel.
*
* @param panelId the ID of the new default panel.
*/
public void setDefault(String panelId) {
ThreadUtils.assertOnThread(mOriginalThread);
final PanelConfig panelConfig = getPanelOrThrow(panelId);
if (isCurrentDefaultPanel(panelConfig)) {
return;
}
if (mDefaultPanel != null) {
mDefaultPanel.setIsDefault(false);
}
panelConfig.setIsDefault(true);
setPanelIsDisabled(panelConfig, false);
mDefaultPanel = panelConfig;
}
/**
* Toggles disabled state for a panel.
*
* @param panelId the ID of the target panel.
* @param disabled true to disable the panel.
*/
public void setDisabled(String panelId, boolean disabled) {
ThreadUtils.assertOnThread(mOriginalThread);
final PanelConfig panelConfig = getPanelOrThrow(panelId);
if (panelConfig.isDisabled() == disabled) {
return;
}
setPanelIsDisabled(panelConfig, disabled);
if (disabled) {
if (isCurrentDefaultPanel(panelConfig)) {
panelConfig.setIsDefault(false);
findNewDefault();
}
} else if (mEnabledCount == 1) {
setDefault(panelId);
}
}
/**
* Adds a new {@code PanelConfig}. It will do nothing if the
* {@code Editor} already contains a panel with the same ID.
*
* @param panelConfig the {@code PanelConfig} instance to be added.
* @return true if the item has been added.
*/
public boolean install(PanelConfig panelConfig) {
ThreadUtils.assertOnThread(mOriginalThread);
if (panelConfig == null) {
throw new IllegalStateException("Can't install a null panel");
}
if (!panelConfig.isDynamic()) {
throw new IllegalStateException("Can't install a built-in panel: " + panelConfig.getId());
}
if (panelConfig.isDisabled()) {
throw new IllegalStateException("Can't install a disabled panel: " + panelConfig.getId());
}
boolean installed = false;
final String id = panelConfig.getId();
if (!mConfigMap.containsKey(id)) {
mConfigMap.put(id, panelConfig);
mEnabledCount++;
if (mEnabledCount == 1 || panelConfig.isDefault()) {
setDefault(panelConfig.getId());
}
installed = true;
}
return installed;
}
/**
* Removes an existing panel.
*
* @return true if the item has been removed.
*/
public boolean uninstall(String panelId) {
ThreadUtils.assertOnThread(mOriginalThread);
final PanelConfig panelConfig = mConfigMap.get(panelId);
if (panelConfig == null) {
return false;
}
if (!panelConfig.isDynamic()) {
throw new IllegalStateException("Can't uninstall a built-in panel: " + panelConfig.getId());
}
mConfigMap.remove(panelId);
if (!panelConfig.isDisabled()) {
mEnabledCount--;
}
if (isCurrentDefaultPanel(panelConfig)) {
findNewDefault();
}
return true;
}
/**
* Replaces an existing panel with a new {@code PanelConfig} instance.
*
* @return true if the item has been updated.
*/
public boolean update(PanelConfig panelConfig) {
ThreadUtils.assertOnThread(mOriginalThread);
if (panelConfig == null) {
throw new IllegalStateException("Can't update a null panel");
}
boolean updated = false;
final String id = panelConfig.getId();
if (mConfigMap.containsKey(id)) {
final PanelConfig oldPanelConfig = mConfigMap.put(id, panelConfig);
// The disabled and default states can't never be
// changed by an update operation.
panelConfig.setIsDefault(oldPanelConfig.isDefault());
panelConfig.setIsDisabled(oldPanelConfig.isDisabled());
updated = true;
}
return updated;
}
/**
* Saves the current {@code Editor} state asynchronously in the
* background thread.
*
* @return the resulting {@code State} instance.
*/
public State apply() {
ThreadUtils.assertOnThread(mOriginalThread);
// We're about to save the current state in the background thread
// so we should use a deep copy of the PanelConfig instances to
// avoid saving corrupted state.
final State newConfigState = new State(mHomeConfig, makeDeepCopy());
ThreadUtils.getBackgroundHandler().post(new Runnable() {
@Override
public void run() {
mHomeConfig.save(newConfigState);
}
});
return newConfigState;
}
/**
* Saves the current {@code Editor} state synchronously in the
* current thread.
*
* @return the resulting {@code State} instance.
*/
public State commit() {
ThreadUtils.assertOnThread(mOriginalThread);
final State newConfigState =
new State(mHomeConfig, new ArrayList<PanelConfig>(mConfigMap.values()));
// This is a synchronous blocking operation, hence no
// need to deep copy the current PanelConfig instances.
mHomeConfig.save(newConfigState);
return newConfigState;
}
public boolean isEmpty() {
return mConfigMap.isEmpty();
}
@Override
public Iterator<PanelConfig> iterator() {
ThreadUtils.assertOnThread(mOriginalThread);
return mConfigMap.values().iterator();
}
}
public interface OnChangeListener {
public void onChange();
}
@ -715,16 +1088,17 @@ public final class HomeConfig {
mBackend = backend;
}
public List<PanelConfig> load() {
return mBackend.load();
public State load() {
final List<PanelConfig> panelConfigs = mBackend.load();
return new State(this, panelConfigs);
}
public String getLocale() {
return mBackend.getLocale();
}
public void save(List<PanelConfig> panelConfigs) {
mBackend.save(panelConfigs);
public void save(State configState) {
mBackend.save(configState.mPanelConfigs);
}
public void setOnChangeListener(OnChangeListener listener) {

Просмотреть файл

@ -189,36 +189,10 @@ public class HomeConfigInvalidator implements GeckoEventListener {
Log.d(LOGTAG, "scheduleInvalidation: scheduled new invalidation: " + mode);
}
/**
* Replace an element if a matching PanelConfig is
* present in the given list.
*/
private boolean replacePanelConfig(List<PanelConfig> panelConfigs, PanelConfig panelConfig) {
final int index = panelConfigs.indexOf(panelConfig);
if (index >= 0) {
panelConfigs.set(index, panelConfig);
Log.d(LOGTAG, "executePendingChanges: replaced position " + index + " with " + panelConfig.getId());
return true;
}
return false;
}
private PanelConfig findPanelConfigWithId(List<PanelConfig> panelConfigs, String panelId) {
for (PanelConfig panelConfig : panelConfigs) {
if (panelConfig.getId().equals(panelId)) {
return panelConfig;
}
}
return null;
}
/**
* Runs in the background thread.
*/
private List<PanelConfig> executePendingChanges(List<PanelConfig> panelConfigs) {
private void executePendingChanges(HomeConfig.Editor editor) {
boolean shouldRefresh = false;
while (!mPendingChanges.isEmpty()) {
@ -227,17 +201,15 @@ public class HomeConfigInvalidator implements GeckoEventListener {
switch (pendingChange.type) {
case UNINSTALL: {
final String panelId = (String) pendingChange.target;
final PanelConfig panelConfig = findPanelConfigWithId(panelConfigs, panelId);
if (panelConfig != null && panelConfigs.remove(panelConfig)) {
Log.d(LOGTAG, "executePendingChanges: removed panel " + panelConfig.getId());
if (editor.uninstall(panelId)) {
Log.d(LOGTAG, "executePendingChanges: uninstalled panel " + panelId);
}
break;
}
case INSTALL: {
final PanelConfig panelConfig = (PanelConfig) pendingChange.target;
if (!replacePanelConfig(panelConfigs, panelConfig)) {
panelConfigs.add(panelConfig);
if (editor.install(panelConfig)) {
Log.d(LOGTAG, "executePendingChanges: added panel " + panelConfig.getId());
}
break;
@ -245,8 +217,8 @@ public class HomeConfigInvalidator implements GeckoEventListener {
case UPDATE: {
final PanelConfig panelConfig = (PanelConfig) pendingChange.target;
if (!replacePanelConfig(panelConfigs, panelConfig)) {
Log.w(LOGTAG, "Tried to update non-existing panel " + panelConfig.getId());
if (editor.update(panelConfig)) {
Log.w(LOGTAG, "executePendingChanges: updated panel " + panelConfig.getId());
}
break;
}
@ -258,23 +230,19 @@ public class HomeConfigInvalidator implements GeckoEventListener {
}
if (shouldRefresh) {
return executeRefresh(panelConfigs);
} else {
return panelConfigs;
executeRefresh(editor);
}
}
/**
* Runs in the background thread.
*/
private List<PanelConfig> refreshFromPanelInfos(List<PanelConfig> panelConfigs, List<PanelInfo> panelInfos) {
private void refreshFromPanelInfos(HomeConfig.Editor editor, List<PanelInfo> panelInfos) {
Log.d(LOGTAG, "refreshFromPanelInfos");
final int count = panelConfigs.size();
for (int i = 0; i < count; i++) {
final PanelConfig panelConfig = panelConfigs.get(i);
for (PanelConfig panelConfig : editor) {
PanelConfig refreshedPanelConfig = null;
if (panelConfig.isDynamic()) {
for (PanelInfo panelInfo : panelInfos) {
if (panelInfo.getId().equals(panelConfig.getId())) {
@ -290,31 +258,26 @@ public class HomeConfigInvalidator implements GeckoEventListener {
if (refreshedPanelConfig == null) {
Log.d(LOGTAG, "refreshFromPanelInfos: no refreshed panel, falling back: " + panelConfig.getId());
refreshedPanelConfig = panelConfig;
continue;
}
refreshedPanelConfig.setIsDefault(panelConfig.isDefault());
refreshedPanelConfig.setIsDisabled(panelConfig.isDisabled());
Log.d(LOGTAG, "refreshFromPanelInfos: set " + i + " with " + refreshedPanelConfig.getId());
panelConfigs.set(i, refreshedPanelConfig);
Log.d(LOGTAG, "refreshFromPanelInfos: refreshed panel " + refreshedPanelConfig.getId());
editor.update(refreshedPanelConfig);
}
return panelConfigs;
}
/**
* Runs in the background thread.
*/
private List<PanelConfig> executeRefresh(List<PanelConfig> panelConfigs) {
if (panelConfigs.isEmpty()) {
return panelConfigs;
private void executeRefresh(HomeConfig.Editor editor) {
if (editor.isEmpty()) {
return;
}
Log.d(LOGTAG, "executeRefresh");
final Set<String> ids = new HashSet<String>();
for (PanelConfig panelConfig : panelConfigs) {
for (PanelConfig panelConfig : editor) {
ids.add(panelConfig.getId());
}
@ -339,11 +302,10 @@ public class HomeConfigInvalidator implements GeckoEventListener {
panelRequestLock.wait(PANEL_INFO_TIMEOUT_MSEC);
Log.d(LOGTAG, "executeRefresh: done fetching panel infos");
return refreshFromPanelInfos(panelConfigs, latestPanelInfos);
refreshFromPanelInfos(editor, latestPanelInfos);
}
} catch (InterruptedException e) {
Log.e(LOGTAG, "Failed to fetch panels from gecko", e);
return panelConfigs;
}
}
@ -353,7 +315,9 @@ public class HomeConfigInvalidator implements GeckoEventListener {
private class InvalidationRunnable implements Runnable {
@Override
public void run() {
mHomeConfig.save(executePendingChanges(mHomeConfig.load()));
final HomeConfig.Editor editor = mHomeConfig.load().edit();
executePendingChanges(editor);
editor.commit();
}
};
}

Просмотреть файл

@ -13,9 +13,9 @@ import android.support.v4.content.AsyncTaskLoader;
import java.util.List;
public class HomeConfigLoader extends AsyncTaskLoader<List<PanelConfig>> {
public class HomeConfigLoader extends AsyncTaskLoader<HomeConfig.State> {
private final HomeConfig mConfig;
private List<PanelConfig> mPanelConfigs;
private HomeConfig.State mConfigState;
public HomeConfigLoader(Context context, HomeConfig homeConfig) {
super(context);
@ -23,32 +23,32 @@ public class HomeConfigLoader extends AsyncTaskLoader<List<PanelConfig>> {
}
@Override
public List<PanelConfig> loadInBackground() {
public HomeConfig.State loadInBackground() {
return mConfig.load();
}
@Override
public void deliverResult(List<PanelConfig> panelConfigs) {
public void deliverResult(HomeConfig.State configState) {
if (isReset()) {
mPanelConfigs = null;
mConfigState = null;
return;
}
mPanelConfigs = panelConfigs;
mConfigState = configState;
mConfig.setOnChangeListener(new ForceLoadChangeListener());
if (isStarted()) {
super.deliverResult(panelConfigs);
super.deliverResult(configState);
}
}
@Override
protected void onStartLoading() {
if (mPanelConfigs != null) {
deliverResult(mPanelConfigs);
if (mConfigState != null) {
deliverResult(mConfigState);
}
if (takeContentChanged() || mPanelConfigs == null) {
if (takeContentChanged() || mConfigState == null) {
forceLoad();
}
}
@ -59,8 +59,8 @@ public class HomeConfigLoader extends AsyncTaskLoader<List<PanelConfig>> {
}
@Override
public void onCanceled(List<PanelConfig> panelConfigs) {
mPanelConfigs = null;
public void onCanceled(HomeConfig.State configState) {
mConfigState = null;
}
@Override
@ -70,7 +70,7 @@ public class HomeConfigLoader extends AsyncTaskLoader<List<PanelConfig>> {
// Ensure the loader is stopped.
onStopLoading();
mPanelConfigs = null;
mConfigState = null;
mConfig.setOnChangeListener(null);
}

Просмотреть файл

@ -250,7 +250,7 @@ public class HomePager extends ViewPager {
mHomeBanner.setActive(active);
}
private void updateUiFromPanelConfigs(List<PanelConfig> panelConfigs) {
private void updateUiFromConfigState(HomeConfig.State configState) {
// We only care about the adapter if HomePager is currently
// loaded, which means it's visible in the activity.
if (!mLoaded) {
@ -270,7 +270,7 @@ public class HomePager extends ViewPager {
// Only keep enabled panels.
final List<PanelConfig> enabledPanels = new ArrayList<PanelConfig>();
for (PanelConfig panelConfig : panelConfigs) {
for (PanelConfig panelConfig : configState) {
if (!panelConfig.isDisabled()) {
enabledPanels.add(panelConfig);
}
@ -314,19 +314,19 @@ public class HomePager extends ViewPager {
}
}
private class ConfigLoaderCallbacks implements LoaderCallbacks<List<PanelConfig>> {
private class ConfigLoaderCallbacks implements LoaderCallbacks<HomeConfig.State> {
@Override
public Loader<List<PanelConfig>> onCreateLoader(int id, Bundle args) {
public Loader<HomeConfig.State> onCreateLoader(int id, Bundle args) {
return new HomeConfigLoader(mContext, mConfig);
}
@Override
public void onLoadFinished(Loader<List<PanelConfig>> loader, List<PanelConfig> panelConfigs) {
updateUiFromPanelConfigs(panelConfigs);
public void onLoadFinished(Loader<HomeConfig.State> loader, HomeConfig.State configState) {
updateUiFromConfigState(configState);
}
@Override
public void onLoaderReset(Loader<List<PanelConfig>> loader) {
public void onLoaderReset(Loader<HomeConfig.State> loader) {
}
}

Просмотреть файл

@ -224,17 +224,17 @@ public class HomePanelPicker extends FragmentActivity {
/**
* Fetch installed Home panels and update the adapter for this activity.
*/
private class ConfigLoaderCallbacks implements LoaderCallbacks<List<PanelConfig>> {
private class ConfigLoaderCallbacks implements LoaderCallbacks<HomeConfig.State> {
@Override
public Loader<List<PanelConfig>> onCreateLoader(int id, Bundle args) {
public Loader<HomeConfig.State> onCreateLoader(int id, Bundle args) {
final HomeConfig homeConfig = HomeConfig.getDefault(HomePanelPicker.this);
return new HomeConfigLoader(HomePanelPicker.this, homeConfig);
}
@Override
public void onLoadFinished(Loader<List<PanelConfig>> loader, List<PanelConfig> panelConfigs) {
public void onLoadFinished(Loader<HomeConfig.State> loader, HomeConfig.State configState) {
mCurrentPanelsIds = new ArrayList<String>();
for (PanelConfig panelConfig : panelConfigs) {
for (PanelConfig panelConfig : configState) {
mCurrentPanelsIds.add(panelConfig.getId());
}
@ -242,6 +242,6 @@ public class HomePanelPicker extends FragmentActivity {
}
@Override
public void onLoaderReset(Loader<List<PanelConfig>> loader) {}
public void onLoaderReset(Loader<HomeConfig.State> loader) {}
}
}

Просмотреть файл

@ -20,10 +20,9 @@ public class PanelsPreferenceCategory extends CustomListCategory {
public static final String LOGTAG = "PanelsPrefCategory";
protected HomeConfig mHomeConfig;
protected List<PanelConfig> mPanelConfigs;
protected HomeConfig.Editor mConfigEditor;
protected UiAsyncTask<Void, Void, List<PanelConfig>> mLoadTask;
protected UiAsyncTask<Void, Void, Void> mSaveTask;
protected UiAsyncTask<Void, Void, HomeConfig.State> mLoadTask;
public PanelsPreferenceCategory(Context context) {
super(context);
@ -55,23 +54,23 @@ public class PanelsPreferenceCategory extends CustomListCategory {
* Load the Home Panels config and populate the preferences screen and maintain local state.
*/
private void loadHomeConfig() {
mLoadTask = new UiAsyncTask<Void, Void, List<PanelConfig>>(ThreadUtils.getBackgroundHandler()) {
mLoadTask = new UiAsyncTask<Void, Void, HomeConfig.State>(ThreadUtils.getBackgroundHandler()) {
@Override
public List<PanelConfig> doInBackground(Void... params) {
public HomeConfig.State doInBackground(Void... params) {
return mHomeConfig.load();
}
@Override
public void onPostExecute(List<PanelConfig> panelConfigs) {
mPanelConfigs = panelConfigs;
displayHomeConfig();
public void onPostExecute(HomeConfig.State configState) {
mConfigEditor = configState.edit();
displayHomeConfig(configState);
}
};
mLoadTask.execute();
}
private void displayHomeConfig() {
for (PanelConfig panelConfig : mPanelConfigs) {
private void displayHomeConfig(HomeConfig.State configState) {
for (PanelConfig panelConfig : configState) {
// Create and add the pref.
final PanelsPreference pref = new PanelsPreference(getContext(), PanelsPreferenceCategory.this);
pref.setTitle(panelConfig.getTitle());
@ -79,51 +78,47 @@ public class PanelsPreferenceCategory extends CustomListCategory {
// XXX: Pull icon from PanelInfo.
addPreference(pref);
if (panelConfig.isDefault()) {
mDefaultReference = pref;
pref.setIsDefault(true);
}
if (panelConfig.isDisabled()) {
pref.setHidden(true);
}
}
setDefaultFromConfig();
}
/**
* Update HomeConfig off the main thread.
*
* @param panelConfigs Configuration to be saved
*/
private void saveHomeConfig() {
if (mPanelConfigs == null) {
private void setDefaultFromConfig() {
final String defaultPanelId = mConfigEditor.getDefaultPanelId();
if (defaultPanelId == null) {
mDefaultReference = null;
return;
}
final List<PanelConfig> panelConfigs = makeConfigListDeepCopy();
mSaveTask = new UiAsyncTask<Void, Void, Void>(ThreadUtils.getBackgroundHandler()) {
@Override
public Void doInBackground(Void... params) {
mHomeConfig.save(panelConfigs);
return null;
}
};
mSaveTask.execute();
}
final int prefCount = getPreferenceCount();
private List<PanelConfig> makeConfigListDeepCopy() {
List<PanelConfig> copiedList = new ArrayList<PanelConfig>();
for (PanelConfig panelConfig : mPanelConfigs) {
copiedList.add(new PanelConfig(panelConfig));
// First preference (index 0) is Preference to add panels.
for (int i = 1; i < prefCount; i++) {
final PanelsPreference pref = (PanelsPreference) getPreference(i);
if (defaultPanelId.equals(pref.getKey())) {
super.setDefault(pref);
break;
}
}
return copiedList;
}
@Override
public void setDefault(CustomListPreference pref) {
super.setDefault(pref);
updateConfigDefault();
saveHomeConfig();
final String id = pref.getKey();
final String defaultPanelId = mConfigEditor.getDefaultPanelId();
if (defaultPanelId != null && defaultPanelId.equals(id)) {
return;
}
mConfigEditor.setDefault(id);
mConfigEditor.apply();
}
@Override
@ -131,48 +126,14 @@ public class PanelsPreferenceCategory extends CustomListCategory {
if (mLoadTask != null) {
mLoadTask.cancel(true);
}
if (mSaveTask != null) {
mSaveTask.cancel(true);
}
}
/**
* Update the local HomeConfig default state from mDefaultReference.
*/
private void updateConfigDefault() {
String id = null;
if (mDefaultReference != null) {
id = mDefaultReference.getKey();
}
for (PanelConfig panelConfig : mPanelConfigs) {
if (TextUtils.equals(panelConfig.getId(), id)) {
panelConfig.setIsDefault(true);
panelConfig.setIsDisabled(false);
} else {
panelConfig.setIsDefault(false);
}
}
}
@Override
public void uninstall(CustomListPreference pref) {
mConfigEditor.uninstall(pref.getKey());
mConfigEditor.apply();
super.uninstall(pref);
// This could change the default, so update the local version of the config.
updateConfigDefault();
final String id = pref.getKey();
PanelConfig toRemove = null;
for (PanelConfig panelConfig : mPanelConfigs) {
if (TextUtils.equals(panelConfig.getId(), id)) {
toRemove = panelConfig;
break;
}
}
mPanelConfigs.remove(toRemove);
saveHomeConfig();
}
/**
@ -183,43 +144,11 @@ public class PanelsPreferenceCategory extends CustomListCategory {
* @param toHide New hidden state of the preference
*/
protected void setHidden(PanelsPreference pref, boolean toHide) {
mConfigEditor.setDisabled(pref.getKey(), toHide);
mConfigEditor.apply();
pref.setHidden(toHide);
ensureDefaultForHide(pref, toHide);
final String id = pref.getKey();
for (PanelConfig panelConfig : mPanelConfigs) {
if (TextUtils.equals(panelConfig.getId(), id)) {
panelConfig.setIsDisabled(toHide);
break;
}
}
saveHomeConfig();
}
/**
* Ensure a default is set (if possible) for hiding/showing a pref.
* If hiding, try to find an enabled pref to set as the default.
* If showing, set it as the default if there is no default currently.
*
* This updates the local HomeConfig state.
*
* @param pref Preference getting updated
* @param toHide Boolean of the new hidden state
*/
private void ensureDefaultForHide(PanelsPreference pref, boolean toHide) {
if (toHide) {
// Set a default if there is an enabled panel left.
if (pref == mDefaultReference) {
setFallbackDefault();
updateConfigDefault();
}
} else {
if (mDefaultReference == null) {
super.setDefault(pref);
updateConfigDefault();
}
}
setDefaultFromConfig();
}
/**
@ -228,15 +157,6 @@ public class PanelsPreferenceCategory extends CustomListCategory {
*/
@Override
protected void setFallbackDefault() {
// First preference (index 0) is Preference to add panels.
final int prefsCount = getPreferenceCount();
for (int i = 1; i < prefsCount; i++) {
final PanelsPreference pref = (PanelsPreference) getPreference(i);
if (!pref.isHidden()) {
super.setDefault(pref);
return;
}
}
mDefaultReference = null;
setDefaultFromConfig();
}
}