summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
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 23aeed5..77fac4f 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 2369554..ac6e4f3 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 c9756da..e72570d 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 3202016..822e82a 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 ecab008..1a20495 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";
}