зеркало из https://github.com/mozilla/gecko-dev.git
Bug 967742 - Consolidate API to edit HomeConfig state (r=margaret)
This commit is contained in:
Родитель
62e731fdff
Коммит
b9b49b223e
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче