Fix losing widget state on restart

This commit is contained in:
serso 2016-03-01 14:01:59 +01:00
parent 4a8c0b7a2d
commit ea21bbe811
4 changed files with 101 additions and 14 deletions

View File

@ -26,7 +26,7 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
import android.view.ContextMenu;
import jscl.math.Generic;
import org.json.JSONException;
import org.json.JSONObject;
import org.solovyev.android.calculator.jscl.JsclOperation;
@ -34,6 +34,8 @@ import org.solovyev.android.calculator.jscl.JsclOperation;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import jscl.math.Generic;
public class DisplayState implements Parcelable, ContextMenu.ContextMenuInfo {
public static final Creator<DisplayState> CREATOR = new Creator<DisplayState>() {
@ -143,4 +145,8 @@ public class DisplayState implements Parcelable, ContextMenu.ContextMenuInfo {
dest.writeString(text);
dest.writeByte((byte) (valid ? 1 : 0));
}
public boolean isEmpty() {
return valid && TextUtils.isEmpty(text);
}
}

View File

@ -4,8 +4,11 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Vibrator;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.solovyev.android.calculator.buttons.CppButton;
import org.solovyev.android.calculator.history.History;
import javax.annotation.Nonnull;
import javax.inject.Inject;
@ -19,6 +22,8 @@ public final class WidgetReceiver extends BroadcastReceiver {
@Inject
Keyboard keyboard;
@Inject
History history;
@Nonnull
public static Intent newButtonClickedIntent(@Nonnull Context context, @Nonnull CppButton button) {
@ -43,9 +48,21 @@ public final class WidgetReceiver extends BroadcastReceiver {
return;
}
if (!keyboard.buttonPressed(button.action)) {
return;
if (history.isLoaded()) {
if (!keyboard.buttonPressed(button.action)) {
// prevent vibrate
return;
}
} else {
// if app has been killed we need first to restore the state and only after doing this
// to apply actions. Otherwise, we will apply actions on the empty editor
history.runWhenLoaded(new MyRunnable(keyboard, button.action));
}
vibrate(context);
}
private void vibrate(@NonNull Context context) {
if (!keyboard.isVibrateOnKeypress()) {
return;
}
@ -55,4 +72,21 @@ public final class WidgetReceiver extends BroadcastReceiver {
}
vibrator.vibrate(10);
}
private static class MyRunnable implements Runnable {
@NonNull
private final Keyboard keyboard;
@NonNull
private final String action;
public MyRunnable(@NonNull Keyboard keyboard, @NonNull String action) {
this.keyboard = keyboard;
this.action = action;
}
@Override
public void run() {
keyboard.buttonPressed(action);
}
}
}

View File

@ -77,6 +77,9 @@ public class History {
private final RecentHistory recent = new RecentHistory();
@Nonnull
private final List<HistoryState> saved = new ArrayList<>();
@Nonnull
private final List<Runnable> whenLoadedRunnables = new ArrayList<>();
private boolean loaded;
@Inject
Application application;
@Inject
@ -217,15 +220,32 @@ public class History {
handler.post(new Runnable() {
@Override
public void run() {
Check.isTrue(recent.isEmpty());
Check.isTrue(saved.isEmpty());
recent.addInitial(recentStates);
saved.addAll(savedStates);
editor.onHistoryLoaded(recent);
onLoaded(recentStates, savedStates);
}
});
}
private void onLoaded(@NonNull List<HistoryState> recentStates, @NonNull List<HistoryState> savedStates) {
Check.isTrue(saved.isEmpty());
Check.isMainThread();
final boolean wasEmpty = recent.isEmpty();
recent.addInitial(recentStates);
saved.addAll(savedStates);
if (wasEmpty) {
// user has typed nothing while we were loading, let's use recent history to restore
// editor state
editor.onHistoryLoaded(recent);
} else {
// user has types something => we should schedule save
postRecentWrite();
}
loaded = true;
for (Runnable runnable : whenLoadedRunnables) {
runnable.run();
}
whenLoadedRunnables.clear();
}
@Nonnull
private List<HistoryState> tryLoadStates(@NonNull File file) {
try {
@ -238,6 +258,10 @@ public class History {
public void addRecent(@Nonnull HistoryState state) {
Check.isMainThread();
if (recent.isEmpty() && state.isEmpty()) {
// don't add empty states to empty history
return;
}
recent.add(state);
onRecentChanged(new AddedEvent(state, true));
}
@ -255,15 +279,23 @@ public class History {
}
private void onRecentChanged(@Nonnull Object event) {
handler.removeCallbacks(writeRecent);
handler.postDelayed(writeRecent, 5000);
postRecentWrite();
bus.post(event);
}
private void postRecentWrite() {
handler.removeCallbacks(writeRecent);
handler.postDelayed(writeRecent, 5000);
}
private void onSavedChanged(@Nonnull Object event) {
postSavedWrite();
bus.post(event);
}
private void postSavedWrite() {
handler.removeCallbacks(writeSaved);
handler.postDelayed(writeSaved, 500);
bus.post(event);
}
@Nonnull
@ -359,6 +391,15 @@ public class History {
addRecent(HistoryState.builder(editorState, displayState).build());
}
public boolean isLoaded() {
return loaded;
}
public void runWhenLoaded(@NonNull Runnable runnable) {
Check.isTrue(!loaded);
whenLoadedRunnables.add(runnable);
}
public static class ClearedEvent {
public final boolean recent;
@ -406,6 +447,9 @@ public class History {
@Override
public void run() {
Check.isMainThread();
if (!loaded) {
return;
}
// don't need to save intermediate states, thus {@link History#getRecent}
final List<HistoryState> states = recent ? getRecent(false) : getSaved();
backgroundThread.execute(new Runnable() {

View File

@ -3,6 +3,7 @@ package org.solovyev.android.calculator.history;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import org.json.JSONException;
import org.json.JSONObject;
@ -15,8 +16,6 @@ import org.solovyev.android.calculator.json.Jsonable;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import static android.text.TextUtils.isEmpty;
public class HistoryState implements Parcelable, Jsonable {
public static final Creator<HistoryState> CREATOR = new Creator<HistoryState>() {
@ -103,7 +102,7 @@ public class HistoryState implements Parcelable, Jsonable {
json.put(JSON_EDITOR, editor.toJson());
json.put(JSON_DISPLAY, display.toJson());
json.put(JSON_TIME, time);
if (!isEmpty(comment)) {
if (!TextUtils.isEmpty(comment)) {
json.put(JSON_COMMENT, comment);
}
return json;
@ -173,6 +172,10 @@ public class HistoryState implements Parcelable, Jsonable {
dest.writeString(comment);
}
public boolean isEmpty() {
return display.isEmpty() && editor.isEmpty() && TextUtils.isEmpty(comment);
}
public static final class Builder {
@NonNull