diff options
Diffstat (limited to 'src/com/android')
-rw-r--r-- | src/com/android/browser/BrowserActivity.java | 10 | ||||
-rw-r--r-- | src/com/android/browser/BrowserSettings.java | 43 | ||||
-rw-r--r-- | src/com/android/browser/Controller.java | 105 | ||||
-rw-r--r-- | src/com/android/browser/CrashRecoveryHandler.java | 89 | ||||
-rw-r--r-- | src/com/android/browser/PreferenceKeys.java | 13 |
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"; } |