diff options
Diffstat (limited to 'core/java/android/webkit')
-rw-r--r-- | core/java/android/webkit/CallbackProxy.java | 34 | ||||
-rw-r--r-- | core/java/android/webkit/CookieManager.java | 2 | ||||
-rw-r--r-- | core/java/android/webkit/WebChromeClient.java | 15 | ||||
-rw-r--r-- | core/java/android/webkit/WebSettings.java | 22 | ||||
-rw-r--r-- | core/java/android/webkit/WebStorage.java | 248 | ||||
-rw-r--r-- | core/java/android/webkit/WebView.java | 67 | ||||
-rw-r--r-- | core/java/android/webkit/WebViewCore.java | 19 |
7 files changed, 394 insertions, 13 deletions
diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index be15ef8..667cb2c 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -99,6 +99,7 @@ class CallbackProxy extends Handler { private static final int RECEIVED_CERTIFICATE = 124; private static final int SWITCH_OUT_HISTORY = 125; private static final int EXCEEDED_DATABASE_QUOTA = 126; + private static final int JS_TIMEOUT = 127; // Message triggered by the client to resume execution private static final int NOTIFY = 200; @@ -548,6 +549,18 @@ class CallbackProxy extends Handler { } break; + case JS_TIMEOUT: + if(mWebChromeClient != null) { + final JsResult res = (JsResult) msg.obj; + if(mWebChromeClient.onJsTimeout()) { + res.confirm(); + } else { + res.cancel(); + } + res.setReady(); + } + break; + case RECEIVED_CERTIFICATE: mWebView.setCertificate((SslCertificate) msg.obj); break; @@ -1073,4 +1086,25 @@ class CallbackProxy extends Handler { sendMessage(exceededQuota); } + /** + * @hide pending API council approval + */ + public boolean onJsTimeout() { + //always interrupt timedout JS by default + if (mWebChromeClient == null) { + return true; + } + JsResult result = new JsResult(this, true); + Message timeout = obtainMessage(JS_TIMEOUT, result); + synchronized (this) { + sendMessage(timeout); + try { + wait(); + } catch (InterruptedException e) { + Log.e(LOGTAG, "Caught exception while waiting for jsUnload"); + Log.e(LOGTAG, Log.getStackTraceString(e)); + } + } + return result.getResult(); + } } diff --git a/core/java/android/webkit/CookieManager.java b/core/java/android/webkit/CookieManager.java index c0c6775..e8c2279 100644 --- a/core/java/android/webkit/CookieManager.java +++ b/core/java/android/webkit/CookieManager.java @@ -647,8 +647,6 @@ public final class CookieManager { // another file in the local web server directory. Still // "localhost" is the best pseudo domain name. ret[0] = "localhost"; - } else if (!ret[0].equals("localhost")) { - return null; } } else if (index == ret[0].lastIndexOf(PERIOD)) { // cookie host must have at least two periods diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 0b874fa..bd64f89 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -174,4 +174,19 @@ public class WebChromeClient { // WebCore will interpret this that new quota was declined. quotaUpdater.updateQuota(currentQuota); } + + /** + * Tell the client that a JavaScript execution timeout has occured. And the + * client may decide whether or not to interrupt the execution. If the + * client returns true, the JavaScript will be interrupted. If the client + * returns false, the execution will continue. Note that in the case of + * continuing execution, the timeout counter will be reset, and the callback + * will continue to occur if the script does not finish at the next check + * point. + * @return boolean Whether the JavaScript execution should be interrupted. + * @hide pending API Council approval + */ + public boolean onJsTimeout() { + return true; + } } diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java index 5a2cd26..883aa28 100644 --- a/core/java/android/webkit/WebSettings.java +++ b/core/java/android/webkit/WebSettings.java @@ -141,6 +141,7 @@ public class WebSettings { private boolean mBlockNetworkLoads; private boolean mJavaScriptEnabled = false; private boolean mPluginsEnabled = false; + private long mWebStorageDefaultQuota = 0; private boolean mJavaScriptCanOpenWindowsAutomatically = false; private boolean mUseDoubleTree = false; private boolean mUseWideViewport = false; @@ -903,6 +904,18 @@ public class WebSettings { } /** + * @hide + * Set the default quota for WebStorage DBs + * @param quota the default quota in bytes + */ + public synchronized void setWebStorageDefaultQuota(long quota) { + if (mWebStorageDefaultQuota != quota) { + mWebStorageDefaultQuota = quota; + postSync(); + } + } + + /** * Set the path to where database storage API databases should be saved. * This will update WebCore when the Sync runs in the C++ side. * @param databasePath String path to the directory where databases should @@ -996,6 +1009,15 @@ public class WebSettings { } /** + * @hide + * Return the default quota for WebStorage DBs + * @return the default quota in bytes + */ + public synchronized long getWebStorageDefaultQuota() { + return mWebStorageDefaultQuota; + } + + /** * Tell javascript to open windows automatically. This applies to the * javascript function window.open(). * @param flag True if javascript can open windows automatically. diff --git a/core/java/android/webkit/WebStorage.java b/core/java/android/webkit/WebStorage.java index a0faf76..f27360d 100644 --- a/core/java/android/webkit/WebStorage.java +++ b/core/java/android/webkit/WebStorage.java @@ -16,6 +16,16 @@ package android.webkit; +import android.os.Handler; +import android.os.Message; +import android.util.Log; + +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.HashMap; +import java.util.Vector; + /** * Functionality for manipulating the webstorage databases. */ @@ -32,4 +42,242 @@ public final class WebStorage { public interface QuotaUpdater { public void updateQuota(long newQuota); }; + + // Log tag + private static final String TAG = "webstorage"; + + // Global instance of a WebStorage + private static WebStorage sWebStorage; + + // We keep a copy of the origins, quotas and usages + // that we protect via a lock and update in syncValues() + private static Lock mLock = new ReentrantLock(); + private static Condition mCacheUpdated = mLock.newCondition(); + + // Message ids + static final int UPDATE = 0; + static final int SET_QUOTA_ORIGIN = 1; + static final int DELETE_ORIGIN = 2; + static final int DELETE_ALL = 3; + + private Vector <String> mOrigins; + private HashMap <String, Long> mQuotas = new HashMap<String, Long>(); + private HashMap <String, Long> mUsages = new HashMap<String, Long>(); + + private Handler mHandler = null; + + private class Origin { + String mOrigin = null; + long mQuota = 0; + + public Origin(String origin, long quota) { + mOrigin = origin; + mQuota = quota; + } + + public Origin(String origin) { + mOrigin = origin; + } + + public String getOrigin() { + return mOrigin; + } + + public long getQuota() { + return mQuota; + } + } + + /** + * @hide + * Message handler + */ + public void createHandler() { + if (mHandler == null) { + mHandler = new Handler() { + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case SET_QUOTA_ORIGIN: { + Origin website = (Origin) msg.obj; + nativeSetQuotaForOrigin(website.getOrigin(), + website.getQuota()); + syncValues(); + } break; + + case DELETE_ORIGIN: { + Origin website = (Origin) msg.obj; + nativeDeleteOrigin(website.getOrigin()); + syncValues(); + } break; + + case DELETE_ALL: + nativeDeleteAllDatabases(); + syncValues(); + break; + + case UPDATE: + syncValues(); + break; + } + } + }; + } + } + + /** + * @hide + * Returns a list of origins having a database + */ + public Vector getOrigins() { + Vector ret = null; + mLock.lock(); + try { + update(); + mCacheUpdated.await(); + ret = mOrigins; + } catch (InterruptedException e) { + Log.e(TAG, "Exception while waiting on the updated origins", e); + } finally { + mLock.unlock(); + } + return ret; + } + + /** + * @hide + * Returns the use for a given origin + */ + public long getUsageForOrigin(String origin) { + long ret = 0; + if (origin == null) { + return ret; + } + mLock.lock(); + try { + update(); + mCacheUpdated.await(); + Long usage = mUsages.get(origin); + if (usage != null) { + ret = usage.longValue(); + } + } catch (InterruptedException e) { + Log.e(TAG, "Exception while waiting on the updated origins", e); + } finally { + mLock.unlock(); + } + return ret; + } + + /** + * @hide + * Returns the quota for a given origin + */ + public long getQuotaForOrigin(String origin) { + long ret = 0; + if (origin == null) { + return ret; + } + mLock.lock(); + try { + update(); + mCacheUpdated.await(); + Long quota = mQuotas.get(origin); + if (quota != null) { + ret = quota.longValue(); + } + } catch (InterruptedException e) { + Log.e(TAG, "Exception while waiting on the updated origins", e); + } finally { + mLock.unlock(); + } + return ret; + } + + /** + * @hide + * Set the quota for a given origin + */ + public void setQuotaForOrigin(String origin, long quota) { + if (origin != null) { + postMessage(Message.obtain(null, SET_QUOTA_ORIGIN, + new Origin(origin, quota))); + } + } + + /** + * @hide + * Delete a given origin + */ + public void deleteOrigin(String origin) { + if (origin != null) { + postMessage(Message.obtain(null, DELETE_ORIGIN, + new Origin(origin))); + } + } + + /** + * @hide + * Delete all databases + */ + public void deleteAllDatabases() { + postMessage(Message.obtain(null, DELETE_ALL)); + } + + /** + * Utility function to send a message to our handler + */ + private void postMessage(Message msg) { + if (mHandler != null) { + mHandler.sendMessage(msg); + } + } + + /** + * @hide + * Get the global instance of WebStorage. + * @return A single instance of WebStorage. + */ + public static WebStorage getInstance() { + if (sWebStorage == null) { + sWebStorage = new WebStorage(); + } + return sWebStorage; + } + + /** + * @hide + * Post a Sync request + */ + public void update() { + postMessage(Message.obtain(null, UPDATE)); + } + + /** + * Run on the webcore thread + * sync the local cached values with the real ones + */ + private void syncValues() { + mLock.lock(); + Vector tmp = nativeGetOrigins(); + mOrigins = new Vector<String>(); + mQuotas.clear(); + mUsages.clear(); + for (int i = 0; i < tmp.size(); i++) { + String origin = (String) tmp.get(i); + mOrigins.add(origin); + mQuotas.put(origin, new Long(nativeGetQuotaForOrigin(origin))); + mUsages.put(origin, new Long(nativeGetUsageForOrigin(origin))); + } + mCacheUpdated.signal(); + mLock.unlock(); + } + + // Native functions + private static native Vector nativeGetOrigins(); + private static native long nativeGetUsageForOrigin(String origin); + private static native long nativeGetQuotaForOrigin(String origin); + private static native void nativeSetQuotaForOrigin(String origin, long quota); + private static native void nativeDeleteOrigin(String origin); + private static native void nativeDeleteAllDatabases(); } diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 935e928..5b67b74 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -21,6 +21,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.DialogInterface.OnCancelListener; +import android.database.DataSetObserver; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Color; @@ -60,6 +61,7 @@ import android.view.inputmethod.InputMethodManager; import android.webkit.TextDialog.AutoCompleteAdapter; import android.webkit.WebViewCore.EventHub; import android.widget.AbsoluteLayout; +import android.widget.Adapter; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.FrameLayout; @@ -4402,7 +4404,7 @@ public class WebView extends AbsoluteLayout View v = mTextEntry; int x = viewToContent((v.getLeft() + v.getRight()) >> 1); int y = viewToContent((v.getTop() + v.getBottom()) >> 1); - nativeMotionUp(x, y, mNavSlop, true); + nativeMotionUp(x, y, mNavSlop); } } @@ -4414,7 +4416,7 @@ public class WebView extends AbsoluteLayout // mLastTouchX and mLastTouchY are the point in the current viewport int contentX = viewToContent((int) mLastTouchX + mScrollX); int contentY = viewToContent((int) mLastTouchY + mScrollY); - if (nativeMotionUp(contentX, contentY, mNavSlop, true)) { + if (nativeMotionUp(contentX, contentY, mNavSlop)) { if (mLogEvent) { Checkin.updateStats(mContext.getContentResolver(), Checkin.Stats.Tag.BROWSER_SNAP_CENTER, 1, 0.0); @@ -4933,7 +4935,10 @@ public class WebView extends AbsoluteLayout @Override public boolean hasStableIds() { - return true; + // AdapterView's onChanged method uses this to determine whether + // to restore the old state. Return false so that the old (out + // of date) state does not replace the new, valid state. + return false; } private Container item(int position) { @@ -4997,6 +5002,51 @@ public class WebView extends AbsoluteLayout } } + /* + * Whenever the data set changes due to filtering, this class ensures + * that the checked item remains checked. + */ + private class SingleDataSetObserver extends DataSetObserver { + private long mCheckedId; + private ListView mListView; + private Adapter mAdapter; + + /* + * Create a new observer. + * @param id The ID of the item to keep checked. + * @param l ListView for getting and clearing the checked states + * @param a Adapter for getting the IDs + */ + public SingleDataSetObserver(long id, ListView l, Adapter a) { + mCheckedId = id; + mListView = l; + mAdapter = a; + } + + public void onChanged() { + // The filter may have changed which item is checked. Find the + // item that the ListView thinks is checked. + int position = mListView.getCheckedItemPosition(); + long id = mAdapter.getItemId(position); + if (mCheckedId != id) { + // Clear the ListView's idea of the checked item, since + // it is incorrect + mListView.clearChoices(); + // Search for mCheckedId. If it is in the filtered list, + // mark it as checked + int count = mAdapter.getCount(); + for (int i = 0; i < count; i++) { + if (mAdapter.getItemId(i) == mCheckedId) { + mListView.setItemChecked(i, true); + break; + } + } + } + } + + public void onInvalidate() {} + } + public void run() { final ListView listView = (ListView) LayoutInflater.from(mContext) .inflate(com.android.internal.R.layout.select_dialog, null); @@ -5030,8 +5080,7 @@ public class WebView extends AbsoluteLayout // filtered. Do not allow filtering on multiple lists until // that bug is fixed. - // Disable filter altogether - // listView.setTextFilterEnabled(!mMultiple); + listView.setTextFilterEnabled(!mMultiple); if (mMultiple) { listView.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE); int length = mSelectedArray.length; @@ -5051,6 +5100,9 @@ public class WebView extends AbsoluteLayout listView.setSelection(mSelection); listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE); listView.setItemChecked(mSelection, true); + DataSetObserver observer = new SingleDataSetObserver( + adapter.getItemId(mSelection), listView, adapter); + adapter.registerDataSetObserver(observer); } } dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { @@ -5120,13 +5172,12 @@ public class WebView extends AbsoluteLayout // called by JNI private void sendMotionUp(int touchGeneration, int buildGeneration, - int frame, int node, int x, int y, int size, boolean isClick, + int frame, int node, int x, int y, int size, boolean retry) { WebViewCore.TouchUpData touchUpData = new WebViewCore.TouchUpData(); touchUpData.mMoveGeneration = touchGeneration; touchUpData.mBuildGeneration = buildGeneration; touchUpData.mSize = size; - touchUpData.mIsClick = isClick; touchUpData.mRetry = retry; mFocusData.mFrame = touchUpData.mFrame = frame; mFocusData.mNode = touchUpData.mNode = node; @@ -5263,7 +5314,7 @@ public class WebView extends AbsoluteLayout private native void nativeInstrumentReport(); private native void nativeMarkNodeInvalid(int node); // return true if the page has been scrolled - private native boolean nativeMotionUp(int x, int y, int slop, boolean isClick); + private native boolean nativeMotionUp(int x, int y, int slop); // returns false if it handled the key private native boolean nativeMoveFocus(int keyCode, int count, boolean noScroll); diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index b364952..1c83264 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -143,6 +143,8 @@ final class WebViewCore { // The WebIconDatabase needs to be initialized within the UI thread so // just request the instance here. WebIconDatabase.getInstance(); + // Create the WebStorage singleton + WebStorage.getInstance(); // Send a message to initialize the WebViewCore. Message init = sWebCoreHandler.obtainMessage( WebCoreThread.INITIALIZE, this); @@ -162,6 +164,8 @@ final class WebViewCore { mSettings.syncSettingsAndCreateHandler(mBrowserFrame); // Create the handler and transfer messages for the IconDatabase WebIconDatabase.getInstance().createHandler(); + // Create the handler for WebStorage + WebStorage.getInstance().createHandler(); // The transferMessages call will transfer all pending messages to the // WebCore thread handler. mEventHub.transferMessages(); @@ -284,6 +288,16 @@ final class WebViewCore { return mCallbackProxy.onJsBeforeUnload(url, message); } + /** + * + * Callback to notify that a JavaScript execution timeout has occured. + * @return True if the JavaScript execution should be interrupted. False + * will continue the execution. + */ + protected boolean jsInterrupt() { + return mCallbackProxy.onJsTimeout(); + } + //------------------------------------------------------------------------- // JNI methods //------------------------------------------------------------------------- @@ -370,7 +384,7 @@ final class WebViewCore { private native void nativeTouchUp(int touchGeneration, int buildGeneration, int framePtr, int nodePtr, int x, int y, - int size, boolean isClick, boolean retry); + int size, boolean retry); private native boolean nativeHandleTouchEvent(int action, int x, int y); @@ -526,7 +540,6 @@ final class WebViewCore { int mX; int mY; int mSize; - boolean mIsClick; boolean mRetry; } @@ -892,7 +905,7 @@ final class WebViewCore { touchUpData.mBuildGeneration, touchUpData.mFrame, touchUpData.mNode, touchUpData.mX, touchUpData.mY, - touchUpData.mSize, touchUpData.mIsClick, + touchUpData.mSize, touchUpData.mRetry); break; |