diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/browser/AutoFillSettingsFragment.java | 81 | ||||
-rw-r--r-- | src/com/android/browser/AutofillHandler.java | 52 | ||||
-rw-r--r-- | src/com/android/browser/BrowserActivity.java | 10 | ||||
-rw-r--r-- | src/com/android/browser/BrowserSettings.java | 45 | ||||
-rw-r--r-- | src/com/android/browser/Controller.java | 114 | ||||
-rw-r--r-- | src/com/android/browser/CrashRecoveryHandler.java | 89 | ||||
-rw-r--r-- | src/com/android/browser/PreferenceKeys.java | 13 |
7 files changed, 263 insertions, 141 deletions
diff --git a/src/com/android/browser/AutoFillSettingsFragment.java b/src/com/android/browser/AutoFillSettingsFragment.java index 04f45b5..7be657d 100644 --- a/src/com/android/browser/AutoFillSettingsFragment.java +++ b/src/com/android/browser/AutoFillSettingsFragment.java @@ -52,7 +52,9 @@ public class AutoFillSettingsFragment extends Fragment { private EditText mCountryEdit; private EditText mPhoneEdit; - private Button mSaveButton; + private MenuItem mSaveMenuItem; + + private boolean mInitialised; // Used to display toast after DB interactions complete. private Handler mHandler; @@ -87,7 +89,7 @@ public class AutoFillSettingsFragment extends Fragment { mPhoneEdit.setError(null); } - updateButtonState(); + updateSaveMenuItemState(); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -99,7 +101,7 @@ public class AutoFillSettingsFragment extends Fragment { private class FieldChangedListener implements TextWatcher { public void afterTextChanged(Editable s) { - updateButtonState(); + updateSaveMenuItemState(); } public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -147,11 +149,14 @@ public class AutoFillSettingsFragment extends Fragment { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.autofill_profile_editor, menu); + mSaveMenuItem = menu.findItem(R.id.autofill_profile_editor_save_profile_menu_id); + updateSaveMenuItemState(); } @Override public boolean onOptionsItemSelected(MenuItem item) { - if (item.getItemId() == R.id.autofill_profile_editor_delete_profile_menu_id) { + switch (item.getItemId()) { + case R.id.autofill_profile_editor_delete_profile_menu_id: // Clear the UI. mFullNameEdit.setText(""); mEmailEdit.setText(""); @@ -168,10 +173,30 @@ public class AutoFillSettingsFragment extends Fragment { // trigger the current profile to get deleted from the DB. mSettings.setAutoFillProfile(null, mHandler.obtainMessage(PROFILE_DELETED_MSG)); - updateButtonState(); + updateSaveMenuItemState(); + return true; + + case R.id.autofill_profile_editor_save_profile_menu_id: + AutoFillProfile newProfile = new AutoFillProfile( + mUniqueId, + mFullNameEdit.getText().toString(), + mEmailEdit.getText().toString(), + mCompanyEdit.getText().toString(), + mAddressLine1Edit.getText().toString(), + mAddressLine2Edit.getText().toString(), + mCityEdit.getText().toString(), + mStateEdit.getText().toString(), + mZipEdit.getText().toString(), + mCountryEdit.getText().toString(), + mPhoneEdit.getText().toString()); + + mSettings.setAutoFillProfile(newProfile, + mHandler.obtainMessage(PROFILE_SAVED_MSG)); return true; + + default: + return false; } - return false; } @Override @@ -203,27 +228,6 @@ public class AutoFillSettingsFragment extends Fragment { mCountryEdit.addTextChangedListener(mFieldChangedListener); mPhoneEdit.addTextChangedListener(new PhoneNumberValidator()); - mSaveButton = (Button)v.findViewById(R.id.autofill_profile_editor_save_button); - mSaveButton.setOnClickListener(new OnClickListener() { - public void onClick(View button) { - AutoFillProfile newProfile = new AutoFillProfile( - mUniqueId, - mFullNameEdit.getText().toString(), - mEmailEdit.getText().toString(), - mCompanyEdit.getText().toString(), - mAddressLine1Edit.getText().toString(), - mAddressLine2Edit.getText().toString(), - mCityEdit.getText().toString(), - mStateEdit.getText().toString(), - mZipEdit.getText().toString(), - mCountryEdit.getText().toString(), - mPhoneEdit.getText().toString()); - - mSettings.setAutoFillProfile(newProfile, - mHandler.obtainMessage(PROFILE_SAVED_MSG)); - } - }); - // Populate the text boxes with any pre existing AutoFill data. AutoFillProfile activeProfile = mSettings.getAutoFillProfile(); if (activeProfile != null) { @@ -239,14 +243,25 @@ public class AutoFillSettingsFragment extends Fragment { mPhoneEdit.setText(activeProfile.getPhoneNumber()); } - updateButtonState(); + mInitialised = true; + + updateSaveMenuItemState(); return v; } - public void updateButtonState() { + private void updateSaveMenuItemState() { + if (mSaveMenuItem == null) { + return; + } - boolean valid = (mFullNameEdit.getText().toString().length() > 0 || + if (!mInitialised) { + mSaveMenuItem.setEnabled(false); + return; + } + + boolean currentState = mSaveMenuItem.isEnabled(); + boolean newState = (mFullNameEdit.getText().toString().length() > 0 || mEmailEdit.getText().toString().length() > 0 || mCompanyEdit.getText().toString().length() > 0 || mAddressLine1Edit.getText().toString().length() > 0 || @@ -257,9 +272,9 @@ public class AutoFillSettingsFragment extends Fragment { mCountryEdit.getText().toString().length() > 0) && mPhoneEdit.getError() == null; - // Only enable the save buttons if we have at least one field completed - // and the phone number (if present is valid). - mSaveButton.setEnabled(valid); + if (currentState != newState) { + mSaveMenuItem.setEnabled(newState); + } } private void closeEditor() { diff --git a/src/com/android/browser/AutofillHandler.java b/src/com/android/browser/AutofillHandler.java index c4b14d7..dc23d00 100644 --- a/src/com/android/browser/AutofillHandler.java +++ b/src/com/android/browser/AutofillHandler.java @@ -21,9 +21,11 @@ import android.content.Context; import android.content.SharedPreferences; import android.content.SharedPreferences.Editor; import android.database.Cursor; +import android.net.Uri; import android.os.AsyncTask; import android.os.Message; import android.preference.PreferenceManager; +import android.provider.ContactsContract; import android.webkit.WebSettings.AutoFillProfile; import java.util.concurrent.CountDownLatch; @@ -114,8 +116,58 @@ public class AutofillHandler { c.close(); autoFillDb.close(); + if (mAutoFillProfile == null) { + // We did not load a profile from disk. Try to populate one with the user's + // "me" contact. + final Uri profileUri = Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI, + ContactsContract.Contacts.Data.CONTENT_DIRECTORY); + + String name = getContactField(profileUri, + ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, + ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE); + // Only attempt to read other data and set a profile if we could successfully + // get a name. + if (name != null) { + String email = getContactField(profileUri, + ContactsContract.CommonDataKinds.Email.ADDRESS, + ContactsContract.CommonDataKinds.Email.CONTENT_ITEM_TYPE); + String phone = getContactField(profileUri, + ContactsContract.CommonDataKinds.Phone.NUMBER, + ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE); + String company = getContactField(profileUri, + ContactsContract.CommonDataKinds.Organization.COMPANY, + ContactsContract.CommonDataKinds.Organization.CONTENT_ITEM_TYPE); + + // Can't easily get structured postal address information (even using + // CommonDataKinds.StructuredPostal) so omit prepopulating that for now. + // When querying structured postal data, it often all comes back as a string + // inside the "street" field. + + mAutoFillProfile = new AutoFillProfile( + 1, name, email, company, null, null, null, null, + null, null, phone); + } + } + mLoaded.countDown(); } + + private String getContactField(Uri uri, String field, String itemType) { + String result = null; + + Cursor c = mContext.getContentResolver().query(uri, new String[] { field }, + ContactsContract.Data.MIMETYPE + "=?", new String[] { itemType }, null); + + try { + // Just use the first returned value if we get more than one. + if (c.moveToFirst()) { + result = c.getString(0); + } + } finally { + c.close(); + } + return result; + } } public void setAutoFillProfile(AutoFillProfile profile, Message msg) { 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..dd7bb56 100644 --- a/src/com/android/browser/BrowserSettings.java +++ b/src/com/android/browser/BrowserSettings.java @@ -174,8 +174,6 @@ public class BrowserSettings implements OnSharedPreferenceChangeListener, mWebStorageSizeManager = new WebStorageSizeManager(mContext, new WebStorageSizeManager.StatFsDiskInfo(getAppCachePath()), new WebStorageSizeManager.WebKitAppCacheInfo(getAppCachePath())); - // Workaround b/5253777 - CookieManager.getInstance().acceptCookie(); // Workaround b/5254577 mPrefs.registerOnSharedPreferenceChangeListener(BrowserSettings.this); if (Build.VERSION.CODENAME.equals("REL")) { @@ -847,4 +845,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 8238d77..9683a47 100644 --- a/src/com/android/browser/Controller.java +++ b/src/com/android/browser/Controller.java @@ -218,15 +218,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); @@ -256,16 +254,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. @@ -293,36 +287,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()); @@ -342,9 +342,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); } } @@ -353,7 +353,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); } } @@ -651,18 +652,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() { @@ -670,6 +680,7 @@ public class Controller Log.e(LOGTAG, "BrowserActivity is already resumed."); return; } + mSettings.setLastRunPaused(false); mActivityPaused = false; Tab current = mTabControl.getCurrentTab(); if (current != null) { @@ -1509,9 +1520,6 @@ public class Controller nav.setEnabled(isNavDump); boolean showDebugSettings = mSettings.isDebugEnabled(); - final MenuItem counter = menu.findItem(R.id.dump_counters_menu_id); - counter.setVisible(showDebugSettings); - counter.setEnabled(showDebugSettings); final MenuItem uaSwitcher = menu.findItem(R.id.ua_desktop_menu_id); uaSwitcher.setChecked(isDesktopUa); menu.setGroupVisible(R.id.LIVE_MENU, isLive); @@ -1666,10 +1674,6 @@ public class Controller getCurrentTopWebView().debugDump(); break; - case R.id.dump_counters_menu_id: - getCurrentTopWebView().dumpV8Counters(); - break; - case R.id.zoom_in_menu_id: getCurrentTopWebView().zoomIn(); break; @@ -2107,7 +2111,7 @@ public class Controller manager.addCompletedDownload(target.getName(), mActivity.getTitle().toString(), false, uri.getMimeType(), target.getAbsolutePath(), - (long)uri.getData().length, false); + (long)uri.getData().length, true); } catch (IOException e) { Log.e(LOGTAG, "Could not save data URL"); } finally { 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"; } |