summaryrefslogtreecommitdiffstats
path: root/src/com/android
diff options
context:
space:
mode:
authorJohn Reck <jreck@google.com>2011-07-27 14:33:12 -0700
committerAndroid (Google) Code Review <android-gerrit@google.com>2011-07-27 14:33:12 -0700
commitb56c13d0aef21002c18b7c9515dffda224ad19c8 (patch)
tree20270fe476841afd36233db64768605258c6c3ec /src/com/android
parentcf1df73719e171915eed887a5f06916158e42f04 (diff)
parent1cf4b79a0020bc18c83ca8bde0e318ecd5252bc2 (diff)
downloadandroid_packages_apps_Gello-b56c13d0aef21002c18b7c9515dffda224ad19c8.tar.gz
android_packages_apps_Gello-b56c13d0aef21002c18b7c9515dffda224ad19c8.tar.bz2
android_packages_apps_Gello-b56c13d0aef21002c18b7c9515dffda224ad19c8.zip
Merge "Restore overhaul"
Diffstat (limited to 'src/com/android')
-rw-r--r--src/com/android/browser/BaseUi.java14
-rw-r--r--src/com/android/browser/BrowserActivity.java4
-rw-r--r--src/com/android/browser/Controller.java59
-rw-r--r--src/com/android/browser/CrashRecoveryHandler.java2
-rw-r--r--src/com/android/browser/PhoneUi.java5
-rw-r--r--src/com/android/browser/PieControlPhone.java2
-rw-r--r--src/com/android/browser/PieControlXLarge.java2
-rw-r--r--src/com/android/browser/PreloadController.java5
-rw-r--r--src/com/android/browser/SnapshotTab.java18
-rw-r--r--src/com/android/browser/Tab.java273
-rw-r--r--src/com/android/browser/TabControl.java43
-rw-r--r--src/com/android/browser/UI.java2
-rw-r--r--src/com/android/browser/WebViewController.java2
-rw-r--r--src/com/android/browser/XLargeUi.java9
-rw-r--r--src/com/android/browser/provider/BrowserProvider2.java60
15 files changed, 359 insertions, 141 deletions
diff --git a/src/com/android/browser/BaseUi.java b/src/com/android/browser/BaseUi.java
index b270dea7..091126c8 100644
--- a/src/com/android/browser/BaseUi.java
+++ b/src/com/android/browser/BaseUi.java
@@ -738,20 +738,6 @@ public abstract class BaseUi implements UI, OnTouchListener {
warning.show();
}
- protected void captureTab(final Tab tab) {
- captureTab(tab,
- (int) mActivity.getResources()
- .getDimension(R.dimen.qc_thumb_width),
- (int) mActivity.getResources()
- .getDimension(R.dimen.qc_thumb_height));
- }
-
- protected void captureTab(final Tab tab, int width, int height) {
- if ((tab == null) || (tab.getWebView() == null)) return;
- Bitmap sshot = Controller.createScreenshot(tab, width, height);
- tab.setScreenshot(sshot);
- }
-
protected WebView getWebView() {
if (mActiveTab != null) {
return mActiveTab.getWebView();
diff --git a/src/com/android/browser/BrowserActivity.java b/src/com/android/browser/BrowserActivity.java
index 0df2e94d..6ec6071a 100644
--- a/src/com/android/browser/BrowserActivity.java
+++ b/src/com/android/browser/BrowserActivity.java
@@ -112,7 +112,7 @@ public class BrowserActivity extends Activity {
protected void onNewIntent(Intent intent) {
if (ACTION_RESTART.equals(intent.getAction())) {
Bundle outState = new Bundle();
- mController.onSaveInstanceState(outState, true);
+ mController.onSaveInstanceState(outState);
finish();
getApplicationContext().startActivity(
new Intent(getApplicationContext(), BrowserActivity.class)
@@ -163,7 +163,7 @@ public class BrowserActivity extends Activity {
if (LOGV_ENABLED) {
Log.v(LOGTAG, "BrowserActivity.onSaveInstanceState: this=" + this);
}
- mController.onSaveInstanceState(outState, true);
+ mController.onSaveInstanceState(outState);
}
@Override
diff --git a/src/com/android/browser/Controller.java b/src/com/android/browser/Controller.java
index b3be6187..92f448c9 100644
--- a/src/com/android/browser/Controller.java
+++ b/src/com/android/browser/Controller.java
@@ -80,6 +80,7 @@ import com.android.browser.IntentHandler.UrlData;
import com.android.browser.UI.ComboViews;
import com.android.browser.UI.DropdownChangeListener;
import com.android.browser.provider.BrowserProvider;
+import com.android.browser.provider.BrowserProvider2.Thumbnails;
import com.android.browser.provider.SnapshotProvider.Snapshots;
import com.android.browser.search.SearchEngine;
import com.android.common.Search;
@@ -87,6 +88,7 @@ import com.android.common.Search;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URLEncoder;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
@@ -309,6 +311,7 @@ public class Controller
private void onPreloginFinished(Bundle icicle, Intent intent, long currentTabId,
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
@@ -335,7 +338,13 @@ public class Controller
} else {
mTabControl.restoreState(icicle, currentTabId, restoreIncognitoTabs,
mUi.needsRestoreAllTabs());
- mUi.updateTabs(mTabControl.getTabs());
+ List<Tab> tabs = mTabControl.getTabs();
+ ArrayList<Long> restoredTabs = new ArrayList<Long>(tabs.size());
+ for (Tab t : tabs) {
+ restoredTabs.add(t.getId());
+ }
+ BackgroundHandler.execute(new PruneThumbnails(mActivity, restoredTabs));
+ mUi.updateTabs(tabs);
// TabControl.restoreState() will create a new tab even if
// restoring the state fails.
setActiveTab(mTabControl.getCurrentTab());
@@ -357,6 +366,38 @@ public class Controller
}
}
+ private static class PruneThumbnails implements Runnable {
+ private Context mContext;
+ private List<Long> mIds;
+
+ PruneThumbnails(Context context, List<Long> preserveIds) {
+ mContext = context.getApplicationContext();
+ mIds = preserveIds;
+ }
+
+ @Override
+ public void run() {
+ ContentResolver cr = mContext.getContentResolver();
+ if (mIds == null || mIds.size() == 0) {
+ cr.delete(Thumbnails.CONTENT_URI, null, null);
+ } else {
+ int length = mIds.size();
+ StringBuilder where = new StringBuilder();
+ where.append(Thumbnails._ID);
+ where.append(" not in (");
+ for (int i = 0; i < length; i++) {
+ where.append(mIds.get(i));
+ if (i < (length - 1)) {
+ where.append(",");
+ }
+ }
+ where.append(")");
+ cr.delete(Thumbnails.CONTENT_URI, where.toString(), null);
+ }
+ }
+
+ }
+
@Override
public WebViewFactory getWebViewFactory() {
return mFactory;
@@ -612,7 +653,7 @@ public class Controller
}
- void onSaveInstanceState(Bundle outState, boolean saveImages) {
+ 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
@@ -620,7 +661,7 @@ public class Controller
// focused view XXX has no id".
// Save all the tabs
- mTabControl.saveState(outState, false);
+ mTabControl.saveState(outState);
if (!outState.isEmpty()) {
// Save time so that we know how old incognito tabs (if any) are.
outState.putSerializable("lastActiveDate", Calendar.getInstance());
@@ -1902,13 +1943,6 @@ public class Controller
R.dimen.bookmarkThumbnailHeight);
}
- static Bitmap createScreenshot(Tab tab, int width, int height) {
- if ((tab != null) && (tab.getWebView() != null)) {
- return createScreenshot(tab.getWebView(), width, height);
- }
- return null;
- }
-
static Bitmap createScreenshot(WebView view, int width, int height) {
// We render to a bitmap 2x the desired size so that we can then
// re-scale it with filtering since canvas.scale doesn't filter
@@ -2646,4 +2680,9 @@ public class Controller
return true;
}
+ @Override
+ public boolean shouldCaptureThumbnails() {
+ return mUi.shouldCaptureThumbnails();
+ }
+
}
diff --git a/src/com/android/browser/CrashRecoveryHandler.java b/src/com/android/browser/CrashRecoveryHandler.java
index 02636c0f..fdcdbc6c 100644
--- a/src/com/android/browser/CrashRecoveryHandler.java
+++ b/src/com/android/browser/CrashRecoveryHandler.java
@@ -133,7 +133,7 @@ public class CrashRecoveryHandler {
public void run() {
try {
final Bundle state = new Bundle();
- mController.onSaveInstanceState(state, false);
+ mController.onSaveInstanceState(state);
Message.obtain(mBackgroundHandler, MSG_WRITE_STATE, state)
.sendToTarget();
// Remove any queued up saves
diff --git a/src/com/android/browser/PhoneUi.java b/src/com/android/browser/PhoneUi.java
index 28db6f0f..1c9d5a04 100644
--- a/src/com/android/browser/PhoneUi.java
+++ b/src/com/android/browser/PhoneUi.java
@@ -276,4 +276,9 @@ public class PhoneUi extends BaseUi {
}
}
+ @Override
+ public boolean shouldCaptureThumbnails() {
+ return true;
+ }
+
}
diff --git a/src/com/android/browser/PieControlPhone.java b/src/com/android/browser/PieControlPhone.java
index c4b28fa3..0b62cef9 100644
--- a/src/com/android/browser/PieControlPhone.java
+++ b/src/com/android/browser/PieControlPhone.java
@@ -72,7 +72,7 @@ public class PieControlPhone extends PieControlBase implements OnClickListener {
private void buildTabs() {
final List<Tab> tabs = mUiController.getTabs();
- mUi.captureTab(mUi.getActiveTab());
+ mUi.getActiveTab().capture();
mTabAdapter.setTabs(tabs);
PieStackView sym = (PieStackView) mShowTabs.getPieView();
sym.setCurrent(mUiController.getTabControl().getCurrentPosition());
diff --git a/src/com/android/browser/PieControlXLarge.java b/src/com/android/browser/PieControlXLarge.java
index a036e0de..95f586e4 100644
--- a/src/com/android/browser/PieControlXLarge.java
+++ b/src/com/android/browser/PieControlXLarge.java
@@ -112,7 +112,7 @@ public class PieControlXLarge extends PieControlBase implements OnClickListener
private void buildTabs() {
final List<Tab> tabs = mUiController.getTabs();
- mUi.captureTab(mUi.getActiveTab());
+ mUi.getActiveTab().capture();
mTabAdapter.setTabs(tabs);
PieStackView sym = (PieStackView) mShowTabs.getPieView();
sym.setCurrent(mUiController.getTabControl().getCurrentPosition());
diff --git a/src/com/android/browser/PreloadController.java b/src/com/android/browser/PreloadController.java
index 652ea8ef..08e223f5 100644
--- a/src/com/android/browser/PreloadController.java
+++ b/src/com/android/browser/PreloadController.java
@@ -276,4 +276,9 @@ public class PreloadController implements WebViewController {
if (LOGD_ENABLED) Log.d(LOGTAG, "hideAutoLogin()");
}
+ @Override
+ public boolean shouldCaptureThumbnails() {
+ return false;
+ }
+
}
diff --git a/src/com/android/browser/SnapshotTab.java b/src/com/android/browser/SnapshotTab.java
index e57502f4..bd6dd5b8 100644
--- a/src/com/android/browser/SnapshotTab.java
+++ b/src/com/android/browser/SnapshotTab.java
@@ -22,6 +22,7 @@ import android.database.Cursor;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
+import android.os.Bundle;
import android.util.Log;
import android.webkit.WebView;
@@ -44,7 +45,7 @@ public class SnapshotTab extends Tab {
private boolean mIsLive;
public SnapshotTab(WebViewController wvcontroller, long snapshotId) {
- super(wvcontroller, null);
+ super(wvcontroller, null, null);
mSnapshotId = snapshotId;
mWebViewFactory = mWebViewController.getWebViewFactory();
WebView web = mWebViewFactory.createWebView(false);
@@ -98,8 +99,8 @@ public class SnapshotTab extends Tab {
}
@Override
- boolean saveState() {
- return false;
+ Bundle saveState() {
+ return null;
}
public long getDateCreated() {
@@ -198,4 +199,15 @@ public class SnapshotTab extends Tab {
}
}
+
+ @Override
+ protected void persistThumbnail() {
+ // Nope
+ }
+
+ @Override
+ protected void deleteThumbnail() {
+ // Nope
+ }
+
}
diff --git a/src/com/android/browser/Tab.java b/src/com/android/browser/Tab.java
index beac2ff4..a4bcc99c 100644
--- a/src/com/android/browser/Tab.java
+++ b/src/com/android/browser/Tab.java
@@ -20,11 +20,13 @@ import android.app.Activity;
import android.app.AlertDialog;
import android.app.SearchManager;
import android.content.ContentResolver;
+import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnCancelListener;
import android.content.Intent;
+import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
@@ -53,7 +55,6 @@ import android.webkit.HttpAuthHandler;
import android.webkit.SslErrorHandler;
import android.webkit.URLUtil;
import android.webkit.ValueCallback;
-import android.webkit.WebBackForwardList;
import android.webkit.WebBackForwardListClient;
import android.webkit.WebChromeClient;
import android.webkit.WebHistoryItem;
@@ -68,10 +69,12 @@ import android.widget.TextView;
import android.widget.Toast;
import com.android.browser.homepages.HomeProvider;
+import com.android.browser.provider.BrowserProvider2.Thumbnails;
import com.android.browser.provider.SnapshotProvider.Snapshots;
import com.android.common.speech.LoggingEvents;
import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
@@ -95,6 +98,8 @@ class Tab implements PictureListener {
private static final int MSG_CAPTURE = 42;
private static final int CAPTURE_DELAY = 500;
+ private static Bitmap sDefaultFavicon;
+
public enum LockIcon {
LOCK_ICON_UNSECURE,
LOCK_ICON_SECURE,
@@ -161,6 +166,13 @@ class Tab implements PictureListener {
private Bitmap mCapture;
private Handler mHandler;
+ private static synchronized Bitmap getDefaultFavicon(Context context) {
+ if (sDefaultFavicon == null) {
+ sDefaultFavicon = BitmapFactory.decodeResource(
+ context.getResources(), R.drawable.app_web_browser_sm);
+ }
+ return sDefaultFavicon;
+ }
// All the state needed for a page
protected static class PageState {
@@ -179,8 +191,7 @@ class Tab implements PictureListener {
mOriginalUrl = mUrl = "";
mTitle = c.getString(R.string.new_tab);
}
- mFavicon = BitmapFactory.decodeResource(
- c.getResources(), R.drawable.app_web_browser_sm);
+ mFavicon = null;
mLockIcon = LockIcon.LOCK_ICON_UNSECURE;
}
@@ -192,13 +203,9 @@ class Tab implements PictureListener {
} else {
mLockIcon = LockIcon.LOCK_ICON_UNSECURE;
}
- if (favicon != null) {
- mFavicon = favicon;
- } else {
- mFavicon = BitmapFactory.decodeResource(
- c.getResources(), R.drawable.app_web_browser_sm);
- }
+ mFavicon = favicon;
}
+
}
// The current/loading page's state
@@ -211,7 +218,6 @@ class Tab implements PictureListener {
static final String PARENTTAB = "parentTab";
static final String APPID = "appid";
static final String INCOGNITO = "privateBrowsingEnabled";
- static final String SCREENSHOT = "screenshot";
static final String USERAGENT = "useragent";
// -------------------------------------------------------------------------
@@ -576,19 +582,7 @@ class Tab implements PictureListener {
url, SystemClock.uptimeMillis() - mLoadStartTime);
}
mInPageLoad = false;
- // Sync state (in case of stop/timeout)
- mCurrentState.mUrl = view.getUrl();
- if (mCurrentState.mUrl == null) {
- mCurrentState.mUrl = url != null ? url : "";
- }
- mCurrentState.mOriginalUrl = view.getOriginalUrl();
- mCurrentState.mTitle = view.getTitle();
- mCurrentState.mFavicon = view.getFavicon();
- if (!URLUtil.isHttpsUrl(mCurrentState.mUrl)) {
- // In case we stop when loading an HTTPS page from an HTTP page
- // but before a provisional load occurred
- mCurrentState.mLockIcon = LockIcon.LOCK_ICON_UNSECURE;
- }
+ syncCurrentState(view, url);
mWebViewController.onPageFinished(Tab.this);
}
@@ -894,6 +888,22 @@ class Tab implements PictureListener {
};
+ private void syncCurrentState(WebView view, String url) {
+ // Sync state (in case of stop/timeout)
+ mCurrentState.mUrl = view.getUrl();
+ if (mCurrentState.mUrl == null) {
+ mCurrentState.mUrl = url != null ? url : "";
+ }
+ mCurrentState.mOriginalUrl = view.getOriginalUrl();
+ mCurrentState.mTitle = view.getTitle();
+ mCurrentState.mFavicon = view.getFavicon();
+ if (!URLUtil.isHttpsUrl(mCurrentState.mUrl)) {
+ // In case we stop when loading an HTTPS page from an HTTP page
+ // but before a provisional load occurred
+ mCurrentState.mLockIcon = LockIcon.LOCK_ICON_UNSECURE;
+ }
+ }
+
// Called by DeviceAccountLogin when the Tab needs to have the auto-login UI
// displayed.
void setDeviceAccountLogin(DeviceAccountLogin login) {
@@ -1355,11 +1365,16 @@ class Tab implements PictureListener {
// -------------------------------------------------------------------------
- // TODO temporarily use activity here
- // remove later
-
// Construct a new tab
Tab(WebViewController wvcontroller, WebView w) {
+ this(wvcontroller, w, null);
+ }
+
+ Tab(WebViewController wvcontroller, Bundle state) {
+ this(wvcontroller, null, state);
+ }
+
+ Tab(WebViewController wvcontroller, WebView w, Bundle state) {
mWebViewController = wvcontroller;
mContext = mWebViewController.getContext();
mSettings = BrowserSettings.getInstance();
@@ -1393,21 +1408,46 @@ class Tab implements PictureListener {
}
};
+ mCaptureWidth = mContext.getResources().getDimensionPixelSize(
+ R.dimen.tab_thumbnail_width);
+ mCaptureHeight = mContext.getResources().getDimensionPixelSize(
+ R.dimen.tab_thumbnail_height);
+ updateShouldCaptureThumbnails();
+ restoreState(state);
setWebView(w);
- mCaptureWidth = mContext.getResources().getDimensionPixelSize(R.dimen.nav_tab_width);
- mCaptureHeight = mContext.getResources().getDimensionPixelSize(R.dimen.nav_tab_height);
- mCapture = Bitmap.createBitmap(mCaptureWidth, mCaptureHeight,
- Bitmap.Config.RGB_565);
mHandler = new Handler() {
public void handleMessage(Message m) {
- Tab.this.capture();
+ switch (m.what) {
+ case MSG_CAPTURE:
+ capture();
+ break;
+ }
}
};
+ }
+ public void updateShouldCaptureThumbnails() {
+ if (mWebViewController.shouldCaptureThumbnails()) {
+ synchronized (Tab.this) {
+ if (mCapture == null) {
+ mCapture = Bitmap.createBitmap(mCaptureWidth, mCaptureHeight,
+ Bitmap.Config.RGB_565);
+ if (mInForeground) {
+ postCapture();
+ }
+ }
+ }
+ } else {
+ synchronized (Tab.this) {
+ mCapture = null;
+ deleteThumbnail();
+ }
+ }
}
public void setController(WebViewController ctl) {
mWebViewController = ctl;
+ updateShouldCaptureThumbnails();
}
public void setId(long id) {
@@ -1435,6 +1475,13 @@ class Tab implements PictureListener {
mWebViewController.onSetWebView(this, w);
+ if (mMainView != null) {
+ if (w != null) {
+ syncCurrentState(w, null);
+ } else {
+ mCurrentState = new PageState(mContext, false);
+ }
+ }
// set the new one
mMainView = w;
// attach the WebViewClient, WebChromeClient and DownloadListener
@@ -1448,6 +1495,10 @@ class Tab implements PictureListener {
mMainView.setDownloadListener(mDownloadListener);
mMainView.setWebBackForwardListClient(mWebBackForwardListClient);
mMainView.setPictureListener(this);
+ if (mSavedState != null) {
+ mMainView.restoreState(mSavedState);
+ mSavedState = null;
+ }
}
}
@@ -1480,6 +1531,7 @@ class Tab implements PictureListener {
if (mParent != null) {
mParent.mChildren.remove(this);
}
+ deleteThumbnail();
}
/**
@@ -1739,7 +1791,10 @@ class Tab implements PictureListener {
* Get the favicon of this tab.
*/
Bitmap getFavicon() {
- return mCurrentState.mFavicon;
+ if (mCurrentState.mFavicon != null) {
+ return mCurrentState.mFavicon;
+ }
+ return getDefaultFavicon(mContext);
}
public boolean isBookmarkedSite() {
@@ -1796,43 +1851,19 @@ class Tab implements PictureListener {
}
/**
- * Get the cached saved state bundle.
- * @return cached state bundle
+ * @return The Bundle with the tab's state if it can be saved, otherwise null
*/
- Bundle getSavedState() {
- return mSavedState;
- }
-
- Bundle getSavedState(boolean saveImages) {
- if (saveImages && mCapture != null) {
- Bundle b = new Bundle(mSavedState);
- b.putParcelable(SCREENSHOT, mCapture);
- return b;
- }
- return mSavedState;
- }
-
- /**
- * Set the saved state.
- */
- void setSavedState(Bundle state) {
- mSavedState = state;
- }
-
- /**
- * @return TRUE if succeed in saving the state.
- */
- boolean saveState() {
+ public Bundle saveState() {
// If the WebView is null it means we ran low on memory and we already
// stored the saved state in mSavedState.
if (mMainView == null) {
- return mSavedState != null;
+ return mSavedState;
}
// If the tab is the homepage or has no URL, don't save it
String homepage = BrowserSettings.getInstance().getHomePage();
if (TextUtils.equals(homepage, mCurrentState.mUrl)
|| TextUtils.isEmpty(mCurrentState.mUrl)) {
- return false;
+ return null;
}
mSavedState = new Bundle();
@@ -1841,6 +1872,7 @@ class Tab implements PictureListener {
mSavedState.putLong(ID, mId);
mSavedState.putString(CURRURL, mCurrentState.mUrl);
mSavedState.putString(CURRTITLE, mCurrentState.mTitle);
+ mSavedState.putBoolean(INCOGNITO, mMainView.isPrivateBrowsingEnabled());
if (mAppId != null) {
mSavedState.putString(APPID, mAppId);
}
@@ -1850,35 +1882,35 @@ class Tab implements PictureListener {
}
mSavedState.putBoolean(USERAGENT,
mSettings.hasDesktopUseragent(getWebView()));
- return true;
+ return mSavedState;
}
/*
* Restore the state of the tab.
*/
- boolean restoreState(Bundle b) {
- if (b == null) {
- return false;
+ private void restoreState(Bundle b) {
+ mSavedState = b;
+ if (mSavedState == null) {
+ return;
}
// Restore the internal state even if the WebView fails to restore.
// This will maintain the app id, original url and close-on-exit values.
- mSavedState = null;
mId = b.getLong(ID);
mAppId = b.getString(APPID);
- final Bitmap sshot = b.getParcelable(SCREENSHOT);
- if (sshot != null) {
- mCapture = sshot;
- }
if (b.getBoolean(USERAGENT)
!= mSettings.hasDesktopUseragent(getWebView())) {
mSettings.toggleDesktopUseragent(getWebView());
}
-
- final WebBackForwardList list = mMainView.restoreState(b);
- if (list == null) {
- return false;
+ String url = b.getString(CURRURL);
+ String title = b.getString(CURRTITLE);
+ boolean incognito = b.getBoolean(INCOGNITO);
+ mCurrentState = new PageState(mContext, incognito, url, null);
+ mCurrentState.mTitle = title;
+ synchronized (Tab.this) {
+ if (mCapture != null) {
+ BackgroundHandler.execute(mLoadThumbnail);
+ }
}
- return true;
}
public void updateBookmarkedStatus() {
@@ -1896,12 +1928,10 @@ class Tab implements PictureListener {
}
};
- public void setScreenshot(Bitmap screenshot) {
- mCapture = screenshot;
- }
-
public Bitmap getScreenshot() {
- return mCapture;
+ synchronized (Tab.this) {
+ return mCapture;
+ }
}
public boolean isSnapshot() {
@@ -1963,11 +1993,16 @@ class Tab implements PictureListener {
float scale = mCaptureWidth / (float) mMainView.getWidth();
c.scale(scale, scale, left, top);
mMainView.draw(c);
+ persistThumbnail();
}
@Override
public void onNewPicture(WebView view, Picture picture) {
//update screenshot
+ postCapture();
+ }
+
+ private void postCapture() {
if (!mHandler.hasMessages(MSG_CAPTURE)) {
mHandler.sendEmptyMessageDelayed(MSG_CAPTURE, CAPTURE_DELAY);
}
@@ -1993,4 +2028,84 @@ class Tab implements PictureListener {
}
}
+ protected void persistThumbnail() {
+ BackgroundHandler.execute(mSaveThumbnail);
+ }
+
+ protected void deleteThumbnail() {
+ BackgroundHandler.execute(mDeleteThumbnail);
+ }
+
+ private void updateCaptureFromBlob(byte[] blob) {
+ synchronized (Tab.this) {
+ if (mCapture == null) {
+ return;
+ }
+ mCapture.copyPixelsFromBuffer(ByteBuffer.wrap(blob));
+ }
+ }
+
+ private byte[] getCaptureBlob() {
+ synchronized (Tab.this) {
+ if (mCapture == null) {
+ return null;
+ }
+ ByteBuffer buffer = ByteBuffer.allocate(mCapture.getByteCount());
+ mCapture.copyPixelsToBuffer(buffer);
+ return buffer.array();
+ }
+ }
+
+ private Runnable mSaveThumbnail = new Runnable() {
+
+ @Override
+ public void run() {
+ byte[] blob = getCaptureBlob();
+ if (blob == null) {
+ return;
+ }
+ ContentResolver cr = mContext.getContentResolver();
+ ContentValues values = new ContentValues();
+ values.put(Thumbnails._ID, mId);
+ values.put(Thumbnails.THUMBNAIL, blob);
+ cr.insert(Thumbnails.CONTENT_URI, values);
+ }
+ };
+
+ private Runnable mDeleteThumbnail = new Runnable() {
+
+ @Override
+ public void run() {
+ ContentResolver cr = mContext.getContentResolver();
+ try {
+ cr.delete(ContentUris.withAppendedId(Thumbnails.CONTENT_URI, mId),
+ null, null);
+ } catch (Throwable t) {}
+ }
+ };
+
+ private Runnable mLoadThumbnail = new Runnable() {
+
+ @Override
+ public void run() {
+ ContentResolver cr = mContext.getContentResolver();
+ Cursor c = null;
+ try {
+ Uri uri = ContentUris.withAppendedId(Thumbnails.CONTENT_URI, mId);
+ c = cr.query(uri, new String[] {Thumbnails._ID,
+ Thumbnails.THUMBNAIL}, null, null, null);
+ if (c.moveToFirst()) {
+ byte[] data = c.getBlob(1);
+ if (data != null && data.length > 0) {
+ updateCaptureFromBlob(data);
+ }
+ }
+ } finally {
+ if (c != null) {
+ c.close();
+ }
+ }
+ }
+ };
+
}
diff --git a/src/com/android/browser/TabControl.java b/src/com/android/browser/TabControl.java
index cd8da2ed..b7088413 100644
--- a/src/com/android/browser/TabControl.java
+++ b/src/com/android/browser/TabControl.java
@@ -186,6 +186,12 @@ class TabControl {
* number of open tabs.
*/
Tab createNewTab(boolean privateBrowsing) {
+ return createNewTab(null, privateBrowsing);
+ }
+
+ Tab createNewTab(Bundle state, boolean privateBrowsing) {
+ int size = mTabs.size();
+ // Return false if we have maxed out on tabs
if (!canCreateNewTab()) {
return null;
}
@@ -193,7 +199,7 @@ class TabControl {
final WebView w = createNewWebView(privateBrowsing);
// Create a new tab and add it to the tab list
- Tab t = new Tab(mController, w);
+ Tab t = new Tab(mController, w, state);
t.setId(getNextId());
mTabs.add(t);
// Initially put the tab in the background.
@@ -288,7 +294,7 @@ class TabControl {
* @param outState
* @param saveImages
*/
- void saveState(Bundle outState, boolean saveImages) {
+ void saveState(Bundle outState) {
final int numTabs = getTabCount();
if (numTabs == 0) {
return;
@@ -296,10 +302,10 @@ class TabControl {
long[] ids = new long[numTabs];
int i = 0;
for (Tab tab : mTabs) {
- if (tab.saveState()) {
+ Bundle tabState = tab.saveState();
+ if (tabState != null) {
ids[i++] = tab.getId();
- outState.putBundle(Long.toString(tab.getId()),
- tab.getSavedState(saveImages));
+ outState.putBundle(Long.toString(tab.getId()), tabState);
} else {
ids[i++] = -1;
}
@@ -329,7 +335,7 @@ class TabControl {
final long oldcurrent = inState.getLong(CURRENT);
long current = -1;
if (restoreIncognitoTabs || (hasState(oldcurrent, inState) && !isIncognito(oldcurrent, inState))) {
- current = oldcurrent;
+ current = oldcurrent;
} else {
// pick first non incognito tab
for (long id : ids) {
@@ -363,8 +369,6 @@ class TabControl {
* @param restoreIncognitoTabs Restoring private browsing tabs
* @param restoreAll All webviews get restored, not just the current tab
* (this does not override handling of incognito tabs)
- * @return True if there were previous tabs that were restored. False if
- * there was no saved state or restoring the state failed.
*/
void restoreState(Bundle inState, long currentId,
boolean restoreIncognitoTabs, boolean restoreAll) {
@@ -387,7 +391,7 @@ class TabControl {
&& state.getBoolean(Tab.INCOGNITO)) {
// ignore tab
} else if (id == currentId || restoreAll) {
- Tab t = createNewTab();
+ Tab t = createNewTab(state, false);
if (t == null) {
// We could "break" at this point, but we want
// sNextId to be set correctly.
@@ -399,23 +403,12 @@ class TabControl {
if (id == currentId) {
setCurrentTab(t);
}
- if (!t.restoreState(state)) {
- Log.w(LOGTAG, "Fail in restoreState, load home page.");
- t.getWebView().loadUrl(BrowserSettings.getInstance()
- .getHomePage());
- }
} else {
// Create a new tab and don't restore the state yet, add it
// to the tab list
- Tab t = new Tab(mController, null);
+ Tab t = new Tab(mController, state);
t.setId(id);
tabMap.put(id, t);
- if (state != null) {
- t.setSavedState(state);
- // Need to maintain the app id and original url so we
- // can possibly reuse this tab.
- t.setAppId(state.getString(Tab.APPID));
- }
mTabs.add(t);
// added the tab to the front as they are not current
mTabQueue.add(0, t);
@@ -619,8 +612,6 @@ class TabControl {
if (getCurrentTab() == t) {
setCurrentTab(t, true);
}
- // Clear the saved state and picker data
- t.setSavedState(null);
}
/**
@@ -681,12 +672,6 @@ class TabControl {
newTab.setWebView(mainView);
}
newTab.putInForeground();
- if (needRestore) {
- // Have to finish setCurrentTab work before calling restoreState
- if (!newTab.restoreState(newTab.getSavedState())) {
- mainView.loadUrl(BrowserSettings.getInstance().getHomePage());
- }
- }
return true;
}
diff --git a/src/com/android/browser/UI.java b/src/com/android/browser/UI.java
index 23897f70..2984d5c3 100644
--- a/src/com/android/browser/UI.java
+++ b/src/com/android/browser/UI.java
@@ -147,4 +147,6 @@ public interface UI {
void setUseQuickControls(boolean enabled);
+ public boolean shouldCaptureThumbnails();
+
}
diff --git a/src/com/android/browser/WebViewController.java b/src/com/android/browser/WebViewController.java
index 175cbf83..f4ff764c 100644
--- a/src/com/android/browser/WebViewController.java
+++ b/src/com/android/browser/WebViewController.java
@@ -122,4 +122,6 @@ public interface WebViewController {
void showAutoLogin(Tab tab);
void hideAutoLogin(Tab tab);
+
+ boolean shouldCaptureThumbnails();
}
diff --git a/src/com/android/browser/XLargeUi.java b/src/com/android/browser/XLargeUi.java
index 73821bf7..aeba7cff 100644
--- a/src/com/android/browser/XLargeUi.java
+++ b/src/com/android/browser/XLargeUi.java
@@ -101,6 +101,10 @@ public class XLargeUi extends BaseUi {
setTitleGravity(Gravity.NO_GRAVITY);
}
mTabBar.setUseQuickControls(mUseQuickControls);
+ // We need to update the tabs with this change
+ for (Tab t : mTabControl.getTabs()) {
+ t.updateShouldCaptureThumbnails();
+ }
}
private void checkTabCount() {
@@ -334,4 +338,9 @@ public class XLargeUi extends BaseUi {
return mTabBar;
}
+ @Override
+ public boolean shouldCaptureThumbnails() {
+ return mUseQuickControls;
+ }
+
}
diff --git a/src/com/android/browser/provider/BrowserProvider2.java b/src/com/android/browser/provider/BrowserProvider2.java
index b974c0e1..e40a8821 100644
--- a/src/com/android/browser/provider/BrowserProvider2.java
+++ b/src/com/android/browser/provider/BrowserProvider2.java
@@ -74,6 +74,13 @@ public class BrowserProvider2 extends SQLiteContentProvider {
static final Uri LEGACY_AUTHORITY_URI = new Uri.Builder()
.authority(LEGACY_AUTHORITY).scheme("content").build();
+ public static interface Thumbnails {
+ public static final Uri CONTENT_URI = Uri.withAppendedPath(
+ BrowserContract.AUTHORITY_URI, "thumbnails");
+ public static final String _ID = "_id";
+ public static final String THUMBNAIL = "thumbnail";
+ }
+
static final String TABLE_BOOKMARKS = "bookmarks";
static final String TABLE_HISTORY = "history";
static final String TABLE_IMAGES = "images";
@@ -81,6 +88,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
static final String TABLE_SYNC_STATE = "syncstate";
static final String TABLE_SETTINGS = "settings";
static final String TABLE_SNAPSHOTS = "snapshots";
+ static final String TABLE_THUMBNAILS = "thumbnails";
static final String TABLE_BOOKMARKS_JOIN_IMAGES = "bookmarks LEFT OUTER JOIN images " +
"ON bookmarks.url = images." + Images.URL;
@@ -111,6 +119,9 @@ public class BrowserProvider2 extends SQLiteContentProvider {
"WHERE url IS NOT NULL AND deleted == 0) AND url_key NOT IN " +
"(SELECT url FROM history WHERE url IS NOT NULL)";
+ static final int THUMBNAILS = 10;
+ static final int THUMBNAILS_ID = 11;
+
static final int BOOKMARKS = 1000;
static final int BOOKMARKS_ID = 1001;
static final int BOOKMARKS_FOLDER = 1002;
@@ -187,6 +198,8 @@ public class BrowserProvider2 extends SQLiteContentProvider {
matcher.addURI(authority, "combined", COMBINED);
matcher.addURI(authority, "combined/#", COMBINED_ID);
matcher.addURI(authority, "settings", SETTINGS);
+ matcher.addURI(authority, "thumbnails", THUMBNAILS);
+ matcher.addURI(authority, "thumbnails/#", THUMBNAILS_ID);
// Legacy
matcher.addURI(LEGACY_AUTHORITY, "searches", SEARCHES);
@@ -333,7 +346,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
final class DatabaseHelper extends SQLiteOpenHelper {
static final String DATABASE_NAME = "browser2.db";
- static final int DATABASE_VERSION = 30;
+ static final int DATABASE_VERSION = 31;
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
@@ -396,6 +409,7 @@ public class BrowserProvider2 extends SQLiteContentProvider {
");");
createAccountsView(db);
+ createThumbnails(db);
mSyncHelper.createDatabase(db);
@@ -406,6 +420,13 @@ public class BrowserProvider2 extends SQLiteContentProvider {
enableSync(db);
}
+ void createThumbnails(SQLiteDatabase db) {
+ db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_THUMBNAILS + " (" +
+ Thumbnails._ID + " INTEGER PRIMARY KEY," +
+ Thumbnails.THUMBNAIL + " BLOB NOT NULL" +
+ ");");
+ }
+
void enableSync(SQLiteDatabase db) {
ContentValues values = new ContentValues();
values.put(Settings.KEY, Settings.KEY_SYNC_ENABLED);
@@ -500,6 +521,9 @@ public class BrowserProvider2 extends SQLiteContentProvider {
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+ if (oldVersion < 31) {
+ createThumbnails(db);
+ }
if (oldVersion < 30) {
db.execSQL("DROP VIEW IF EXISTS " + VIEW_SNAPSHOTS_COMBINED);
db.execSQL("DROP TABLE IF EXISTS " + TABLE_SNAPSHOTS);
@@ -974,6 +998,18 @@ public class BrowserProvider2 extends SQLiteContentProvider {
break;
}
+ case THUMBNAILS_ID: {
+ selection = DatabaseUtils.concatenateWhere(
+ selection, Thumbnails._ID + " = ?");
+ selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
+ new String[] { Long.toString(ContentUris.parseId(uri)) });
+ // fall through
+ }
+ case THUMBNAILS: {
+ qb.setTables(TABLE_THUMBNAILS);
+ break;
+ }
+
default: {
throw new UnsupportedOperationException("Unknown URL " + uri.toString());
}
@@ -1173,6 +1209,17 @@ public class BrowserProvider2 extends SQLiteContentProvider {
}
break;
}
+ case THUMBNAILS_ID: {
+ selection = DatabaseUtils.concatenateWhere(
+ selection, Thumbnails._ID + " = ?");
+ selectionArgs = DatabaseUtils.appendSelectionArgs(selectionArgs,
+ new String[] { Long.toString(ContentUris.parseId(uri)) });
+ // fall through
+ }
+ case THUMBNAILS: {
+ deleted = db.delete(TABLE_THUMBNAILS, selection, selectionArgs);
+ break;
+ }
default: {
throw new UnsupportedOperationException("Unknown delete URI " + uri);
}
@@ -1310,6 +1357,11 @@ public class BrowserProvider2 extends SQLiteContentProvider {
break;
}
+ case THUMBNAILS: {
+ id = db.replaceOrThrow(TABLE_THUMBNAILS, null, values);
+ break;
+ }
+
default: {
throw new UnsupportedOperationException("Unknown insert URI " + uri);
}
@@ -1552,6 +1604,12 @@ public class BrowserProvider2 extends SQLiteContentProvider {
break;
}
+ case THUMBNAILS: {
+ modified = db.update(TABLE_THUMBNAILS, values,
+ selection, selectionArgs);
+ break;
+ }
+
default: {
throw new UnsupportedOperationException("Unknown update URI " + uri);
}