Merge "Seperate interface and implementation of 4 WebView classes"

This commit is contained in:
Jonathan Dixon
2012-04-23 05:48:40 -07:00
committed by Android (Google) Code Review
17 changed files with 1302 additions and 879 deletions

View File

@@ -16,27 +16,20 @@
package android.webkit;
import android.net.ParseException;
import android.net.WebAddress;
import android.os.AsyncTask;
import android.util.Log;
/**
* Manages the cookies used by an application's {@link WebView} instances.
* Cookies are manipulated according to RFC2109.
*/
public class CookieManager {
private static CookieManager sRef;
private static final String LOGTAG = "webkit";
private int mPendingCookieOperations = 0;
private CookieManager() {
/**
* @hide Only for use by WebViewProvider implementations
*/
protected CookieManager() {
}
@Override
protected Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException("doesn't implement Cloneable");
}
@@ -46,14 +39,11 @@ public class CookieManager {
* before the application instantiates a {@link WebView} instance,
* {@link CookieSyncManager#createInstance(Context)} must be called
* first.
*
*
* @return The singleton CookieManager instance
*/
public static synchronized CookieManager getInstance() {
if (sRef == null) {
sRef = new CookieManager();
}
return sRef;
return WebViewFactory.getProvider().getCookieManager();
}
/**
@@ -63,7 +53,7 @@ public class CookieManager {
* cookies
*/
public synchronized void setAcceptCookie(boolean accept) {
nativeSetAcceptCookie(accept);
throw new MustOverrideException();
}
/**
@@ -72,39 +62,20 @@ public class CookieManager {
* @return True if {@link WebView} instances send and accept cookies
*/
public synchronized boolean acceptCookie() {
return nativeAcceptCookie();
throw new MustOverrideException();
}
/**
/**
* Sets a cookie for the given URL. Any existing cookie with the same host,
* path and name will be replaced with the new cookie. The cookie being set
* must not have expired and must not be a session cookie, otherwise it
* will be ignored.
* @param url The URL for which the cookie is set
* @param value The cookie as a string, using the format of the
* 'Set-Cookie' HTTP response header
* @param value The cookie as a string, using the format of the 'Set-Cookie'
* HTTP response header
*/
public void setCookie(String url, String value) {
setCookie(url, value, false);
}
/**
* See {@link setCookie(String, String)}
* @param url The URL for which the cookie is set
* @param value The value of the cookie, as a string, using the format of
* the 'Set-Cookie' HTTP response header
* @param privateBrowsing Whether to use the private browsing cookie jar
*/
void setCookie(String url, String value, boolean privateBrowsing) {
WebAddress uri;
try {
uri = new WebAddress(url);
} catch (ParseException ex) {
Log.e(LOGTAG, "Bad address: " + url);
return;
}
nativeSetCookie(uri.toString(), value, privateBrowsing);
throw new MustOverrideException();
}
/**
@@ -114,11 +85,11 @@ public class CookieManager {
* HTTP request header
*/
public String getCookie(String url) {
return getCookie(url, false);
throw new MustOverrideException();
}
/**
* See {@link getCookie(String)}
* See {@link #getCookie(String)}
* @param url The URL for which the cookies are requested
* @param privateBrowsing Whether to use the private browsing cookie jar
* @return value The cookies as a string, using the format of the 'Cookie'
@@ -126,15 +97,7 @@ public class CookieManager {
* @hide Used by Browser, no intention to publish.
*/
public String getCookie(String url, boolean privateBrowsing) {
WebAddress uri;
try {
uri = new WebAddress(url);
} catch (ParseException ex) {
Log.e(LOGTAG, "Bad address: " + url);
return null;
}
return nativeGetCookie(uri.toString(), privateBrowsing);
throw new MustOverrideException();
}
/**
@@ -146,32 +109,7 @@ public class CookieManager {
* @hide Used by RequestHandle, no intention to publish.
*/
public synchronized String getCookie(WebAddress uri) {
return nativeGetCookie(uri.toString(), false);
}
/**
* Waits for pending operations to completed.
*/
void waitForCookieOperationsToComplete() {
// Note that this function is applicable for both the java
// and native http stacks, and works correctly with either.
synchronized (this) {
while (mPendingCookieOperations > 0) {
try {
wait();
} catch (InterruptedException e) { }
}
}
}
private synchronized void signalCookieOperationsComplete() {
mPendingCookieOperations--;
assert mPendingCookieOperations > -1;
notify();
}
private synchronized void signalCookieOperationsStart() {
mPendingCookieOperations++;
throw new MustOverrideException();
}
/**
@@ -179,21 +117,14 @@ public class CookieManager {
* date.
*/
public void removeSessionCookie() {
signalCookieOperationsStart();
new AsyncTask<Void, Void, Void>() {
protected Void doInBackground(Void... none) {
nativeRemoveSessionCookie();
signalCookieOperationsComplete();
return null;
}
}.execute();
throw new MustOverrideException();
}
/**
* Removes all cookies.
*/
public void removeAllCookie() {
nativeRemoveAllCookie();
throw new MustOverrideException();
}
/**
@@ -201,32 +132,32 @@ public class CookieManager {
* @return True if there are stored cookies.
*/
public synchronized boolean hasCookies() {
return hasCookies(false);
throw new MustOverrideException();
}
/**
* See {@link hasCookies()}.
* See {@link #hasCookies()}.
* @param privateBrowsing Whether to use the private browsing cookie jar
* @hide Used by Browser, no intention to publish.
*/
public synchronized boolean hasCookies(boolean privateBrowsing) {
return nativeHasCookies(privateBrowsing);
throw new MustOverrideException();
}
/**
* Removes all expired cookies.
*/
public void removeExpiredCookie() {
nativeRemoveExpiredCookie();
throw new MustOverrideException();
}
/**
* Package level api, called from CookieSyncManager
*
* Flush all cookies managed by the Chrome HTTP stack to flash.
*
* @hide Package level api, called from CookieSyncManager
*/
void flushCookieStore() {
nativeFlushCookieStore();
protected void flushCookieStore() {
throw new MustOverrideException();
}
/**
@@ -236,7 +167,7 @@ public class CookieManager {
* file scheme URLs
*/
public static boolean allowFileSchemeCookies() {
return nativeAcceptFileSchemeCookies();
throw new MustOverrideException();
}
/**
@@ -250,19 +181,6 @@ public class CookieManager {
* {@link WebView} or CookieManager instance has been created.
*/
public static void setAcceptFileSchemeCookies(boolean accept) {
nativeSetAcceptFileSchemeCookies(accept);
throw new MustOverrideException();
}
// Native functions
private static native boolean nativeAcceptCookie();
private static native String nativeGetCookie(String url, boolean privateBrowsing);
private static native boolean nativeHasCookies(boolean privateBrowsing);
private static native void nativeRemoveAllCookie();
private static native void nativeRemoveExpiredCookie();
private static native void nativeRemoveSessionCookie();
private static native void nativeSetAcceptCookie(boolean accept);
private static native void nativeSetCookie(String url, String value, boolean privateBrowsing);
private static native void nativeFlushCookieStore();
private static native boolean nativeAcceptFileSchemeCookies();
private static native void nativeSetAcceptFileSchemeCookies(boolean accept);
}

View File

@@ -0,0 +1,198 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
import android.net.ParseException;
import android.net.WebAddress;
import android.os.AsyncTask;
import android.util.Log;
class CookieManagerClassic extends CookieManager {
private static CookieManagerClassic sRef;
private static final String LOGTAG = "webkit";
private int mPendingCookieOperations = 0;
private CookieManagerClassic() {
}
public static synchronized CookieManagerClassic getInstance() {
if (sRef == null) {
sRef = new CookieManagerClassic();
}
return sRef;
}
@Override
public synchronized void setAcceptCookie(boolean accept) {
nativeSetAcceptCookie(accept);
}
@Override
public synchronized boolean acceptCookie() {
return nativeAcceptCookie();
}
@Override
public void setCookie(String url, String value) {
setCookie(url, value, false);
}
/**
* See {@link #setCookie(String, String)}
* @param url The URL for which the cookie is set
* @param value The value of the cookie, as a string, using the format of
* the 'Set-Cookie' HTTP response header
* @param privateBrowsing Whether to use the private browsing cookie jar
*/
void setCookie(String url, String value, boolean privateBrowsing) {
WebAddress uri;
try {
uri = new WebAddress(url);
} catch (ParseException ex) {
Log.e(LOGTAG, "Bad address: " + url);
return;
}
nativeSetCookie(uri.toString(), value, privateBrowsing);
}
@Override
public String getCookie(String url) {
return getCookie(url, false);
}
@Override
public String getCookie(String url, boolean privateBrowsing) {
WebAddress uri;
try {
uri = new WebAddress(url);
} catch (ParseException ex) {
Log.e(LOGTAG, "Bad address: " + url);
return null;
}
return nativeGetCookie(uri.toString(), privateBrowsing);
}
@Override
public synchronized String getCookie(WebAddress uri) {
return nativeGetCookie(uri.toString(), false);
}
/**
* Waits for pending operations to completed.
*/
void waitForCookieOperationsToComplete() {
// Note that this function is applicable for both the java
// and native http stacks, and works correctly with either.
synchronized (this) {
while (mPendingCookieOperations > 0) {
try {
wait();
} catch (InterruptedException e) { }
}
}
}
private synchronized void signalCookieOperationsComplete() {
mPendingCookieOperations--;
assert mPendingCookieOperations > -1;
notify();
}
private synchronized void signalCookieOperationsStart() {
mPendingCookieOperations++;
}
@Override
public void removeSessionCookie() {
signalCookieOperationsStart();
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... none) {
nativeRemoveSessionCookie();
signalCookieOperationsComplete();
return null;
}
}.execute();
}
@Override
public void removeAllCookie() {
nativeRemoveAllCookie();
}
@Override
public synchronized boolean hasCookies() {
return hasCookies(false);
}
@Override
public synchronized boolean hasCookies(boolean privateBrowsing) {
return nativeHasCookies(privateBrowsing);
}
@Override
public void removeExpiredCookie() {
nativeRemoveExpiredCookie();
}
@Override
protected void flushCookieStore() {
nativeFlushCookieStore();
}
/**
* Gets whether the application's {@link WebView} instances send and accept
* cookies for file scheme URLs.
* @return True if {@link WebView} instances send and accept cookies for
* file scheme URLs
*/
public static boolean allowFileSchemeCookies() {
return nativeAcceptFileSchemeCookies();
}
/**
* Sets whether the application's {@link WebView} instances should send and
* accept cookies for file scheme URLs.
* Use of cookies with file scheme URLs is potentially insecure. Do not use
* this feature unless you can be sure that no unintentional sharing of
* cookie data can take place.
* <p>
* Note that calls to this method will have no effect if made after a
* {@link WebView} or CookieManager instance has been created.
*/
public static void setAcceptFileSchemeCookies(boolean accept) {
nativeSetAcceptFileSchemeCookies(accept);
}
// Native functions
private static native boolean nativeAcceptCookie();
private static native String nativeGetCookie(String url, boolean privateBrowsing);
private static native boolean nativeHasCookies(boolean privateBrowsing);
private static native void nativeRemoveAllCookie();
private static native void nativeRemoveExpiredCookie();
private static native void nativeRemoveSessionCookie();
private static native void nativeSetAcceptCookie(boolean accept);
private static native void nativeSetCookie(String url, String value, boolean privateBrowsing);
private static native void nativeFlushCookieStore();
private static native boolean nativeAcceptFileSchemeCookies();
private static native void nativeSetAcceptFileSchemeCookies(boolean accept);
}

View File

@@ -16,13 +16,7 @@
package android.webkit;
import android.os.Handler;
import android.os.Message;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
/**
* This class is used to manage permissions for the WebView's Geolocation
@@ -44,9 +38,6 @@ import java.util.Vector;
* The methods of this class can be used to modify and interrogate the stored
* Geolocation permissions at any time.
*/
// This class is the Java counterpart of the WebKit C++ GeolocationPermissions
// class. It simply marshals calls from the UI thread to the WebKit thread.
//
// Within WebKit, Geolocation permissions may be applied either temporarily
// (for the duration of the page) or permanently. This class deals only with
// permanent permissions.
@@ -68,144 +59,12 @@ public class GeolocationPermissions {
public void invoke(String origin, boolean allow, boolean retain);
};
// Global instance
private static GeolocationPermissions sInstance;
private Handler mHandler;
private Handler mUIHandler;
// A queue to store messages until the handler is ready.
private Vector<Message> mQueuedMessages;
// Message ids
static final int GET_ORIGINS = 0;
static final int GET_ALLOWED = 1;
static final int CLEAR = 2;
static final int ALLOW = 3;
static final int CLEAR_ALL = 4;
// Message ids on the UI thread
static final int RETURN_ORIGINS = 0;
static final int RETURN_ALLOWED = 1;
private static final String ORIGINS = "origins";
private static final String ORIGIN = "origin";
private static final String CALLBACK = "callback";
private static final String ALLOWED = "allowed";
/**
* Get the singleton instance of this class.
* @return The singleton {@link GeolocationPermissions} instance.
*/
public static GeolocationPermissions getInstance() {
if (sInstance == null) {
sInstance = new GeolocationPermissions();
}
return sInstance;
}
/**
* Creates the UI message handler. Must be called on the UI thread.
* @hide
*/
public void createUIHandler() {
if (mUIHandler == null) {
mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Runs on the UI thread.
switch (msg.what) {
case RETURN_ORIGINS: {
Map values = (Map) msg.obj;
Set<String> origins = (Set<String>) values.get(ORIGINS);
ValueCallback<Set<String> > callback = (ValueCallback<Set<String> >) values.get(CALLBACK);
callback.onReceiveValue(origins);
} break;
case RETURN_ALLOWED: {
Map values = (Map) msg.obj;
Boolean allowed = (Boolean) values.get(ALLOWED);
ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK);
callback.onReceiveValue(allowed);
} break;
}
}
};
}
}
/**
* Creates the message handler. Must be called on the WebKit thread.
* @hide
*/
public synchronized void createHandler() {
if (mHandler == null) {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Runs on the WebKit thread.
switch (msg.what) {
case GET_ORIGINS: {
Set origins = nativeGetOrigins();
ValueCallback callback = (ValueCallback) msg.obj;
Map values = new HashMap<String, Object>();
values.put(CALLBACK, callback);
values.put(ORIGINS, origins);
postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
} break;
case GET_ALLOWED: {
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
boolean allowed = nativeGetAllowed(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
retValues.put(ALLOWED, Boolean.valueOf(allowed));
postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
} break;
case CLEAR:
nativeClear((String) msg.obj);
break;
case ALLOW:
nativeAllow((String) msg.obj);
break;
case CLEAR_ALL:
nativeClearAll();
break;
}
}
};
// Handle the queued messages
if (mQueuedMessages != null) {
while (!mQueuedMessages.isEmpty()) {
mHandler.sendMessage(mQueuedMessages.remove(0));
}
mQueuedMessages = null;
}
}
}
/**
* Utility function to send a message to our handler.
*/
private synchronized void postMessage(Message msg) {
if (mHandler == null) {
if (mQueuedMessages == null) {
mQueuedMessages = new Vector<Message>();
}
mQueuedMessages.add(msg);
} else {
mHandler.sendMessage(msg);
}
}
/**
* Utility function to send a message to the handler on the UI thread
*/
private void postUIMessage(Message msg) {
if (mUIHandler != null) {
mUIHandler.sendMessage(msg);
}
return WebViewFactory.getProvider().getGeolocationPermissions();
}
/**
@@ -222,14 +81,7 @@ public class GeolocationPermissions {
// (Database, Geolocation etc) do so, it's safe to match up origins based
// on this string.
public void getOrigins(ValueCallback<Set<String> > callback) {
if (callback != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
Set origins = nativeGetOrigins();
callback.onReceiveValue(origins);
} else {
postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -243,54 +95,30 @@ public class GeolocationPermissions {
* Geolocation API.
*/
public void getAllowed(String origin, ValueCallback<Boolean> callback) {
if (callback == null) {
return;
}
if (origin == null) {
callback.onReceiveValue(null);
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
boolean allowed = nativeGetAllowed(origin);
callback.onReceiveValue(Boolean.valueOf(allowed));
} else {
Map values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
values.put(CALLBACK, callback);
postMessage(Message.obtain(null, GET_ALLOWED, values));
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
* Clear the Geolocation permission state for the specified origin.
* @param origin The origin for which Geolocation permissions are cleared.
*/
// This method may be called before the WebKit
// thread has intialized the message handler. Messages will be queued until
// this time.
public void clear(String origin) {
// Called on the UI thread.
postMessage(Message.obtain(null, CLEAR, origin));
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
* Allow the specified origin to use the Geolocation API.
* @param origin The origin for which Geolocation API use is allowed.
*/
// This method may be called before the WebKit
// thread has intialized the message handler. Messages will be queued until
// this time.
public void allow(String origin) {
// Called on the UI thread.
postMessage(Message.obtain(null, ALLOW, origin));
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
* Clear the Geolocation permission state for all origins.
*/
public void clearAll() {
// Called on the UI thread.
postMessage(Message.obtain(null, CLEAR_ALL));
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -299,14 +127,7 @@ public class GeolocationPermissions {
* Note this constructor was erroneously public and published in SDK levels prior to 16, but
* applications using it would receive a non-functional instance of this class (there was no
* way to call createHandler() and createUIHandler(), so it would not work).
* @hide
* @hide Only for use by WebViewProvider implementations
*/
public GeolocationPermissions() {}
// Native functions, run on the WebKit thread.
private static native Set nativeGetOrigins();
private static native boolean nativeGetAllowed(String origin);
private static native void nativeClear(String origin);
private static native void nativeAllow(String origin);
private static native void nativeClearAll();
}

View File

@@ -0,0 +1,234 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
import android.os.Handler;
import android.os.Message;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.Vector;
// This class is the Java counterpart of the WebKit C++ GeolocationPermissions
// class. It simply marshals calls from the UI thread to the WebKit thread.
final class GeolocationPermissionsClassic extends GeolocationPermissions {
private Handler mHandler;
private Handler mUIHandler;
// A queue to store messages until the handler is ready.
private Vector<Message> mQueuedMessages;
// Message ids
static final int GET_ORIGINS = 0;
static final int GET_ALLOWED = 1;
static final int CLEAR = 2;
static final int ALLOW = 3;
static final int CLEAR_ALL = 4;
// Message ids on the UI thread
static final int RETURN_ORIGINS = 0;
static final int RETURN_ALLOWED = 1;
private static final String ORIGINS = "origins";
private static final String ORIGIN = "origin";
private static final String CALLBACK = "callback";
private static final String ALLOWED = "allowed";
// Global instance
private static GeolocationPermissionsClassic sInstance;
public static GeolocationPermissionsClassic getInstance() {
if (sInstance == null) {
sInstance = new GeolocationPermissionsClassic();
}
return sInstance;
}
/**
* Creates the UI message handler. Must be called on the UI thread.
* @hide
*/
public void createUIHandler() {
if (mUIHandler == null) {
mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Runs on the UI thread.
switch (msg.what) {
case RETURN_ORIGINS: {
Map values = (Map) msg.obj;
Set<String> origins = (Set<String>) values.get(ORIGINS);
ValueCallback<Set<String> > callback = (ValueCallback<Set<String> >) values.get(CALLBACK);
callback.onReceiveValue(origins);
} break;
case RETURN_ALLOWED: {
Map values = (Map) msg.obj;
Boolean allowed = (Boolean) values.get(ALLOWED);
ValueCallback<Boolean> callback = (ValueCallback<Boolean>) values.get(CALLBACK);
callback.onReceiveValue(allowed);
} break;
}
}
};
}
}
/**
* Creates the message handler. Must be called on the WebKit thread.
* @hide
*/
public synchronized void createHandler() {
if (mHandler == null) {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Runs on the WebKit thread.
switch (msg.what) {
case GET_ORIGINS: {
Set origins = nativeGetOrigins();
ValueCallback callback = (ValueCallback) msg.obj;
Map values = new HashMap<String, Object>();
values.put(CALLBACK, callback);
values.put(ORIGINS, origins);
postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
} break;
case GET_ALLOWED: {
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
boolean allowed = nativeGetAllowed(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
retValues.put(ALLOWED, Boolean.valueOf(allowed));
postUIMessage(Message.obtain(null, RETURN_ALLOWED, retValues));
} break;
case CLEAR:
nativeClear((String) msg.obj);
break;
case ALLOW:
nativeAllow((String) msg.obj);
break;
case CLEAR_ALL:
nativeClearAll();
break;
}
}
};
// Handle the queued messages
if (mQueuedMessages != null) {
while (!mQueuedMessages.isEmpty()) {
mHandler.sendMessage(mQueuedMessages.remove(0));
}
mQueuedMessages = null;
}
}
}
/**
* Utility function to send a message to our handler.
*/
private synchronized void postMessage(Message msg) {
if (mHandler == null) {
if (mQueuedMessages == null) {
mQueuedMessages = new Vector<Message>();
}
mQueuedMessages.add(msg);
} else {
mHandler.sendMessage(msg);
}
}
/**
* Utility function to send a message to the handler on the UI thread
*/
private void postUIMessage(Message msg) {
if (mUIHandler != null) {
mUIHandler.sendMessage(msg);
}
}
// Note that we represent the origins as strings. These are created using
// WebCore::SecurityOrigin::toString(). As long as all 'HTML 5 modules'
// (Database, Geolocation etc) do so, it's safe to match up origins based
// on this string.
@Override
public void getOrigins(ValueCallback<Set<String> > callback) {
if (callback != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
Set origins = nativeGetOrigins();
callback.onReceiveValue(origins);
} else {
postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
}
}
@Override
public void getAllowed(String origin, ValueCallback<Boolean> callback) {
if (callback == null) {
return;
}
if (origin == null) {
callback.onReceiveValue(null);
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
boolean allowed = nativeGetAllowed(origin);
callback.onReceiveValue(Boolean.valueOf(allowed));
} else {
Map values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
values.put(CALLBACK, callback);
postMessage(Message.obtain(null, GET_ALLOWED, values));
}
}
// This method may be called before the WebKit
// thread has intialized the message handler. Messages will be queued until
// this time.
@Override
public void clear(String origin) {
// Called on the UI thread.
postMessage(Message.obtain(null, CLEAR, origin));
}
// This method may be called before the WebKit
// thread has intialized the message handler. Messages will be queued until
// this time.
@Override
public void allow(String origin) {
// Called on the UI thread.
postMessage(Message.obtain(null, ALLOW, origin));
}
@Override
public void clearAll() {
// Called on the UI thread.
postMessage(Message.obtain(null, CLEAR_ALL));
}
GeolocationPermissionsClassic() {}
// Native functions, run on the WebKit thread.
private static native Set nativeGetOrigins();
private static native boolean nativeGetAllowed(String origin);
private static native void nativeClear(String origin);
private static native void nativeAllow(String origin);
private static native void nativeClearAll();
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
// TODO: Remove MustOverrideException and make all methods throwing it abstract instead;
// needs API file update.
class MustOverrideException extends RuntimeException {
MustOverrideException() {
super("abstract function called: must be overriden!");
}
}

View File

@@ -17,16 +17,7 @@
package android.webkit;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.provider.Browser;
import android.util.Log;
import java.io.File;
import java.util.HashMap;
import java.util.Vector;
/**
* Functions for manipulating the icon database used by WebView.
@@ -36,149 +27,6 @@ import java.util.Vector;
* single object.
*/
public class WebIconDatabase {
private static final String LOGTAG = "WebIconDatabase";
// Global instance of a WebIconDatabase
private static WebIconDatabase sIconDatabase;
// EventHandler for handling messages before and after the WebCore thread is
// ready.
private final EventHandler mEventHandler = new EventHandler();
// Class to handle messages before WebCore is ready
private static class EventHandler extends Handler {
// Message ids
static final int OPEN = 0;
static final int CLOSE = 1;
static final int REMOVE_ALL = 2;
static final int REQUEST_ICON = 3;
static final int RETAIN_ICON = 4;
static final int RELEASE_ICON = 5;
static final int BULK_REQUEST_ICON = 6;
// Message for dispatching icon request results
private static final int ICON_RESULT = 10;
// Actual handler that runs in WebCore thread
private Handler mHandler;
// Vector of messages before the WebCore thread is ready
private Vector<Message> mMessages = new Vector<Message>();
// Class to handle a result dispatch
private class IconResult {
private final String mUrl;
private final Bitmap mIcon;
private final IconListener mListener;
IconResult(String url, Bitmap icon, IconListener l) {
mUrl = url;
mIcon = icon;
mListener = l;
}
void dispatch() {
mListener.onReceivedIcon(mUrl, mIcon);
}
}
@Override
public void handleMessage(Message msg) {
// Note: This is the message handler for the UI thread.
switch (msg.what) {
case ICON_RESULT:
((IconResult) msg.obj).dispatch();
break;
}
}
// Called by WebCore thread to create the actual handler
private synchronized void createHandler() {
if (mHandler == null) {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Note: This is the message handler for the WebCore
// thread.
switch (msg.what) {
case OPEN:
nativeOpen((String) msg.obj);
break;
case CLOSE:
nativeClose();
break;
case REMOVE_ALL:
nativeRemoveAllIcons();
break;
case REQUEST_ICON:
IconListener l = (IconListener) msg.obj;
String url = msg.getData().getString("url");
requestIconAndSendResult(url, l);
break;
case BULK_REQUEST_ICON:
bulkRequestIcons(msg);
break;
case RETAIN_ICON:
nativeRetainIconForPageUrl((String) msg.obj);
break;
case RELEASE_ICON:
nativeReleaseIconForPageUrl((String) msg.obj);
break;
}
}
};
// Transfer all pending messages
for (int size = mMessages.size(); size > 0; size--) {
mHandler.sendMessage(mMessages.remove(0));
}
mMessages = null;
}
}
private synchronized boolean hasHandler() {
return mHandler != null;
}
private synchronized void postMessage(Message msg) {
if (mMessages != null) {
mMessages.add(msg);
} else {
mHandler.sendMessage(msg);
}
}
private void bulkRequestIcons(Message msg) {
HashMap map = (HashMap) msg.obj;
IconListener listener = (IconListener) map.get("listener");
ContentResolver cr = (ContentResolver) map.get("contentResolver");
String where = (String) map.get("where");
Cursor c = null;
try {
c = cr.query(
Browser.BOOKMARKS_URI,
new String[] { Browser.BookmarkColumns.URL },
where, null, null);
if (c.moveToFirst()) {
do {
String url = c.getString(0);
requestIconAndSendResult(url, listener);
} while (c.moveToNext());
}
} catch (IllegalStateException e) {
Log.e(LOGTAG, "BulkRequestIcons", e);
} finally {
if (c != null) c.close();
}
}
private void requestIconAndSendResult(String url, IconListener listener) {
Bitmap icon = nativeIconForPageUrl(url);
if (icon != null) {
sendMessage(obtainMessage(ICON_RESULT,
new IconResult(url, icon, listener)));
}
}
}
/**
* Interface for receiving icons from the database.
*/
@@ -197,31 +45,21 @@ public class WebIconDatabase {
* @param path The directory path where the icon database will be stored.
*/
public void open(String path) {
if (path != null) {
// Make the directories and parents if they don't exist
File db = new File(path);
if (!db.exists()) {
db.mkdirs();
}
mEventHandler.postMessage(
Message.obtain(null, EventHandler.OPEN, db.getAbsolutePath()));
}
throw new MustOverrideException();
}
/**
* Close the shared instance of the icon database.
*/
public void close() {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.CLOSE));
throw new MustOverrideException();
}
/**
* Removes all the icons in the database.
*/
public void removeAllIcons() {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.REMOVE_ALL));
throw new MustOverrideException();
}
/**
@@ -231,36 +69,14 @@ public class WebIconDatabase {
* @param listener An implementation on IconListener to receive the result.
*/
public void requestIconForPageUrl(String url, IconListener listener) {
if (listener == null || url == null) {
return;
}
Message msg = Message.obtain(null, EventHandler.REQUEST_ICON, listener);
msg.getData().putString("url", url);
mEventHandler.postMessage(msg);
throw new MustOverrideException();
}
/** {@hide}
*/
public void bulkRequestIconForPageUrl(ContentResolver cr, String where,
IconListener listener) {
if (listener == null) {
return;
}
// Special case situation: we don't want to add this message to the
// queue if there is no handler because we may never have a real
// handler to service the messages and the cursor will never get
// closed.
if (mEventHandler.hasHandler()) {
// Don't use Bundle as it is parcelable.
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("contentResolver", cr);
map.put("where", where);
map.put("listener", listener);
Message msg =
Message.obtain(null, EventHandler.BULK_REQUEST_ICON, map);
mEventHandler.postMessage(msg);
}
throw new MustOverrideException();
}
/**
@@ -268,10 +84,7 @@ public class WebIconDatabase {
* @param url The page's url.
*/
public void retainIconForPageUrl(String url) {
if (url != null) {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.RETAIN_ICON, url));
}
throw new MustOverrideException();
}
/**
@@ -279,10 +92,7 @@ public class WebIconDatabase {
* @param url The page's url.
*/
public void releaseIconForPageUrl(String url) {
if (url != null) {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.RELEASE_ICON, url));
}
throw new MustOverrideException();
}
/**
@@ -293,30 +103,11 @@ public class WebIconDatabase {
*/
public static WebIconDatabase getInstance() {
// XXX: Must be created in the UI thread.
if (sIconDatabase == null) {
sIconDatabase = new WebIconDatabase();
}
return sIconDatabase;
return WebViewFactory.getProvider().getWebIconDatabase();
}
/**
* Create the internal handler and transfer all pending messages.
* XXX: Called by WebCore thread only!
* @hide Only for use by WebViewProvider implementations
*/
/*package*/ void createHandler() {
mEventHandler.createHandler();
}
/**
* Private constructor to avoid anyone else creating an instance.
*/
private WebIconDatabase() {}
// Native functions
private static native void nativeOpen(String path);
private static native void nativeClose();
private static native void nativeRemoveAllIcons();
private static native Bitmap nativeIconForPageUrl(String url);
private static native void nativeRetainIconForPageUrl(String url);
private static native void nativeReleaseIconForPageUrl(String url);
protected WebIconDatabase() {}
}

View File

@@ -0,0 +1,289 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.provider.Browser;
import android.util.Log;
import java.io.File;
import java.util.HashMap;
import java.util.Vector;
class WebIconDatabaseClassic extends WebIconDatabase {
private static final String LOGTAG = "WebIconDatabase";
// Global instance of a WebIconDatabase
private static WebIconDatabaseClassic sIconDatabase;
// EventHandler for handling messages before and after the WebCore thread is
// ready.
private final EventHandler mEventHandler = new EventHandler();
// Class to handle messages before WebCore is ready
private static class EventHandler extends Handler {
// Message ids
static final int OPEN = 0;
static final int CLOSE = 1;
static final int REMOVE_ALL = 2;
static final int REQUEST_ICON = 3;
static final int RETAIN_ICON = 4;
static final int RELEASE_ICON = 5;
static final int BULK_REQUEST_ICON = 6;
// Message for dispatching icon request results
private static final int ICON_RESULT = 10;
// Actual handler that runs in WebCore thread
private Handler mHandler;
// Vector of messages before the WebCore thread is ready
private Vector<Message> mMessages = new Vector<Message>();
// Class to handle a result dispatch
private class IconResult {
private final String mUrl;
private final Bitmap mIcon;
private final IconListener mListener;
IconResult(String url, Bitmap icon, IconListener l) {
mUrl = url;
mIcon = icon;
mListener = l;
}
void dispatch() {
mListener.onReceivedIcon(mUrl, mIcon);
}
}
@Override
public void handleMessage(Message msg) {
// Note: This is the message handler for the UI thread.
switch (msg.what) {
case ICON_RESULT:
((IconResult) msg.obj).dispatch();
break;
}
}
// Called by WebCore thread to create the actual handler
private synchronized void createHandler() {
if (mHandler == null) {
mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// Note: This is the message handler for the WebCore
// thread.
switch (msg.what) {
case OPEN:
nativeOpen((String) msg.obj);
break;
case CLOSE:
nativeClose();
break;
case REMOVE_ALL:
nativeRemoveAllIcons();
break;
case REQUEST_ICON:
IconListener l = (IconListener) msg.obj;
String url = msg.getData().getString("url");
requestIconAndSendResult(url, l);
break;
case BULK_REQUEST_ICON:
bulkRequestIcons(msg);
break;
case RETAIN_ICON:
nativeRetainIconForPageUrl((String) msg.obj);
break;
case RELEASE_ICON:
nativeReleaseIconForPageUrl((String) msg.obj);
break;
}
}
};
// Transfer all pending messages
for (int size = mMessages.size(); size > 0; size--) {
mHandler.sendMessage(mMessages.remove(0));
}
mMessages = null;
}
}
private synchronized boolean hasHandler() {
return mHandler != null;
}
private synchronized void postMessage(Message msg) {
if (mMessages != null) {
mMessages.add(msg);
} else {
mHandler.sendMessage(msg);
}
}
private void bulkRequestIcons(Message msg) {
HashMap map = (HashMap) msg.obj;
IconListener listener = (IconListener) map.get("listener");
ContentResolver cr = (ContentResolver) map.get("contentResolver");
String where = (String) map.get("where");
Cursor c = null;
try {
c = cr.query(
Browser.BOOKMARKS_URI,
new String[] { Browser.BookmarkColumns.URL },
where, null, null);
if (c.moveToFirst()) {
do {
String url = c.getString(0);
requestIconAndSendResult(url, listener);
} while (c.moveToNext());
}
} catch (IllegalStateException e) {
Log.e(LOGTAG, "BulkRequestIcons", e);
} finally {
if (c != null) c.close();
}
}
private void requestIconAndSendResult(String url, IconListener listener) {
Bitmap icon = nativeIconForPageUrl(url);
if (icon != null) {
sendMessage(obtainMessage(ICON_RESULT,
new IconResult(url, icon, listener)));
}
}
}
@Override
public void open(String path) {
if (path != null) {
// Make the directories and parents if they don't exist
File db = new File(path);
if (!db.exists()) {
db.mkdirs();
}
mEventHandler.postMessage(
Message.obtain(null, EventHandler.OPEN, db.getAbsolutePath()));
}
}
@Override
public void close() {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.CLOSE));
}
@Override
public void removeAllIcons() {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.REMOVE_ALL));
}
/**
* Request the Bitmap representing the icon for the given page
* url. If the icon exists, the listener will be called with the result.
* @param url The page's url.
* @param listener An implementation on IconListener to receive the result.
*/
public void requestIconForPageUrl(String url, IconListener listener) {
if (listener == null || url == null) {
return;
}
Message msg = Message.obtain(null, EventHandler.REQUEST_ICON, listener);
msg.getData().putString("url", url);
mEventHandler.postMessage(msg);
}
/** {@hide}
*/
public void bulkRequestIconForPageUrl(ContentResolver cr, String where,
IconListener listener) {
if (listener == null) {
return;
}
// Special case situation: we don't want to add this message to the
// queue if there is no handler because we may never have a real
// handler to service the messages and the cursor will never get
// closed.
if (mEventHandler.hasHandler()) {
// Don't use Bundle as it is parcelable.
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("contentResolver", cr);
map.put("where", where);
map.put("listener", listener);
Message msg =
Message.obtain(null, EventHandler.BULK_REQUEST_ICON, map);
mEventHandler.postMessage(msg);
}
}
@Override
public void retainIconForPageUrl(String url) {
if (url != null) {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.RETAIN_ICON, url));
}
}
@Override
public void releaseIconForPageUrl(String url) {
if (url != null) {
mEventHandler.postMessage(
Message.obtain(null, EventHandler.RELEASE_ICON, url));
}
}
/**
* Get the global instance of WebIconDatabase.
* @return A single instance of WebIconDatabase. It will be the same
* instance for the current process each time this method is
* called.
*/
public static WebIconDatabaseClassic getInstance() {
// XXX: Must be created in the UI thread.
if (sIconDatabase == null) {
sIconDatabase = new WebIconDatabaseClassic();
}
return sIconDatabase;
}
/**
* Create the internal handler and transfer all pending messages.
* XXX: Called by WebCore thread only!
*/
/*package*/ void createHandler() {
mEventHandler.createHandler();
}
/**
* Private constructor to avoid anyone else creating an instance.
*/
private WebIconDatabaseClassic() {}
// Native functions
private static native void nativeOpen(String path);
private static native void nativeClose();
private static native void nativeRemoveAllIcons();
private static native Bitmap nativeIconForPageUrl(String url);
private static native void nativeRetainIconForPageUrl(String url);
private static native void nativeReleaseIconForPageUrl(String url);
}

View File

@@ -27,18 +27,10 @@ import android.os.Build;
* been destroyed, any method call on WebSettings will throw an
* IllegalStateException.
*/
// This is (effectively) an abstract base class; concrete WebViewProviders must
// This is an abstract base class: concrete WebViewProviders must
// create a class derived from this, and return an instance of it in the
// WebViewProvider.getWebSettingsProvider() method implementation.
public abstract class WebSettings {
// TODO: Remove MustOverrideException and make all methods throwing it abstract instead;
// needs API file update.
private static class MustOverrideException extends RuntimeException {
MustOverrideException() {
super("abstract function called: must be overriden!");
}
}
/**
* Enum for controlling the layout of html.
* NORMAL means no rendering changes.

View File

@@ -16,13 +16,7 @@
package android.webkit;
import android.os.Handler;
import android.os.Message;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* This class is used to manage the JavaScript storage APIs provided by the
@@ -56,34 +50,6 @@ public class WebStorage {
public void updateQuota(long newQuota);
};
// Global instance of a WebStorage
private static WebStorage sWebStorage;
// 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;
static final int GET_ORIGINS = 4;
static final int GET_USAGE_ORIGIN = 5;
static final int GET_QUOTA_ORIGIN = 6;
// Message ids on the UI thread
static final int RETURN_ORIGINS = 0;
static final int RETURN_USAGE_ORIGIN = 1;
static final int RETURN_QUOTA_ORIGIN = 2;
private static final String ORIGINS = "origins";
private static final String ORIGIN = "origin";
private static final String CALLBACK = "callback";
private static final String USAGE = "usage";
private static final String QUOTA = "quota";
private Map <String, Origin> mOrigins;
private Handler mHandler = null;
private Handler mUIHandler = null;
/**
* This class encapsulates information about the amount of storage
* currently used by an origin for the JavaScript storage APIs.
@@ -94,18 +60,21 @@ public class WebStorage {
private long mQuota = 0;
private long mUsage = 0;
private Origin(String origin, long quota, long usage) {
/** @hide */
protected Origin(String origin, long quota, long usage) {
mOrigin = origin;
mQuota = quota;
mUsage = usage;
}
private Origin(String origin, long quota) {
/** @hide */
protected Origin(String origin, long quota) {
mOrigin = origin;
mQuota = quota;
}
private Origin(String origin) {
/** @hide */
protected Origin(String origin) {
mOrigin = origin;
}
@@ -142,114 +111,6 @@ public class WebStorage {
}
}
/**
* Message handler, UI side
* @hide
*/
public void createUIHandler() {
if (mUIHandler == null) {
mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case RETURN_ORIGINS: {
Map values = (Map) msg.obj;
Map origins = (Map) values.get(ORIGINS);
ValueCallback<Map> callback = (ValueCallback<Map>) values.get(CALLBACK);
callback.onReceiveValue(origins);
} break;
case RETURN_USAGE_ORIGIN: {
Map values = (Map) msg.obj;
ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
callback.onReceiveValue((Long)values.get(USAGE));
} break;
case RETURN_QUOTA_ORIGIN: {
Map values = (Map) msg.obj;
ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
callback.onReceiveValue((Long)values.get(QUOTA));
} break;
}
}
};
}
}
/**
* Message handler, WebCore side
* @hide
*/
public synchronized 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());
} break;
case DELETE_ORIGIN: {
Origin website = (Origin) msg.obj;
nativeDeleteOrigin(website.getOrigin());
} break;
case DELETE_ALL:
nativeDeleteAllData();
break;
case GET_ORIGINS: {
syncValues();
ValueCallback callback = (ValueCallback) msg.obj;
Map origins = new HashMap(mOrigins);
Map values = new HashMap<String, Object>();
values.put(CALLBACK, callback);
values.put(ORIGINS, origins);
postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
} break;
case GET_USAGE_ORIGIN: {
syncValues();
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
Origin website = mOrigins.get(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
if (website != null) {
long usage = website.getUsage();
retValues.put(USAGE, new Long(usage));
}
postUIMessage(Message.obtain(null, RETURN_USAGE_ORIGIN, retValues));
} break;
case GET_QUOTA_ORIGIN: {
syncValues();
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
Origin website = mOrigins.get(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
if (website != null) {
long quota = website.getQuota();
retValues.put(QUOTA, new Long(quota));
}
postUIMessage(Message.obtain(null, RETURN_QUOTA_ORIGIN, retValues));
} break;
case UPDATE:
syncValues();
break;
}
}
};
}
}
/*
* When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
* we need to get the values from WebCore, but we cannot block while doing so
@@ -270,26 +131,7 @@ public class WebStorage {
* representation of the origin to a {@link WebStorage.Origin} object.
*/
public void getOrigins(ValueCallback<Map> callback) {
if (callback != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
callback.onReceiveValue(mOrigins);
} else {
postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
}
}
/**
* Returns a list of origins having a database
* should only be called from WebViewCore.
*/
Collection<Origin> getOriginsSync() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
update();
return mOrigins.values();
}
return null;
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -300,23 +142,7 @@ public class WebStorage {
* a {@link ValueCallback}.
*/
public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
if (callback == null) {
return;
}
if (origin == null) {
callback.onReceiveValue(null);
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
Origin website = mOrigins.get(origin);
callback.onReceiveValue(new Long(website.getUsage()));
} else {
HashMap values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
values.put(CALLBACK, callback);
postMessage(Message.obtain(null, GET_USAGE_ORIGIN, values));
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -327,23 +153,7 @@ public class WebStorage {
* enforced on a per-origin basis for the Application Cache API.
*/
public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
if (callback == null) {
return;
}
if (origin == null) {
callback.onReceiveValue(null);
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
Origin website = mOrigins.get(origin);
callback.onReceiveValue(new Long(website.getUsage()));
} else {
HashMap values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
values.put(CALLBACK, callback);
postMessage(Message.obtain(null, GET_QUOTA_ORIGIN, values));
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -353,14 +163,7 @@ public class WebStorage {
* for the Application Cache API.
*/
public void setQuotaForOrigin(String origin, long quota) {
if (origin != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
nativeSetQuotaForOrigin(origin, quota);
} else {
postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
new Origin(origin, quota)));
}
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -369,14 +172,7 @@ public class WebStorage {
* its string representation.
*/
public void deleteOrigin(String origin) {
if (origin != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
nativeDeleteOrigin(origin);
} else {
postMessage(Message.obtain(null, DELETE_ORIGIN,
new Origin(origin)));
}
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -385,38 +181,7 @@ public class WebStorage {
* Storage APIs.
*/
public void deleteAllData() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
nativeDeleteAllData();
} else {
postMessage(Message.obtain(null, DELETE_ALL));
}
}
/**
* Sets the maximum size of the ApplicationCache.
* This should only ever be called on the WebKit thread.
* @hide
*/
public void setAppCacheMaximumSize(long size) {
nativeSetAppCacheMaximumSize(size);
}
/**
* Utility function to send a message to our handler
*/
private synchronized void postMessage(Message msg) {
if (mHandler != null) {
mHandler.sendMessage(msg);
}
}
/**
* Utility function to send a message to the handler on the UI thread
*/
private void postUIMessage(Message msg) {
if (mUIHandler != null) {
mUIHandler.sendMessage(msg);
}
// Must be a no-op for backward compatibility: see the hidden constructor for reason.
}
/**
@@ -424,37 +189,7 @@ public class WebStorage {
* @return The singleton {@link WebStorage} instance.
*/
public static WebStorage getInstance() {
if (sWebStorage == null) {
sWebStorage = new WebStorage();
}
return sWebStorage;
}
/**
* @hide
* Post a Sync request
*/
public void update() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
} else {
postMessage(Message.obtain(null, UPDATE));
}
}
/**
* Run on the WebCore thread
* set the local values with the current ones
*/
private void syncValues() {
Set<String> tmp = nativeGetOrigins();
mOrigins = new HashMap<String, Origin>();
for (String origin : tmp) {
Origin website = new Origin(origin,
nativeGetQuotaForOrigin(origin),
nativeGetUsageForOrigin(origin));
mOrigins.put(origin, website);
}
return WebViewFactory.getProvider().getWebStorage();
}
/**
@@ -466,13 +201,4 @@ public class WebStorage {
* @hide
*/
public WebStorage() {}
// Native functions
private static native Set 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 nativeDeleteAllData();
private static native void nativeSetAppCacheMaximumSize(long size);
}

View File

@@ -0,0 +1,352 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
import android.os.Handler;
import android.os.Message;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/** @hide */
public class WebStorageClassic extends WebStorage {
// Global instance of a WebStorage
private static WebStorageClassic sWebStorage;
// 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;
static final int GET_ORIGINS = 4;
static final int GET_USAGE_ORIGIN = 5;
static final int GET_QUOTA_ORIGIN = 6;
// Message ids on the UI thread
static final int RETURN_ORIGINS = 0;
static final int RETURN_USAGE_ORIGIN = 1;
static final int RETURN_QUOTA_ORIGIN = 2;
private static final String ORIGINS = "origins";
private static final String ORIGIN = "origin";
private static final String CALLBACK = "callback";
private static final String USAGE = "usage";
private static final String QUOTA = "quota";
private Map <String, Origin> mOrigins;
private Handler mHandler = null;
private Handler mUIHandler = null;
/**
* @hide
* Message handler, UI side
* @hide
*/
public void createUIHandler() {
if (mUIHandler == null) {
mUIHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case RETURN_ORIGINS: {
Map values = (Map) msg.obj;
Map origins = (Map) values.get(ORIGINS);
ValueCallback<Map> callback = (ValueCallback<Map>) values.get(CALLBACK);
callback.onReceiveValue(origins);
} break;
case RETURN_USAGE_ORIGIN: {
Map values = (Map) msg.obj;
ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
callback.onReceiveValue((Long)values.get(USAGE));
} break;
case RETURN_QUOTA_ORIGIN: {
Map values = (Map) msg.obj;
ValueCallback<Long> callback = (ValueCallback<Long>) values.get(CALLBACK);
callback.onReceiveValue((Long)values.get(QUOTA));
} break;
}
}
};
}
}
/**
* Message handler, WebCore side
* @hide
*/
public synchronized 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());
} break;
case DELETE_ORIGIN: {
Origin website = (Origin) msg.obj;
nativeDeleteOrigin(website.getOrigin());
} break;
case DELETE_ALL:
nativeDeleteAllData();
break;
case GET_ORIGINS: {
syncValues();
ValueCallback callback = (ValueCallback) msg.obj;
Map origins = new HashMap(mOrigins);
Map values = new HashMap<String, Object>();
values.put(CALLBACK, callback);
values.put(ORIGINS, origins);
postUIMessage(Message.obtain(null, RETURN_ORIGINS, values));
} break;
case GET_USAGE_ORIGIN: {
syncValues();
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
Origin website = mOrigins.get(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
if (website != null) {
long usage = website.getUsage();
retValues.put(USAGE, new Long(usage));
}
postUIMessage(Message.obtain(null, RETURN_USAGE_ORIGIN, retValues));
} break;
case GET_QUOTA_ORIGIN: {
syncValues();
Map values = (Map) msg.obj;
String origin = (String) values.get(ORIGIN);
ValueCallback callback = (ValueCallback) values.get(CALLBACK);
Origin website = mOrigins.get(origin);
Map retValues = new HashMap<String, Object>();
retValues.put(CALLBACK, callback);
if (website != null) {
long quota = website.getQuota();
retValues.put(QUOTA, new Long(quota));
}
postUIMessage(Message.obtain(null, RETURN_QUOTA_ORIGIN, retValues));
} break;
case UPDATE:
syncValues();
break;
}
}
};
}
}
/*
* When calling getOrigins(), getUsageForOrigin() and getQuotaForOrigin(),
* we need to get the values from WebCore, but we cannot block while doing so
* as we used to do, as this could result in a full deadlock (other WebCore
* messages received while we are still blocked here, see http://b/2127737).
*
* We have to do everything asynchronously, by providing a callback function.
* We post a message on the WebCore thread (mHandler) that will get the result
* from WebCore, and we post it back on the UI thread (using mUIHandler).
* We can then use the callback function to return the value.
*/
@Override
public void getOrigins(ValueCallback<Map> callback) {
if (callback != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
callback.onReceiveValue(mOrigins);
} else {
postMessage(Message.obtain(null, GET_ORIGINS, callback));
}
}
}
/**
* Returns a list of origins having a database
* should only be called from WebViewCore.
*/
Collection<Origin> getOriginsSync() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
update();
return mOrigins.values();
}
return null;
}
@Override
public void getUsageForOrigin(String origin, ValueCallback<Long> callback) {
if (callback == null) {
return;
}
if (origin == null) {
callback.onReceiveValue(null);
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
Origin website = mOrigins.get(origin);
callback.onReceiveValue(new Long(website.getUsage()));
} else {
HashMap values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
values.put(CALLBACK, callback);
postMessage(Message.obtain(null, GET_USAGE_ORIGIN, values));
}
}
@Override
public void getQuotaForOrigin(String origin, ValueCallback<Long> callback) {
if (callback == null) {
return;
}
if (origin == null) {
callback.onReceiveValue(null);
return;
}
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
Origin website = mOrigins.get(origin);
callback.onReceiveValue(new Long(website.getUsage()));
} else {
HashMap values = new HashMap<String, Object>();
values.put(ORIGIN, origin);
values.put(CALLBACK, callback);
postMessage(Message.obtain(null, GET_QUOTA_ORIGIN, values));
}
}
@Override
public void setQuotaForOrigin(String origin, long quota) {
if (origin != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
nativeSetQuotaForOrigin(origin, quota);
} else {
postMessage(Message.obtain(null, SET_QUOTA_ORIGIN,
new Origin(origin, quota)));
}
}
}
@Override
public void deleteOrigin(String origin) {
if (origin != null) {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
nativeDeleteOrigin(origin);
} else {
postMessage(Message.obtain(null, DELETE_ORIGIN,
new Origin(origin)));
}
}
}
@Override
public void deleteAllData() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
nativeDeleteAllData();
} else {
postMessage(Message.obtain(null, DELETE_ALL));
}
}
/**
* Sets the maximum size of the ApplicationCache.
* This should only ever be called on the WebKit thread.
* Not part of the base-class API: this is only used by dump render tree.
*/
public void setAppCacheMaximumSize(long size) {
nativeSetAppCacheMaximumSize(size);
}
/**
* Utility function to send a message to our handler
*/
private synchronized void postMessage(Message msg) {
if (mHandler != null) {
mHandler.sendMessage(msg);
}
}
/**
* Utility function to send a message to the handler on the UI thread
*/
private void postUIMessage(Message msg) {
if (mUIHandler != null) {
mUIHandler.sendMessage(msg);
}
}
/**
* Get the singleton instance of this class.
* @return The singleton {@link WebStorage} instance.
*/
public static WebStorageClassic getInstance() {
if (sWebStorage == null) {
sWebStorage = new WebStorageClassic();
}
return sWebStorage;
}
/**
* @hide
* Post a Sync request
*/
public void update() {
if (WebViewCore.THREAD_NAME.equals(Thread.currentThread().getName())) {
syncValues();
} else {
postMessage(Message.obtain(null, UPDATE));
}
}
/**
* Run on the WebCore thread
* set the local values with the current ones
*/
private void syncValues() {
Set<String> tmp = nativeGetOrigins();
mOrigins = new HashMap<String, Origin>();
for (String origin : tmp) {
Origin website = new Origin(origin,
nativeGetQuotaForOrigin(origin),
nativeGetUsageForOrigin(origin));
mOrigins.put(origin, website);
}
}
WebStorageClassic() {}
// Native functions
private static native Set 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 nativeDeleteAllData();
private static native void nativeSetAppCacheMaximumSize(long size);
}

View File

@@ -268,12 +268,7 @@ public class WebView extends AbsoluteLayout
implements ViewTreeObserver.OnGlobalFocusChangeListener,
ViewGroup.OnHierarchyChangeListener {
// Default Provider factory class name.
private static final String DEFAULT_WEB_VIEW_FACTORY = "android.webkit.WebViewClassic$Factory";
private static final String LOGTAG = "webview_proxy";
// TODO: flip DEBUG to always be disabled.
private static final boolean DEBUG = true;
/**
* Transportation object for returning WebView across thread boundaries.
@@ -1702,16 +1697,11 @@ public class WebView extends AbsoluteLayout
// Private internal stuff
//-------------------------------------------------------------------------
// Cache the factory both for efficiency, and ensure any one process gets all webviews from the
// same provider.
private static WebViewFactoryProvider sProviderFactory;
private WebViewProvider mProvider;
private void ensureProviderCreated() {
checkThread();
if (mProvider == null) {
if (DEBUG) Log.v(LOGTAG, "instantiating webview provider instance");
// As this can get called during the base class constructor chain, pass the minimum
// number of dependencies here; the rest are deferred to init().
mProvider = getFactory().createWebView(this, new PrivateAccess());
@@ -1722,30 +1712,7 @@ public class WebView extends AbsoluteLayout
// For now the main purpose of this function (and the factory abstration) is to keep
// us honest and minimize usage of WebViewClassic internals when binding the proxy.
checkThread();
if (sProviderFactory != null) return sProviderFactory;
sProviderFactory = getFactoryByName(DEFAULT_WEB_VIEW_FACTORY);
if (sProviderFactory == null) {
if (DEBUG) Log.v (LOGTAG, "Falling back to explicit linkage");
sProviderFactory = new WebViewClassic.Factory();
}
return sProviderFactory;
}
private static WebViewFactoryProvider getFactoryByName(String providerName) {
try {
if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName);
Class<?> c = Class.forName(providerName);
if (DEBUG) Log.v(LOGTAG, "instantiating factory");
return (WebViewFactoryProvider) c.newInstance();
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (IllegalAccessException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (InstantiationException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
}
return null;
return WebViewFactory.getProvider();
}
private static void checkThread() {

View File

@@ -1458,14 +1458,6 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
// WebViewProvider bindings
static class Factory implements WebViewFactoryProvider, WebViewFactoryProvider.Statics {
@Override
public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) {
return new WebViewClassic(webView, privateAccess);
}
@Override
public Statics getStatics() { return this; }
@Override
public String findAddress(String addr) {
return WebViewClassic.findAddress(addr);
@@ -1479,6 +1471,33 @@ public final class WebViewClassic implements WebViewProvider, WebViewProvider.Sc
}
}
@Override
public Statics getStatics() { return this; }
@Override
public WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess) {
return new WebViewClassic(webView, privateAccess);
}
@Override
public GeolocationPermissions getGeolocationPermissions() {
return GeolocationPermissionsClassic.getInstance();
}
@Override
public CookieManager getCookieManager() {
return CookieManagerClassic.getInstance();
}
@Override
public WebIconDatabase getWebIconDatabase() {
return WebIconDatabaseClassic.getInstance();
}
@Override
public WebStorage getWebStorage() {
return WebStorageClassic.getInstance();
}
}
private void onHandleUiEvent(MotionEvent event, int eventType, int flags) {

View File

@@ -189,10 +189,10 @@ public 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 and the UI handler
WebStorage.getInstance().createUIHandler();
// Create the WebStorageClassic singleton and the UI handler
WebStorageClassic.getInstance().createUIHandler();
// Create the UI handler for GeolocationPermissions
GeolocationPermissions.getInstance().createUIHandler();
GeolocationPermissionsClassic.getInstance().createUIHandler();
// Get the memory class of the current device. V8 will use these values
// to GC more effectively.
@@ -227,11 +227,11 @@ public final class WebViewCore {
// Sync the native settings and also create the WebCore thread handler.
mSettings.syncSettingsAndCreateHandler(mBrowserFrame);
// Create the handler and transfer messages for the IconDatabase
WebIconDatabase.getInstance().createHandler();
// Create the handler for WebStorage
WebStorage.getInstance().createHandler();
WebIconDatabaseClassic.getInstance().createHandler();
// Create the handler for WebStorageClassic
WebStorageClassic.getInstance().createHandler();
// Create the handler for GeolocationPermissions.
GeolocationPermissions.getInstance().createHandler();
GeolocationPermissionsClassic.getInstance().createHandler();
// The transferMessages call will transfer all pending messages to the
// WebCore thread handler.
mEventHub.transferMessages();
@@ -1308,20 +1308,20 @@ public final class WebViewCore {
break;
case LOAD_URL: {
CookieManager.getInstance().waitForCookieOperationsToComplete();
CookieManagerClassic.getInstance().waitForCookieOperationsToComplete();
GetUrlData param = (GetUrlData) msg.obj;
loadUrl(param.mUrl, param.mExtraHeaders);
break;
}
case POST_URL: {
CookieManager.getInstance().waitForCookieOperationsToComplete();
CookieManagerClassic.getInstance().waitForCookieOperationsToComplete();
PostUrlData param = (PostUrlData) msg.obj;
mBrowserFrame.postUrl(param.mUrl, param.mPostData);
break;
}
case LOAD_DATA:
CookieManager.getInstance().waitForCookieOperationsToComplete();
CookieManagerClassic.getInstance().waitForCookieOperationsToComplete();
BaseUrlData loadParams = (BaseUrlData) msg.obj;
String baseUrl = loadParams.mBaseUrl;
if (baseUrl != null) {
@@ -2129,7 +2129,7 @@ public final class WebViewCore {
// Utility method for exceededDatabaseQuota and reachedMaxAppCacheSize
// callbacks. Computes the sum of database quota for all origins.
private long getUsedQuota() {
WebStorage webStorage = WebStorage.getInstance();
WebStorageClassic webStorage = WebStorageClassic.getInstance();
Collection<WebStorage.Origin> origins = webStorage.getOriginsSync();
if (origins == null) {

View File

@@ -0,0 +1,64 @@
/*
* Copyright (C) 2012 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.webkit;
import android.util.Log;
/**
* Top level factory, used creating all the main WebView implementation classes.
*/
class WebViewFactory {
// Default Provider factory class name.
private static final String DEFAULT_WEB_VIEW_FACTORY = "android.webkit.WebViewClassic$Factory";
private static final String LOGTAG = "WebViewFactory";
private static final boolean DEBUG = false;
// Cache the factory both for efficiency, and ensure any one process gets all webviews from the
// same provider.
private static WebViewFactoryProvider sProviderInstance;
static synchronized WebViewFactoryProvider getProvider() {
// For now the main purpose of this function (and the factory abstraction) is to keep
// us honest and minimize usage of WebViewClassic internals when binding the proxy.
if (sProviderInstance != null) return sProviderInstance;
sProviderInstance = getFactoryByName(DEFAULT_WEB_VIEW_FACTORY);
if (sProviderInstance == null) {
if (DEBUG) Log.v(LOGTAG, "Falling back to explicit linkage");
sProviderInstance = new WebViewClassic.Factory();
}
return sProviderInstance;
}
private static WebViewFactoryProvider getFactoryByName(String providerName) {
try {
if (DEBUG) Log.v(LOGTAG, "attempt to load class " + providerName);
Class<?> c = Class.forName(providerName);
if (DEBUG) Log.v(LOGTAG, "instantiating factory");
return (WebViewFactoryProvider) c.newInstance();
} catch (ClassNotFoundException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (IllegalAccessException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
} catch (InstantiationException e) {
Log.e(LOGTAG, "error loading " + providerName, e);
}
return null;
}
}

View File

@@ -23,18 +23,6 @@ package android.webkit;
* @hide
*/
public interface WebViewFactoryProvider {
/**
* Construct a new WebView provider.
* @param webView the WebView instance bound to this implementation instance. Note it will not
* necessarily be fully constructed at the point of this call: defer real initialization to
* WebViewProvider.init().
* @param privateAccess provides access into WebView internal methods.
*/
WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess);
Statics getStatics();
/**
* This Interface provides glue for implementing the backend of WebView static methods which
* cannot be implemented in-situ in the proxy class.
@@ -53,4 +41,43 @@ public interface WebViewFactoryProvider {
*/
void setPlatformNotificationsEnabled(boolean enable);
}
Statics getStatics();
/**
* Construct a new WebViewProvider.
* @param webView the WebView instance bound to this implementation instance. Note it will not
* necessarily be fully constructed at the point of this call: defer real initialization to
* WebViewProvider.init().
* @param privateAccess provides access into WebView internal methods.
*/
WebViewProvider createWebView(WebView webView, WebView.PrivateAccess privateAccess);
/**
* Gets the singleton GeolocationPermissions instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
* @return the single GeolocationPermissions instance.
*/
GeolocationPermissions getGeolocationPermissions();
/**
* Gets the singleton CookieManager instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
* @return the singleton CookieManager instance.
*/
CookieManager getCookieManager();
/**
* Gets the singleton WebIconDatabase instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
* @return the singleton WebIconDatabase instance.
*/
WebIconDatabase getWebIconDatabase();
/**
* Gets the singleton WebStorage instance for this WebView implementation. The
* implementation must return the same instance on subsequent calls.
* @return the singleton WebStorage instance.
*/
WebStorage getWebStorage();
}

View File

@@ -487,7 +487,7 @@ public class CallbackProxy extends Handler implements EventSender, LayoutTestCon
}
public void setAppCacheMaximumSize(long size) {
WebStorage.getInstance().setAppCacheMaximumSize(size);
android.webkit.WebStorageClassic.getInstance().setAppCacheMaximumSize(size);
}
public void setCanOpenWindows() {

View File

@@ -66,7 +66,7 @@ public class LayoutTestController {
public void setAppCacheMaximumSize(long size) {
Log.i(LOG_TAG, "setAppCacheMaximumSize() called with: " + size);
WebStorage.getInstance().setAppCacheMaximumSize(size);
android.webkit.WebStorageClassic.getInstance().setAppCacheMaximumSize(size);
}
public void setCanOpenWindows() {