1/* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package com.android.browser; 17 18import android.content.ContentResolver; 19import android.content.ContentUris; 20import android.content.ContentValues; 21import android.content.Context; 22import android.database.Cursor; 23import android.graphics.BitmapFactory; 24import android.net.Uri; 25import android.os.AsyncTask; 26import android.os.Bundle; 27import android.text.TextUtils; 28import android.util.Log; 29import android.webkit.WebView; 30import android.webkit.WebViewClassic; 31 32import com.android.browser.provider.SnapshotProvider.Snapshots; 33 34import java.io.ByteArrayInputStream; 35import java.io.FileNotFoundException; 36import java.io.InputStream; 37import java.util.Map; 38import java.util.zip.GZIPInputStream; 39 40 41public class SnapshotTab extends Tab { 42 43 private static final String LOGTAG = "SnapshotTab"; 44 45 private long mSnapshotId; 46 private LoadData mLoadTask; 47 private WebViewFactory mWebViewFactory; 48 private int mBackgroundColor; 49 private long mDateCreated; 50 private boolean mIsLive; 51 52 public SnapshotTab(WebViewController wvcontroller, long snapshotId) { 53 super(wvcontroller, null, null); 54 mSnapshotId = snapshotId; 55 mWebViewFactory = mWebViewController.getWebViewFactory(); 56 WebView web = mWebViewFactory.createWebView(false); 57 setWebView(web); 58 loadData(); 59 } 60 61 @Override 62 void putInForeground() { 63 if (getWebView() == null) { 64 WebView web = mWebViewFactory.createWebView(false); 65 if (mBackgroundColor != 0) { 66 web.setBackgroundColor(mBackgroundColor); 67 } 68 setWebView(web); 69 loadData(); 70 } 71 super.putInForeground(); 72 } 73 74 @Override 75 void putInBackground() { 76 if (getWebView() == null) return; 77 super.putInBackground(); 78 } 79 80 void loadData() { 81 if (mLoadTask == null) { 82 mLoadTask = new LoadData(this, mContext); 83 mLoadTask.execute(); 84 } 85 } 86 87 @Override 88 void addChildTab(Tab child) { 89 if (mIsLive) { 90 super.addChildTab(child); 91 } else { 92 throw new IllegalStateException("Snapshot tabs cannot have child tabs!"); 93 } 94 } 95 96 @Override 97 public boolean isSnapshot() { 98 return !mIsLive; 99 } 100 101 public long getSnapshotId() { 102 return mSnapshotId; 103 } 104 105 @Override 106 public ContentValues createSnapshotValues() { 107 if (mIsLive) { 108 return super.createSnapshotValues(); 109 } 110 return null; 111 } 112 113 @Override 114 public Bundle saveState() { 115 if (mIsLive) { 116 return super.saveState(); 117 } 118 return null; 119 } 120 121 public long getDateCreated() { 122 return mDateCreated; 123 } 124 125 @Override 126 public void loadUrl(String url, Map<String, String> headers) { 127 if (!mIsLive) { 128 mIsLive = true; 129 getWebViewClassic().clearViewState(); 130 } 131 super.loadUrl(url, headers); 132 } 133 134 @Override 135 public boolean canGoBack() { 136 return super.canGoBack() || mIsLive; 137 } 138 139 @Override 140 public boolean canGoForward() { 141 return mIsLive && super.canGoForward(); 142 } 143 144 @Override 145 public void goBack() { 146 if (super.canGoBack()) { 147 super.goBack(); 148 } else { 149 mIsLive = false; 150 getWebView().stopLoading(); 151 loadData(); 152 } 153 } 154 155 static class LoadData extends AsyncTask<Void, Void, Cursor> { 156 157 static final String[] PROJECTION = new String[] { 158 Snapshots._ID, // 0 159 Snapshots.URL, // 1 160 Snapshots.TITLE, // 2 161 Snapshots.FAVICON, // 3 162 Snapshots.VIEWSTATE, // 4 163 Snapshots.BACKGROUND, // 5 164 Snapshots.DATE_CREATED, // 6 165 Snapshots.VIEWSTATE_PATH, // 7 166 }; 167 static final int SNAPSHOT_ID = 0; 168 static final int SNAPSHOT_URL = 1; 169 static final int SNAPSHOT_TITLE = 2; 170 static final int SNAPSHOT_FAVICON = 3; 171 static final int SNAPSHOT_VIEWSTATE = 4; 172 static final int SNAPSHOT_BACKGROUND = 5; 173 static final int SNAPSHOT_DATE_CREATED = 6; 174 static final int SNAPSHOT_VIEWSTATE_PATH = 7; 175 176 private SnapshotTab mTab; 177 private ContentResolver mContentResolver; 178 private Context mContext; 179 180 public LoadData(SnapshotTab t, Context context) { 181 mTab = t; 182 mContentResolver = context.getContentResolver(); 183 mContext = context; 184 } 185 186 @Override 187 protected Cursor doInBackground(Void... params) { 188 long id = mTab.mSnapshotId; 189 Uri uri = ContentUris.withAppendedId(Snapshots.CONTENT_URI, id); 190 return mContentResolver.query(uri, PROJECTION, null, null, null); 191 } 192 193 private InputStream getInputStream(Cursor c) throws FileNotFoundException { 194 String path = c.getString(SNAPSHOT_VIEWSTATE_PATH); 195 if (!TextUtils.isEmpty(path)) { 196 return mContext.openFileInput(path); 197 } 198 byte[] data = c.getBlob(SNAPSHOT_VIEWSTATE); 199 ByteArrayInputStream bis = new ByteArrayInputStream(data); 200 return bis; 201 } 202 203 @Override 204 protected void onPostExecute(Cursor result) { 205 try { 206 if (result.moveToFirst()) { 207 mTab.mCurrentState.mTitle = result.getString(SNAPSHOT_TITLE); 208 mTab.mCurrentState.mUrl = result.getString(SNAPSHOT_URL); 209 byte[] favicon = result.getBlob(SNAPSHOT_FAVICON); 210 if (favicon != null) { 211 mTab.mCurrentState.mFavicon = BitmapFactory 212 .decodeByteArray(favicon, 0, favicon.length); 213 } 214 WebViewClassic web = mTab.getWebViewClassic(); 215 if (web != null) { 216 InputStream ins = getInputStream(result); 217 GZIPInputStream stream = new GZIPInputStream(ins); 218 web.loadViewState(stream); 219 } 220 mTab.mBackgroundColor = result.getInt(SNAPSHOT_BACKGROUND); 221 mTab.mDateCreated = result.getLong(SNAPSHOT_DATE_CREATED); 222 mTab.mWebViewController.onPageFinished(mTab); 223 } 224 } catch (Exception e) { 225 Log.w(LOGTAG, "Failed to load view state, closing tab", e); 226 mTab.mWebViewController.closeTab(mTab); 227 } finally { 228 if (result != null) { 229 result.close(); 230 } 231 mTab.mLoadTask = null; 232 } 233 } 234 235 } 236 237 @Override 238 protected void persistThumbnail() { 239 if (mIsLive) { 240 super.persistThumbnail(); 241 } 242 } 243} 244