summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorGeorge Mount <mount@google.com>2011-11-21 09:08:21 -0800
committerGeorge Mount <mount@google.com>2011-11-23 14:06:03 -0800
commit3636d0a6d90fd8de55a4894210b2dbe23f32aac9 (patch)
tree7109001dd220719fe4d43369506dbd2d8b0b69a8 /src/com/android
parente744d3b4f1f5d649c96641d5b77fb169b0e102d2 (diff)
downloadandroid_packages_apps_Gello-3636d0a6d90fd8de55a4894210b2dbe23f32aac9.tar.gz
android_packages_apps_Gello-3636d0a6d90fd8de55a4894210b2dbe23f32aac9.tar.bz2
android_packages_apps_Gello-3636d0a6d90fd8de55a4894210b2dbe23f32aac9.zip
Crash recover no longer uses icicle.
Bug 5508252 Changed load state to use the crash recovery state every time instead of using icicle. When the state is saved, the value is written synchronously. Moved settings from CrashRecoveryHandler to BrowserSettings Change-Id: I1a241d4c488fe3246c7d7f1ee0ce26c42ba29429
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/browser/BrowserActivity.java10
-rw-r--r--src/com/android/browser/BrowserSettings.java43
-rw-r--r--src/com/android/browser/Controller.java105
-rw-r--r--src/com/android/browser/CrashRecoveryHandler.java89
-rw-r--r--src/com/android/browser/PreferenceKeys.java13
5 files changed, 162 insertions, 98 deletions
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 23aeed5e..77fac4f2 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -62,7 +62,7 @@ public class BrowserActivity extends Activity {
finish();
return;
}
- mController = new Controller(this, icicle == null);
+ mController = new Controller(this);
boolean xlarge = isTablet(this);
if (xlarge) {
mUi = new XLargeUi(this, mController);
@@ -71,12 +71,8 @@ public class BrowserActivity extends Activity {
}
mController.setUi(mUi);
- Bundle state = getIntent().getBundleExtra(EXTRA_STATE);
- if (state != null && icicle == null) {
- icicle = state;
- }
-
- mController.start(icicle, getIntent());
+ Intent intent = (icicle == null) ? getIntent() : null;
+ mController.start(intent);
}
public static boolean isTablet(Context context) {
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 23695549..ac6e4f36 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -847,4 +847,47 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener,
return mPrefs.getString(PREF_DATA_PRELOAD, getDefaultPreloadSetting());
}
+ // -----------------------------
+ // getter/setters for browser recovery
+ // -----------------------------
+ /**
+ * The last time browser was started.
+ * @return The last browser start time as System.currentTimeMillis. This
+ * can be 0 if this is the first time or the last tab was closed.
+ */
+ public long getLastRecovered() {
+ return mPrefs.getLong(KEY_LAST_RECOVERED, 0);
+ }
+
+ /**
+ * Sets the last browser start time.
+ * @param time The last time as System.currentTimeMillis that the browser
+ * was started. This should be set to 0 if the last tab is closed.
+ */
+ public void setLastRecovered(long time) {
+ mPrefs.edit()
+ .putLong(KEY_LAST_RECOVERED, time)
+ .apply();
+ }
+
+ /**
+ * Used to determine whether or not the previous browser run crashed. Once
+ * the previous state has been determined, the value will be set to false
+ * until a pause is received.
+ * @return true if the last browser run was paused or false if it crashed.
+ */
+ public boolean wasLastRunPaused() {
+ return mPrefs.getBoolean(KEY_LAST_RUN_PAUSED, false);
+ }
+
+ /**
+ * Sets whether or not the last run was a pause or crash.
+ * @param isPaused Set to true When a pause is received or false after
+ * resuming.
+ */
+ public void setLastRunPaused(boolean isPaused) {
+ mPrefs.edit()
+ .putBoolean(KEY_LAST_RUN_PAUSED, isPaused)
+ .apply();
+ }
}
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index c9756da9..e72570d2 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -220,15 +220,13 @@ public class Controller
private boolean mBlockEvents;
- public Controller(Activity browser, boolean preloadCrashState) {
+ public Controller(Activity browser) {
mActivity = browser;
mSettings = BrowserSettings.getInstance();
mTabControl = new TabControl(this);
mSettings.setController(this);
mCrashRecoveryHandler = CrashRecoveryHandler.initialize(this);
- if (preloadCrashState) {
- mCrashRecoveryHandler.preloadCrashState();
- }
+ mCrashRecoveryHandler.preloadCrashState();
mFactory = new BrowserWebViewFactory(browser);
mUrlHandler = new UrlHandler(this);
@@ -258,16 +256,12 @@ public class Controller
openIconDatabase();
}
- void start(final Bundle icicle, final Intent intent) {
- boolean noCrashRecovery = intent.getBooleanExtra(NO_CRASH_RECOVERY, false);
- if (icicle != null || noCrashRecovery) {
- doStart(icicle, intent, false);
- } else {
- mCrashRecoveryHandler.startRecovery(intent);
- }
+ void start(final Intent intent) {
+ // mCrashRecoverHandler has any previously saved state.
+ mCrashRecoveryHandler.startRecovery(intent);
}
- void doStart(final Bundle icicle, final Intent intent, final boolean fromCrash) {
+ void doStart(final Bundle icicle, final Intent intent) {
// Unless the last browser usage was within 24 hours, destroy any
// remaining incognito tabs.
@@ -295,36 +289,42 @@ public class Controller
GoogleAccountLogin.startLoginIfNeeded(mActivity,
new Runnable() {
@Override public void run() {
- onPreloginFinished(icicle, intent, currentTabId, restoreIncognitoTabs,
- fromCrash);
+ onPreloginFinished(icicle, intent, currentTabId,
+ restoreIncognitoTabs);
}
});
}
private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
- boolean restoreIncognitoTabs, boolean fromCrash) {
+ boolean restoreIncognitoTabs) {
if (currentTabId == -1) {
BackgroundHandler.execute(new PruneThumbnails(mActivity, null));
- final Bundle extra = intent.getExtras();
- // Create an initial tab.
- // If the intent is ACTION_VIEW and data is not null, the Browser is
- // invoked to view the content by another application. In this case,
- // the tab will be close when exit.
- UrlData urlData = IntentHandler.getUrlDataFromIntent(intent);
- Tab t = null;
- if (urlData.isEmpty()) {
- t = openTabToHomePage();
+ if (intent == null) {
+ // This won't happen under common scenarios. The icicle is
+ // not null, but there aren't any tabs to restore.
+ openTabToHomePage();
} else {
- t = openTab(urlData);
- }
- if (t != null) {
- t.setAppId(intent.getStringExtra(Browser.EXTRA_APPLICATION_ID));
- }
- WebView webView = t.getWebView();
- if (extra != null) {
- int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0);
- if (scale > 0 && scale <= 1000) {
- webView.setInitialScale(scale);
+ final Bundle extra = intent.getExtras();
+ // Create an initial tab.
+ // If the intent is ACTION_VIEW and data is not null, the Browser is
+ // invoked to view the content by another application. In this case,
+ // the tab will be close when exit.
+ UrlData urlData = IntentHandler.getUrlDataFromIntent(intent);
+ Tab t = null;
+ if (urlData.isEmpty()) {
+ t = openTabToHomePage();
+ } else {
+ t = openTab(urlData);
+ }
+ if (t != null) {
+ t.setAppId(intent.getStringExtra(Browser.EXTRA_APPLICATION_ID));
+ }
+ WebView webView = t.getWebView();
+ if (extra != null) {
+ int scale = extra.getInt(Browser.INITIAL_ZOOM_LEVEL, 0);
+ if (scale > 0 && scale <= 1000) {
+ webView.setInitialScale(scale);
+ }
}
}
mUi.updateTabs(mTabControl.getTabs());
@@ -344,9 +344,9 @@ public class Controller
// TabControl.restoreState() will create a new tab even if
// restoring the state fails.
setActiveTab(mTabControl.getCurrentTab());
- // Handle the intent if needed. If icicle != null, we are restoring
- // and the intent will be stale - ignore it.
- if (icicle == null || fromCrash) {
+ // Intent is non-null when framework thinks the browser should be
+ // launching with a new intent (icicle is null).
+ if (intent != null) {
mIntentHandler.onNewIntent(intent);
}
}
@@ -355,7 +355,8 @@ public class Controller
if (jsFlags.trim().length() != 0) {
getCurrentWebView().setJsFlags(jsFlags);
}
- if (BrowserActivity.ACTION_SHOW_BOOKMARKS.equals(intent.getAction())) {
+ if (intent != null
+ && BrowserActivity.ACTION_SHOW_BOOKMARKS.equals(intent.getAction())) {
bookmarksOrHistoryPicker(ComboViews.Bookmarks);
}
}
@@ -653,18 +654,27 @@ public class Controller
}
void onSaveInstanceState(Bundle outState) {
- // the default implementation requires each view to have an id. As the
- // browser handles the state itself and it doesn't use id for the views,
- // don't call the default implementation. Otherwise it will trigger the
- // warning like this, "couldn't save which view has focus because the
- // focused view XXX has no id".
-
// Save all the tabs
- mTabControl.saveState(outState);
- if (!outState.isEmpty()) {
+ Bundle saveState = createSaveState();
+
+ // crash recovery manages all save & restore state
+ mCrashRecoveryHandler.writeState(saveState);
+ mSettings.setLastRunPaused(true);
+ }
+
+ /**
+ * Save the current state to outState. Does not write the state to
+ * disk.
+ * @return Bundle containing the current state of all tabs.
+ */
+ /* package */ Bundle createSaveState() {
+ Bundle saveState = new Bundle();
+ mTabControl.saveState(saveState);
+ if (!saveState.isEmpty()) {
// Save time so that we know how old incognito tabs (if any) are.
- outState.putSerializable("lastActiveDate", Calendar.getInstance());
+ saveState.putSerializable("lastActiveDate", Calendar.getInstance());
}
+ return saveState;
}
void onResume() {
@@ -672,6 +682,7 @@ public class Controller
Log.e(LOGTAG, "BrowserActivity is already resumed.");
return;
}
+ mSettings.setLastRunPaused(false);
mActivityPaused = false;
Tab current = mTabControl.getCurrentTab();
if (current != null) {
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 3202016e..822e82a8 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -37,8 +37,6 @@ public class CrashRecoveryHandler {
private static final boolean LOGV_ENABLED = Browser.LOGV_ENABLED;
private static final String LOGTAG = "BrowserCrashRecovery";
private static final String STATE_FILE = "browser_state.parcel";
- private static final String RECOVERY_PREFERENCES = "browser_recovery_prefs";
- private static final String KEY_LAST_RECOVERED = "last_recovered";
private static final int BUFFER_SIZE = 4096;
private static final long BACKUP_DELAY = 500; // 500ms between writes
/* This is the duration for which we will prompt to restore
@@ -85,31 +83,8 @@ public class CrashRecoveryHandler {
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_WRITE_STATE:
- if (LOGV_ENABLED) {
- Log.v(LOGTAG, "Saving crash recovery state");
- }
- Parcel p = Parcel.obtain();
- try {
- Bundle state = (Bundle) msg.obj;
- state.writeToParcel(p, 0);
- File stateJournal = new File(mContext.getCacheDir(),
- STATE_FILE + ".journal");
- FileOutputStream fout = new FileOutputStream(stateJournal);
- fout.write(p.marshall());
- fout.close();
- File stateFile = new File(mContext.getCacheDir(),
- STATE_FILE);
- if (!stateJournal.renameTo(stateFile)) {
- // Failed to rename, try deleting the existing
- // file and try again
- stateFile.delete();
- stateJournal.renameTo(stateFile);
- }
- } catch (Throwable e) {
- Log.i(LOGTAG, "Failed to save persistent state", e);
- } finally {
- p.recycle();
- }
+ Bundle saveState = (Bundle) msg.obj;
+ writeState(saveState);
break;
case MSG_CLEAR_STATE:
if (LOGV_ENABLED) {
@@ -142,8 +117,7 @@ public class CrashRecoveryHandler {
@Override
public void run() {
try {
- final Bundle state = new Bundle();
- mController.onSaveInstanceState(state);
+ final Bundle state = mController.createSaveState();
Message.obtain(mBackgroundHandler, MSG_WRITE_STATE, state)
.sendToTarget();
// Remove any queued up saves
@@ -162,28 +136,24 @@ public class CrashRecoveryHandler {
}
private boolean shouldRestore() {
- SharedPreferences prefs = mContext.getSharedPreferences(
- RECOVERY_PREFERENCES, Context.MODE_PRIVATE);
- long lastRecovered = prefs.getLong(KEY_LAST_RECOVERED, 0);
+ BrowserSettings browserSettings = BrowserSettings.getInstance();
+ long lastRecovered = browserSettings.getLastRecovered();
long timeSinceLastRecover = System.currentTimeMillis() - lastRecovered;
- if (timeSinceLastRecover > PROMPT_INTERVAL) {
- return true;
- }
- return false;
+ return (timeSinceLastRecover > PROMPT_INTERVAL)
+ || browserSettings.wasLastRunPaused();
}
private void updateLastRecovered(long time) {
- SharedPreferences prefs = mContext.getSharedPreferences(
- RECOVERY_PREFERENCES, Context.MODE_PRIVATE);
- prefs.edit()
- .putLong(KEY_LAST_RECOVERED, time)
- .apply();
+ BrowserSettings browserSettings = BrowserSettings.getInstance();
+ browserSettings.setLastRecovered(time);
}
- private Bundle loadCrashState() {
+ synchronized private Bundle loadCrashState() {
if (!shouldRestore()) {
return null;
}
+ BrowserSettings browserSettings = BrowserSettings.getInstance();
+ browserSettings.setLastRunPaused(false);
Bundle state = null;
Parcel parcel = Parcel.obtain();
FileInputStream fin = null;
@@ -231,7 +201,7 @@ public class CrashRecoveryHandler {
}
updateLastRecovered(mRecoveryState != null
? System.currentTimeMillis() : 0);
- mController.doStart(mRecoveryState, intent, true);
+ mController.doStart(mRecoveryState, intent);
mRecoveryState = null;
}
@@ -245,4 +215,35 @@ public class CrashRecoveryHandler {
mBackgroundHandler.sendEmptyMessage(MSG_PRELOAD_STATE);
}
-}
+ /**
+ * Writes the crash recovery state to a file synchronously.
+ * Errors are swallowed, but logged.
+ * @param state The state to write out
+ */
+ synchronized void writeState(Bundle state) {
+ if (LOGV_ENABLED) {
+ Log.v(LOGTAG, "Saving crash recovery state");
+ }
+ Parcel p = Parcel.obtain();
+ try {
+ state.writeToParcel(p, 0);
+ File stateJournal = new File(mContext.getCacheDir(),
+ STATE_FILE + ".journal");
+ FileOutputStream fout = new FileOutputStream(stateJournal);
+ fout.write(p.marshall());
+ fout.close();
+ File stateFile = new File(mContext.getCacheDir(),
+ STATE_FILE);
+ if (!stateJournal.renameTo(stateFile)) {
+ // Failed to rename, try deleting the existing
+ // file and try again
+ stateFile.delete();
+ stateJournal.renameTo(stateFile);
+ }
+ } catch (Throwable e) {
+ Log.i(LOGTAG, "Failed to save persistent state", e);
+ } finally {
+ p.recycle();
+ }
+ }
+} \ No newline at end of file
diff --git a/src/com/android/browser/PreferenceKeys.java b/src/com/android/browser/PreferenceKeys.java
index ecab008a..1a204956 100644
--- a/src/com/android/browser/PreferenceKeys.java
+++ b/src/com/android/browser/PreferenceKeys.java
@@ -104,4 +104,17 @@ public interface PreferenceKeys {
static final String PREF_DATA_PRELOAD = "preload_when";
static final String PREF_LOAD_IMAGES = "load_images";
+ // ----------------------
+ // Keys for browser recovery
+ // ----------------------
+ /**
+ * The last time recovery was started as System.currentTimeMillis.
+ * 0 if not set.
+ */
+ static final String KEY_LAST_RECOVERED = "last_recovered";
+
+ /**
+ * Key for whether or not the last run was paused.
+ */
+ static final String KEY_LAST_RUN_PAUSED = "last_paused";
}