summaryrefslogtreecommitdiffstats
path: root/core/java/android/webkit
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/webkit')
-rw-r--r--core/java/android/webkit/CallbackProxy.java34
-rw-r--r--core/java/android/webkit/CookieManager.java2
-rw-r--r--core/java/android/webkit/WebChromeClient.java15
-rw-r--r--core/java/android/webkit/WebSettings.java22
-rw-r--r--core/java/android/webkit/WebStorage.java248
-rw-r--r--core/java/android/webkit/WebView.java67
-rw-r--r--core/java/android/webkit/WebViewCore.java19
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;