Commit 1cf4b79a authored by John Reck's avatar John Reck
Browse files

Restore overhaul

 Bug: 5069192
 Store thumbnails in a database restored async for each tab
 Fix restoring a tab not restoring its current state

Change-Id: I2c14e352638aac0ef766fb3bf4036ff220c53ecd
parent ff6a748a
......@@ -37,4 +37,6 @@
<dimen name="suggest_item_padding">16dp</dimen>
<dimen name="toolbar_height">48dip</dimen>
<dimen name="progress_bar_margin">-11dip</dimen>
<dimen name="tab_thumbnail_width">@dimen/qc_thumb_width</dimen>
<dimen name="tab_thumbnail_height">@dimen/qc_thumb_height</dimen>
</resources>
......@@ -67,7 +67,8 @@
<dimen name="menu_width">240dip</dimen>
<dimen name="menu_height">32dip</dimen>
<dimen name="toolbar_height">52dip</dimen>
<dimen name="tab_capture_size">160dp</dimen>
<dimen name="tab_thumbnail_width">@dimen/nav_tab_width</dimen>
<dimen name="tab_thumbnail_height">@dimen/nav_tab_height</dimen>
<dimen name="nav_tab_width">240dip</dimen>
<dimen name="nav_tab_height">160dip</dimen>
<dimen name="nav_tab_text_normal">18sp</dimen>
......
......@@ -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();
......
......@@ -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
......
......@@ -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();
}
}
......@@ -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
......
......@@ -276,4 +276,9 @@ public class PhoneUi extends BaseUi {
}
}
@Override
public boolean shouldCaptureThumbnails() {
return true;
}
}
......@@ -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());
......
......@@ -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());
......
......@@ -276,4 +276,9 @@ public class PreloadController implements WebViewController {
if (LOGD_ENABLED) Log.d(LOGTAG, "hideAutoLogin()");
}
@Override
public boolean shouldCaptureThumbnails() {
return false;
}
}
......@@ -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
}
}
......@@ -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();
}
}
}
};
}
......@@ -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;
}
......
......@@ -147,4 +147,6 @@ public interface UI {
void setUseQuickControls(boolean enabled);
public boolean shouldCaptureThumbnails();
}
......@@ -122,4 +122,6 @@ public interface WebViewController {
void showAutoLogin(Tab tab);
void hideAutoLogin(Tab tab);
boolean shouldCaptureThumbnails();
}
......@@ -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;
}
}
......@@ -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);
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment