Merge "Remove unused parameter"
diff --git a/res/values-sw600dp/strings.xml b/res/values-sw600dp/strings.xml
index d715c1b..82ba301 100644
--- a/res/values-sw600dp/strings.xml
+++ b/res/values-sw600dp/strings.xml
@@ -35,5 +35,5 @@
     <!-- Recover tabs after a crash dialog title [CHAR LIMIT=32] -->
     <string name="recover_title">Restore tabs?</string>
     <!-- Recover tabs after a crash dialog prompt [CHAR LIMIT=none] -->
-    <string name="recover_prompt">Browser appears to have crashed. Would you like to restore your tabs from last time?</string>
+    <string name="recover_prompt">Would you like to restore your tabs from last time?</string>
 </resources>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index b86edb5..1e92fb5 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -1000,9 +1000,9 @@
     <!-- Recover tabs after a crash dialog title [CHAR LIMIT=32] -->
     <string name="recover_title">Restore windows?</string>
     <!-- Recover tabs after a crash dialog prompt [CHAR LIMIT=none] -->
-    <string name="recover_prompt">Browser appears to have crashed. Would you like to restore your windows from last time?</string>
+    <string name="recover_prompt">Would you like to restore your windows from last time?</string>
     <!-- Yes, recover windows from last time [CHAR LIMIT=10] -->
-    <string name="recover_yes">Yes</string>
+    <string name="recover_yes">Restore</string>
     <!-- No, don't recover windows from last time [CHAR LIMIT=10] -->
     <string name="recover_no">No</string>
     <!-- Font size preview label [CHAR LIMIT=30] -->
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 9472b41..efd9012 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) {
@@ -2139,6 +2138,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);
     }
diff --git a/src/com/android/browser/KeyChainLookup.java b/src/com/android/browser/KeyChainLookup.java
index 7f236e5..52be25a 100644
--- a/src/com/android/browser/KeyChainLookup.java
+++ b/src/com/android/browser/KeyChainLookup.java
@@ -18,8 +18,8 @@
 
 import android.content.Context;
 import android.os.AsyncTask;
-import android.os.RemoteException;
 import android.security.KeyChain;
+import android.security.KeyChainException;
 import android.webkit.ClientCertRequestHandler;
 import java.security.PrivateKey;
 import java.security.cert.X509Certificate;
@@ -42,7 +42,7 @@
         } catch (InterruptedException e) {
             mHandler.ignore();
             return null;
-        } catch (RemoteException e) {
+        } catch (KeyChainException e) {
             mHandler.ignore();
             return null;
         }
diff --git a/src/com/android/browser/NavTabScroller.java b/src/com/android/browser/NavTabScroller.java
index bd26df7..312e2b8 100644
--- a/src/com/android/browser/NavTabScroller.java
+++ b/src/com/android/browser/NavTabScroller.java
@@ -197,17 +197,7 @@
                 int bottom = child.getBottom();
                 if (top <= midy && bottom >= midy) {
                     sel = i;
-                } else {
-                    // check if on screen
-                    if (top > getScrollY() + getHeight() || bottom < getScrollY()) {
-                        if (!child.isPaused()) {
-                            child.pause();
-                        }
-                    } else {
-                        if (child.isPaused()) {
-                            child.resume();
-                        }
-                    }
+                    break;
                 }
             }
             if (sel != -1) {
diff --git a/src/com/android/browser/NavTabView.java b/src/com/android/browser/NavTabView.java
index 061e024..f170b0f 100644
--- a/src/com/android/browser/NavTabView.java
+++ b/src/com/android/browser/NavTabView.java
@@ -198,7 +198,9 @@
 
     @Override
     public void onDetachedFromWindow() {
-        mWebView.setProxyView(null);
+        if (mWebView != null) {
+            mWebView.setProxyView(null);
+        }
     }
 
     private static void removeFromParent(View v) {
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index e517d76..89f567b 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -33,7 +33,7 @@
 import android.os.Message;
 import android.os.SystemClock;
 import android.security.KeyChain;
-import android.security.KeyChainAliasResponse;
+import android.security.KeyChainAliasCallback;
 import android.speech.RecognizerResultsIntent;
 import android.util.Log;
 import android.view.KeyEvent;
@@ -803,7 +803,7 @@
                 handler.ignore();
                 return;
             }
-            KeyChain.choosePrivateKeyAlias(mActivity, new KeyChainAliasResponse() {
+            KeyChain.choosePrivateKeyAlias(mActivity, new KeyChainAliasCallback() {
                 @Override public void alias(String alias) {
                     if (alias == null) {
                         handler.cancel();
@@ -811,7 +811,7 @@
                     }
                     new KeyChainLookup(mActivity, handler, alias).execute();
                 }
-            });
+            }, null, null, null, -1);
         }
 
         /**
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 0aaf3d6..1e21431 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -286,7 +286,11 @@
             }
         }
         outState.putLongArray(POSITIONS, ids);
-        final long cid = getCurrentTab().getId();
+        Tab current = getCurrentTab();
+        long cid = -1;
+        if (current != null) {
+            cid = current.getId();
+        }
         outState.putLong(CURRENT, cid);
     }
 
diff --git a/src/com/android/browser/WallpaperHandler.java b/src/com/android/browser/WallpaperHandler.java
index 2cb223a..cd896da 100644
--- a/src/com/android/browser/WallpaperHandler.java
+++ b/src/com/android/browser/WallpaperHandler.java
@@ -68,7 +68,7 @@
 
     @Override
     public boolean onMenuItemClick(MenuItem item) {
-        if (mUrl != null) {
+        if (mUrl != null && getState() == State.NEW) {
             // The user may have tried to set a image with a large file size as
             // their background so it may take a few moments to perform the
             // operation.