Merge "Add char limit for localization."
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index b62862b..3535725 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -116,6 +116,7 @@
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLEncoder;
+import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
@@ -276,7 +277,19 @@
}
};
- if (!mTabControl.restoreState(icicle)) {
+ // Unless the last browser usage was within 24 hours, destroy any
+ // remaining incognito tabs.
+
+ Calendar lastActiveDate = icicle != null ? (Calendar) icicle.getSerializable("lastActiveDate") : null;
+ Calendar today = Calendar.getInstance();
+ Calendar yesterday = Calendar.getInstance();
+ yesterday.add(Calendar.DATE, -1);
+
+ boolean dontRestoreIncognitoTabs = lastActiveDate == null
+ || lastActiveDate.before(yesterday)
+ || lastActiveDate.after(today);
+
+ if (!mTabControl.restoreState(icicle, dontRestoreIncognitoTabs)) {
// clear up the thumbnail directory if we can't restore the state as
// none of the files in the directory are referenced any more.
new ClearThumbnails().execute(
@@ -284,6 +297,8 @@
// there is no quit on Android. But if we can't restore the state,
// we can treat it as a new Browser, remove the old session cookies.
CookieManager.getInstance().removeSessionCookie();
+ // remove any incognito files
+ WebView.cleanupPrivateBrowsingFiles(this);
final Intent intent = getIntent();
final Bundle extra = intent.getExtras();
// Create an initial tab.
@@ -316,6 +331,10 @@
loadUrlDataIn(t, urlData);
}
} else {
+ if (dontRestoreIncognitoTabs) {
+ WebView.cleanupPrivateBrowsingFiles(this);
+ }
+
// TabControl.restoreState() will create a new tab even if
// restoring the state fails.
attachTabToContentView(mTabControl.getCurrentTab());
@@ -930,6 +949,9 @@
// Save all the tabs
mTabControl.saveState(outState);
+
+ // Save time so that we know how old incognito tabs (if any) are.
+ outState.putSerializable("lastActiveDate", Calendar.getInstance());
}
@Override
@@ -1392,17 +1414,26 @@
if (LOGD_ENABLED) {
Log.d(LOGTAG, "Save as Web Archive");
}
- String directory = getExternalFilesDir(null).getAbsolutePath() + File.separator;
- getTopWindow().saveWebArchive(directory, true, new ValueCallback<String>() {
- @Override
- public void onReceiveValue(String value) {
- if (value != null) {
- Toast.makeText(BrowserActivity.this, R.string.webarchive_saved, Toast.LENGTH_SHORT).show();
- } else {
- Toast.makeText(BrowserActivity.this, R.string.webarchive_failed, Toast.LENGTH_SHORT).show();
+ String state = Environment.getExternalStorageState();
+ if (Environment.MEDIA_MOUNTED.equals(state)) {
+ String directory = Environment.getExternalStoragePublicDirectory(
+ Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + File.separator;
+ getTopWindow().saveWebArchive(directory, true, new ValueCallback<String>() {
+ @Override
+ public void onReceiveValue(String value) {
+ if (value != null) {
+ Toast.makeText(BrowserActivity.this, R.string.webarchive_saved,
+ Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(BrowserActivity.this, R.string.webarchive_failed,
+ Toast.LENGTH_SHORT).show();
+ }
}
- }
- });
+ });
+ } else {
+ Toast.makeText(BrowserActivity.this, R.string.webarchive_failed,
+ Toast.LENGTH_SHORT).show();
+ }
break;
case R.id.page_info_menu_id:
@@ -2086,6 +2117,10 @@
mTabControl.setCurrentTab(mTabControl.getTab(currentIndex));
resetTitleIconAndProgress();
updateLockIconToLatest();
+
+ if (!mTabControl.hasAnyOpenIncognitoTabs()) {
+ WebView.cleanupPrivateBrowsingFiles(this);
+ }
}
/* package */ void goBackOnePageOrQuit() {
diff --git a/src/com/android/browser/BrowserProvider.java b/src/com/android/browser/BrowserProvider.java
index 87c38e2..33f3006 100644
--- a/src/com/android/browser/BrowserProvider.java
+++ b/src/com/android/browser/BrowserProvider.java
@@ -385,7 +385,7 @@
fixPicasaBookmark();
Editor ed = p.edit();
ed.putBoolean("fix_picasa", false);
- ed.commit();
+ ed.apply();
}
}
mSearchManager = (SearchManager) context.getSystemService(Context.SEARCH_SERVICE);
diff --git a/src/com/android/browser/BrowserSettings.java b/src/com/android/browser/BrowserSettings.java
index 2f739fa..5a7dd0d 100644
--- a/src/com/android/browser/BrowserSettings.java
+++ b/src/com/android/browser/BrowserSettings.java
@@ -401,7 +401,7 @@
Editor ed = PreferenceManager.
getDefaultSharedPreferences(context).edit();
ed.putString(PREF_HOMEPAGE, url);
- ed.commit();
+ ed.apply();
homeUrl = url;
}
@@ -581,7 +581,7 @@
reset();
SharedPreferences p =
PreferenceManager.getDefaultSharedPreferences(ctx);
- p.edit().clear().commit();
+ p.edit().clear().apply();
PreferenceManager.setDefaultValues(ctx, R.xml.browser_preferences,
true);
// reset homeUrl
diff --git a/src/com/android/browser/SystemAllowGeolocationOrigins.java b/src/com/android/browser/SystemAllowGeolocationOrigins.java
index 3f5a84e..b53611f 100644
--- a/src/com/android/browser/SystemAllowGeolocationOrigins.java
+++ b/src/com/android/browser/SystemAllowGeolocationOrigins.java
@@ -103,7 +103,7 @@
// Save the new value as the last read value
preferences.edit()
.putString(LAST_READ_ALLOW_GEOLOCATION_ORIGINS, newSetting)
- .commit();
+ .apply();
Set<String> oldOrigins = parseAllowGeolocationOrigins(lastReadSetting);
Set<String> newOrigins = parseAllowGeolocationOrigins(newSetting);
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index a9ab058..7c52bb6 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -156,6 +156,7 @@
static final String PARENTTAB = "parentTab";
static final String APPID = "appid";
static final String ORIGINALURL = "originalUrl";
+ static final String INCOGNITO = "privateBrowsingEnabled";
// -------------------------------------------------------------------------
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index 333ce91..7377a1e 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -29,6 +29,7 @@
import java.io.File;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.Vector;
class TabControl {
@@ -150,6 +151,19 @@
}
/**
+ * Returns true if there are any incognito tabs open.
+ * @return True when any incognito tabs are open, false otherwise.
+ */
+ boolean hasAnyOpenIncognitoTabs() {
+ for (Tab tab : mTabs) {
+ if (tab.getWebView() != null && tab.getWebView().isPrivateBrowsingEnabled()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Create a new tab.
* @return The newly createTab or null if we have reached the maximum
* number of open tabs.
@@ -284,29 +298,56 @@
* @return True if there were previous tabs that were restored. False if
* there was no saved state or restoring the state failed.
*/
- boolean restoreState(Bundle inState) {
+ boolean restoreState(Bundle inState, boolean dontRestoreIncognitoTabs) {
final int numTabs = (inState == null)
? -1 : inState.getInt(Tab.NUMTABS, -1);
if (numTabs == -1) {
return false;
} else {
- final int currentTab = inState.getInt(Tab.CURRTAB, -1);
+ final int oldCurrentTab = inState.getInt(Tab.CURRTAB, -1);
+
+ // Determine whether the saved current tab can be restored, and
+ // if not, which tab will take its place.
+ int currentTab = -1;
+ if (!dontRestoreIncognitoTabs
+ || !inState.getBundle(Tab.WEBVIEW + oldCurrentTab).getBoolean(Tab.INCOGNITO)) {
+ currentTab = oldCurrentTab;
+ } else {
+ for (int i = 0; i < numTabs; i++) {
+ if (!inState.getBundle(Tab.WEBVIEW + i).getBoolean(Tab.INCOGNITO)) {
+ currentTab = i;
+ break;
+ }
+ }
+ }
+ if (currentTab < 0) {
+ return false;
+ }
+
+ // Map saved tab indices to new indices, in case any incognito tabs
+ // need to not be restored.
+ HashMap<Integer, Integer> originalTabIndices = new HashMap<Integer, Integer>();
+ originalTabIndices.put(-1, -1);
for (int i = 0; i < numTabs; i++) {
- if (i == currentTab) {
+ Bundle state = inState.getBundle(Tab.WEBVIEW + i);
+
+ if (dontRestoreIncognitoTabs && state != null && state.getBoolean(Tab.INCOGNITO)) {
+ originalTabIndices.put(i, -1);
+ } else if (i == currentTab) {
Tab t = createNewTab();
// Me must set the current tab before restoring the state
// so that all the client classes are set.
setCurrentTab(t);
- if (!t.restoreState(inState.getBundle(Tab.WEBVIEW + i))) {
+ if (!t.restoreState(state)) {
Log.w(LOGTAG, "Fail in restoreState, load home page.");
t.getWebView().loadUrl(BrowserSettings.getInstance()
.getHomePage());
}
+ originalTabIndices.put(i, getTabCount() - 1);
} else {
// Create a new tab and don't restore the state yet, add it
// to the tab list
Tab t = new Tab(mActivity, null, false, null, null);
- Bundle state = inState.getBundle(Tab.WEBVIEW + i);
if (state != null) {
t.setSavedState(state);
t.populatePickerDataFromSavedState();
@@ -318,15 +359,17 @@
mTabs.add(t);
// added the tab to the front as they are not current
mTabQueue.add(0, t);
+ originalTabIndices.put(i, getTabCount() - 1);
}
}
+
// Rebuild the tree of tabs. Do this after all tabs have been
// created/restored so that the parent tab exists.
for (int i = 0; i < numTabs; i++) {
final Bundle b = inState.getBundle(Tab.WEBVIEW + i);
final Tab t = getTab(i);
if (b != null && t != null) {
- final int parentIndex = b.getInt(Tab.PARENTTAB, -1);
+ final Integer parentIndex = originalTabIndices.get(b.getInt(Tab.PARENTTAB, -1));
if (parentIndex != -1) {
final Tab parent = getTab(parentIndex);
if (parent != null) {
diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index 5825525..cba585e 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -31,13 +31,13 @@
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
import android.provider.BrowserContract;
+import android.provider.SyncStateContract;
import android.provider.BrowserContract.Bookmarks;
import android.provider.BrowserContract.ChromeSyncColumns;
import android.provider.BrowserContract.History;
import android.provider.BrowserContract.Searches;
import android.provider.BrowserContract.SyncState;
import android.provider.ContactsContract.RawContacts;
-import android.provider.SyncStateContract;
import android.text.TextUtils;
import java.util.HashMap;
@@ -73,6 +73,7 @@
static final long FIXED_ID_OTHER_BOOKMARKS = 4;
static final String DEFAULT_BOOKMARKS_SORT_ORDER = "position ASC, _id ASC";
+
static final UriMatcher URI_MATCHER = new UriMatcher(UriMatcher.NO_MATCH);
@@ -112,6 +113,8 @@
map.put(Bookmarks.ACCOUNT_TYPE, Bookmarks.ACCOUNT_TYPE);
map.put(Bookmarks.SOURCE_ID, Bookmarks.SOURCE_ID);
map.put(Bookmarks.VERSION, Bookmarks.VERSION);
+ map.put(Bookmarks.DATE_CREATED, Bookmarks.DATE_CREATED);
+ map.put(Bookmarks.DATE_MODIFIED, Bookmarks.DATE_MODIFIED);
map.put(Bookmarks.DIRTY, Bookmarks.DIRTY);
map.put(Bookmarks.SYNC1, Bookmarks.SYNC1);
map.put(Bookmarks.SYNC2, Bookmarks.SYNC2);
@@ -148,13 +151,13 @@
static final String qualifyColumn(String table, String column) {
return table + "." + column + " AS " + column;
}
-
+
DatabaseHelper mOpenHelper;
SyncStateContentProviderHelper mSyncHelper = new SyncStateContentProviderHelper();
final class DatabaseHelper extends SQLiteOpenHelper {
static final String DATABASE_NAME = "browser2.db";
- static final int DATABASE_VERSION = 15;
+ static final int DATABASE_VERSION = 16;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -177,6 +180,8 @@
Bookmarks.ACCOUNT_TYPE + " TEXT," +
Bookmarks.SOURCE_ID + " TEXT," +
Bookmarks.VERSION + " INTEGER NOT NULL DEFAULT 1," +
+ Bookmarks.DATE_CREATED + " INTEGER," +
+ Bookmarks.DATE_MODIFIED + " INTEGER," +
Bookmarks.DIRTY + " INTEGER NOT NULL DEFAULT 0," +
Bookmarks.SYNC1 + " TEXT," +
Bookmarks.SYNC2 + " TEXT," +
@@ -224,6 +229,7 @@
public void onOpen(SQLiteDatabase db) {
mSyncHelper.onDatabaseOpened(db);
}
+
private void createDefaultBookmarks(SQLiteDatabase db) {
ContentValues values = new ContentValues();
@@ -451,7 +457,7 @@
if (TextUtils.isEmpty(sortOrder)) {
sortOrder = DEFAULT_BOOKMARKS_SORT_ORDER;
}
-
+
qb.setProjectionMap(BOOKMARKS_PROJECTION_MAP);
qb.setTables(TABLE_BOOKMARKS);
break;
@@ -535,6 +541,7 @@
// If the caller isn't a sync adapter just go through and update all the
// bookmarks to have the deleted flag set.
ContentValues values = new ContentValues();
+ values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis());
values.put(Bookmarks.IS_DELETED, 1);
return updateInTransaction(uri, values, selection, selectionArgs,
callerIsSyncAdapter);
@@ -592,6 +599,9 @@
case BOOKMARKS: {
// Mark rows dirty if they're not coming from a sync adapater
if (!callerIsSyncAdapter) {
+ long now = System.currentTimeMillis();
+ values.put(Bookmarks.DATE_CREATED, now);
+ values.put(Bookmarks.DATE_MODIFIED, now);
values.put(Bookmarks.DIRTY, 1);
}
@@ -615,12 +625,12 @@
}
case SEARCHES: {
- id = db.insertOrThrow(TABLE_SEARCHES, Searches.SEARCH, values);
+ id = insertSearchesInTransaction(db, values);
break;
}
case SYNCSTATE: {
- id = mSyncHelper.insert(mDb, values);
+ id = mSyncHelper.insert(db, values);
break;
}
@@ -636,6 +646,31 @@
}
}
+ /**
+ * Searches are unique, so perform an UPSERT manually since SQLite doesn't support them.
+ */
+ private long insertSearchesInTransaction(SQLiteDatabase db, ContentValues values) {
+ String search = values.getAsString(Searches.SEARCH);
+ if (TextUtils.isEmpty(search)) {
+ throw new IllegalArgumentException("Must include the SEARCH field");
+ }
+ Cursor cursor = null;
+ try {
+ cursor = db.query(TABLE_SEARCHES, new String[] { Searches._ID },
+ Searches.SEARCH + "=?", new String[] { search }, null, null, null);
+ if (cursor.moveToNext()) {
+ long id = cursor.getLong(0);
+ db.update(TABLE_SEARCHES, values, Searches._ID + "=?",
+ new String[] { Long.toString(id) });
+ return id;
+ } else {
+ return db.insertOrThrow(TABLE_SEARCHES, Searches.SEARCH, values);
+ }
+ } finally {
+ if (cursor != null) cursor.close();
+ }
+ }
+
@Override
public int updateInTransaction(Uri uri, ContentValues values, String selection,
String[] selectionArgs, boolean callerIsSyncAdapter) {
@@ -664,16 +699,6 @@
return db.update(TABLE_HISTORY, values, selection, selectionArgs);
}
- case SEARCHES_ID: {
- selection = DatabaseUtils.concatenateWhere(selection, TABLE_SEARCHES + "._id=?");
- selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
- new String[] { Long.toString(ContentUris.parseId(uri)) });
- // fall through
- }
- case SEARCHES: {
- return db.update(TABLE_SEARCHES, values, selection, selectionArgs);
- }
-
case SYNCSTATE: {
return mSyncHelper.update(mDb, values,
appendAccountToSelection(uri, selection), selectionArgs);
@@ -706,6 +731,7 @@
// Mark the bookmark dirty if the caller isn't a sync adapter
if (!callerIsSyncAdapter) {
values = new ContentValues(values);
+ values.put(Bookmarks.DATE_MODIFIED, System.currentTimeMillis());
values.put(Bookmarks.DIRTY, 1);
}
while (cursor.moveToNext()) {