Always offer to restore
Always offer to restore (even across reboots)
Periodically save while the user is typing in a textfield
Change-Id: If226ea7d2e19c58d8205d663f9f8dd670c712436
diff --git a/src/com/android/browser/BrowserWebView.java b/src/com/android/browser/BrowserWebView.java
index 5a40b3c..55dd24a 100644
--- a/src/com/android/browser/BrowserWebView.java
+++ b/src/com/android/browser/BrowserWebView.java
@@ -191,4 +191,13 @@
}
}
+ @Override
+ protected void updateCachedTextfield(String updatedText) {
+ super.updateCachedTextfield(updatedText);
+ CrashRecoveryHandler handler = CrashRecoveryHandler.getInstance();
+ if (handler != null) {
+ handler.backupState();
+ }
+ }
+
}
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index 986b617..5fb413b 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -226,7 +226,7 @@
mDataController = DataController.getInstance(mActivity);
mTabControl = new TabControl(this);
mSettings.setController(this);
- mCrashRecoveryHandler = new CrashRecoveryHandler(this);
+ mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this);
mUrlHandler = new UrlHandler(this);
mIntentHandler = new IntentHandler(mActivity, this);
@@ -262,7 +262,6 @@
void start(final Bundle icicle, final Intent intent) {
boolean noCrashRecovery = intent.getBooleanExtra(NO_CRASH_RECOVERY, false);
if (icicle != null || noCrashRecovery) {
- mCrashRecoveryHandler.clearState();
doStart(icicle, intent);
} else {
mCrashRecoveryHandler.startRecovery(intent);
@@ -615,7 +614,7 @@
mNetworkHandler.onPause();
WebView.disablePlatformNotifications();
- mCrashRecoveryHandler.clearState();
+ mCrashRecoveryHandler.backupState();
}
void onSaveInstanceState(Bundle outState, boolean saveImages) {
@@ -2141,6 +2140,7 @@
protected void removeTab(Tab tab) {
mUi.removeTab(tab);
mTabControl.removeTab(tab);
+ mCrashRecoveryHandler.backupState();
}
@Override
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 60e39da..7ee9cee 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -22,7 +22,10 @@
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
import android.os.Parcel;
+import android.os.Process;
import android.util.Log;
import java.io.ByteArrayOutputStream;
@@ -35,37 +38,88 @@
private static final String LOGTAG = "BrowserCrashRecovery";
private static final String STATE_FILE = "browser_state.parcel";
private static final int BUFFER_SIZE = 4096;
+ private static final long BACKUP_DELAY = 500; // 500ms between writes
+
+ private static CrashRecoveryHandler sInstance;
private Controller mController;
+ private Handler mForegroundHandler;
+ private Handler mBackgroundHandler;
- public CrashRecoveryHandler(Controller controller) {
+ public static CrashRecoveryHandler initialize(Controller controller) {
+ if (sInstance == null) {
+ sInstance = new CrashRecoveryHandler(controller);
+ } else {
+ sInstance.mController = controller;
+ }
+ return sInstance;
+ }
+
+ public static CrashRecoveryHandler getInstance() {
+ return sInstance;
+ }
+
+ private CrashRecoveryHandler(Controller controller) {
mController = controller;
+ mForegroundHandler = new Handler();
+ HandlerThread thread = new HandlerThread(LOGTAG,
+ Process.THREAD_PRIORITY_BACKGROUND);
+ thread.start();
+ mBackgroundHandler = new Handler(thread.getLooper());
}
public void backupState() {
- final Bundle state = new Bundle();
- mController.onSaveInstanceState(state, false);
- final Context context = mController.getActivity();
- new Thread() {
- @Override
- public void run() {
- Parcel p = Parcel.obtain();
- try {
- state.writeToParcel(p, 0);
- FileOutputStream fout = context.openFileOutput(STATE_FILE,
- Context.MODE_PRIVATE);
- fout.write(p.marshall());
- fout.close();
- } catch (Throwable e) {
- Log.i(LOGTAG, "Failed to save persistent state", e);
- } finally {
- p.recycle();
- }
- }
- }.start();
+ mForegroundHandler.postDelayed(mCreateState, BACKUP_DELAY);
}
- public void clearState() {
+ private Runnable mCreateState = new Runnable() {
+
+ @Override
+ public void run() {
+ try {
+ final Bundle state = new Bundle();
+ mController.onSaveInstanceState(state, false);
+ Context context = mController.getActivity()
+ .getApplicationContext();
+ mBackgroundHandler.post(new WriteState(context, state));
+ // Remove any queued up saves
+ mForegroundHandler.removeCallbacks(mCreateState);
+ } catch (Throwable t) {
+ Log.w(LOGTAG, "Failed to save state", t);
+ return;
+ }
+ }
+
+ };
+
+ static class WriteState implements Runnable {
+ private Context mContext;
+ private Bundle mState;
+
+ WriteState(Context context, Bundle state) {
+ mContext = context;
+ mState = state;
+ }
+
+ @Override
+ public void run() {
+ Parcel p = Parcel.obtain();
+ try {
+ mState.writeToParcel(p, 0);
+ FileOutputStream fout = mContext.openFileOutput(STATE_FILE,
+ Context.MODE_PRIVATE);
+ fout.write(p.marshall());
+ fout.close();
+ } catch (Throwable e) {
+ Log.i(LOGTAG, "Failed to save persistent state", e);
+ } finally {
+ p.recycle();
+ }
+ }
+
+ }
+
+ private void clearState() {
Context context = mController.getActivity();
context.deleteFile(STATE_FILE);
}