summaryrefslogtreecommitdiffstats
path: root/android_webview
diff options
context:
space:
mode:
authorkristianm@chromium.org <kristianm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-14 14:58:58 +0000
committerkristianm@chromium.org <kristianm@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-02-14 14:58:58 +0000
commit3a879683c4422affac21bb8cb4cfb7b3004730f0 (patch)
treeb77bfbdff457644164de7df117f91635b8e09b82 /android_webview
parentc37a3c686abacfe30528c3cdf65d772220392f56 (diff)
downloadchromium_src-3a879683c4422affac21bb8cb4cfb7b3004730f0.zip
chromium_src-3a879683c4422affac21bb8cb4cfb7b3004730f0.tar.gz
chromium_src-3a879683c4422affac21bb8cb4cfb7b3004730f0.tar.bz2
Implementing geolocation for the Android Webview
Enabling geolocation callbacks BUG= Review URL: https://chromiumcodereview.appspot.com/12211047 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@182465 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'android_webview')
-rw-r--r--android_webview/browser/aw_content_browser_client.cc24
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwContents.java62
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwGeolocationPermissions.java84
-rw-r--r--android_webview/java/src/org/chromium/android_webview/AwSettings.java21
-rw-r--r--android_webview/native/aw_contents.cc90
-rw-r--r--android_webview/native/aw_contents.h21
-rw-r--r--android_webview/native/aw_geolocation_permission_context.cc35
-rw-r--r--android_webview/native/aw_geolocation_permission_context.h8
8 files changed, 260 insertions, 85 deletions
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc
index 4662e74..bc4918b 100644
--- a/android_webview/browser/aw_content_browser_client.cc
+++ b/android_webview/browser/aw_content_browser_client.cc
@@ -24,20 +24,25 @@
namespace {
-class DummyAccessTokenStore : public content::AccessTokenStore {
+class AwAccessTokenStore : public content::AccessTokenStore {
public:
- DummyAccessTokenStore() { }
+ AwAccessTokenStore() { }
+ // content::AccessTokenStore implementation
virtual void LoadAccessTokens(
- const LoadAccessTokensCallbackType& request) OVERRIDE { }
+ const LoadAccessTokensCallbackType& request) OVERRIDE {
+ AccessTokenStore::AccessTokenSet access_token_set;
+ // AccessTokenSet and net::URLRequestContextGetter not used on Android,
+ // but Run needs to be called to finish the geolocation setup.
+ request.Run(access_token_set, NULL);
+ }
+ virtual void SaveAccessToken(const GURL& server_url,
+ const string16& access_token) OVERRIDE { }
private:
- virtual ~DummyAccessTokenStore() { }
-
- virtual void SaveAccessToken(
- const GURL& server_url, const string16& access_token) OVERRIDE { }
+ virtual ~AwAccessTokenStore() { }
- DISALLOW_COPY_AND_ASSIGN(DummyAccessTokenStore);
+ DISALLOW_COPY_AND_ASSIGN(AwAccessTokenStore);
};
}
@@ -326,8 +331,7 @@ net::NetLog* AwContentBrowserClient::GetNetLog() {
}
content::AccessTokenStore* AwContentBrowserClient::CreateAccessTokenStore() {
- // TODO(boliu): Implement as part of geolocation code.
- return new DummyAccessTokenStore();
+ return new AwAccessTokenStore();
}
bool AwContentBrowserClient::IsFastShutdownPossible() {
diff --git a/android_webview/java/src/org/chromium/android_webview/AwContents.java b/android_webview/java/src/org/chromium/android_webview/AwContents.java
index e0ada40..51c7a14 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwContents.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwContents.java
@@ -862,33 +862,52 @@ public class AwContents {
mContentsClient.onReceivedHttpAuthRequest(handler, host, realm);
}
- private static class ChromiumGeolocationCallback implements GeolocationPermissions.Callback {
- final int mRenderProcessId;
- final int mRenderViewId;
- final int mBridgeId;
- final String mRequestingFrame;
-
- private ChromiumGeolocationCallback(int renderProcessId, int renderViewId, int bridgeId,
- String requestingFrame) {
- mRenderProcessId = renderProcessId;
- mRenderViewId = renderViewId;
- mBridgeId = bridgeId;
- mRequestingFrame = requestingFrame;
+ private class AwGeolocationCallback implements GeolocationPermissions.Callback {
+ private final AwGeolocationPermissions mGeolocationPermissions;
+
+ private AwGeolocationCallback(AwGeolocationPermissions geolocationPermissions) {
+ mGeolocationPermissions = geolocationPermissions;
}
@Override
- public void invoke(String origin, boolean allow, boolean retain) {
- // TODO(kristianm): Implement callback handling
+ public void invoke(final String origin, final boolean allow, final boolean retain) {
+ ThreadUtils.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if (retain) {
+ if (allow) {
+ mGeolocationPermissions.allow(origin);
+ } else {
+ mGeolocationPermissions.deny(origin);
+ }
+ }
+ nativeInvokeGeolocationCallback(mNativeAwContents, allow, origin);
+ }
+ });
}
}
@CalledByNative
- private void onGeolocationPermissionsShowPrompt(int renderProcessId, int renderViewId,
- int bridgeId, String requestingFrame) {
- // TODO(kristianm): Check with GeolocationPermissions if origin already has a policy set
- mContentsClient.onGeolocationPermissionsShowPrompt(GURLUtils.getOrigin(requestingFrame),
- new ChromiumGeolocationCallback(renderProcessId, renderViewId, bridgeId,
- requestingFrame));
+ private void onGeolocationPermissionsShowPrompt(String origin) {
+ AwGeolocationPermissions permissions = AwGeolocationPermissions.getInstance();
+ // Reject if geoloaction is disabled, or the origin has a retained deny
+ if (!mSettings.getGeolocationEnabled()) {
+ nativeInvokeGeolocationCallback(mNativeAwContents, false, origin);
+ return;
+ }
+ // Allow if the origin has a retained allow
+ if (permissions.hasOrigin(origin)) {
+ nativeInvokeGeolocationCallback(mNativeAwContents, permissions.isOriginAllowed(origin),
+ origin);
+ return;
+ }
+ mContentsClient.onGeolocationPermissionsShowPrompt(
+ origin, new AwGeolocationCallback(permissions));
+ }
+
+ @CalledByNative
+ private void onGeolocationPermissionsHidePrompt() {
+ mContentsClient.onGeolocationPermissionsHidePrompt();
}
@CalledByNative
@@ -1084,4 +1103,7 @@ public class AwContents {
private native Picture nativeCapturePicture(int nativeAwContents);
private native void nativeEnableOnNewPicture(int nativeAwContents, boolean enabled,
boolean invalidationOnly);
+
+ private native void nativeInvokeGeolocationCallback(
+ int nativeAwContents, boolean value, String requestingFrame);
}
diff --git a/android_webview/java/src/org/chromium/android_webview/AwGeolocationPermissions.java b/android_webview/java/src/org/chromium/android_webview/AwGeolocationPermissions.java
index 133f597..229bf20 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwGeolocationPermissions.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwGeolocationPermissions.java
@@ -24,10 +24,51 @@ public final class AwGeolocationPermissions {
AwGeolocationPermissions.class.getCanonicalName() + "%";
private final SharedPreferences mSharedPreferences;
+ private static AwGeolocationPermissions sInstance;
+
+ // TODO(kristianm): Rewrite when AwBrowserContext has landed in
+ // CL: https://codereview.chromium.org/12208099/
public AwGeolocationPermissions(SharedPreferences sharedPreferences) {
mSharedPreferences = sharedPreferences;
+ setInstance(this);
+ }
+
+ private static void setInstance(AwGeolocationPermissions instance) {
+ synchronized (AwGeolocationPermissions.class) {
+ sInstance = instance;
+ }
+ }
+
+ /**
+ * Get the static instance after it has been created
+ */
+ public static AwGeolocationPermissions getInstance() {
+ synchronized (AwGeolocationPermissions.class) {
+ if (sInstance == null) {
+ throw new IllegalStateException("This should only be called after createInstance.");
+ }
+ }
+ return sInstance;
+ }
+
+ /**
+ * Create the static instance of this class
+ */
+ public static AwGeolocationPermissions createInstance(
+ SharedPreferences sharedPreferences) {
+ synchronized (AwGeolocationPermissions.class) {
+ if (sInstance != null) {
+ throw new IllegalStateException("This should only be called once.");
+ }
+ // sInstance set in the constructor
+ new AwGeolocationPermissions(sharedPreferences);
+ return sInstance;
+ }
}
+ /**
+ * Set one origin to be allowed.
+ */
public void allow(String origin) {
String key = getOriginKey(origin);
if (key != null) {
@@ -35,6 +76,9 @@ public final class AwGeolocationPermissions {
}
}
+ /**
+ * Set one origin to be denied.
+ */
public void deny(String origin) {
String key = getOriginKey(origin);
if (key != null) {
@@ -42,6 +86,9 @@ public final class AwGeolocationPermissions {
}
}
+ /**
+ * Clear the stored permission for a particular origin.
+ */
public void clear(String origin) {
String key = getOriginKey(origin);
if (key != null) {
@@ -49,6 +96,9 @@ public final class AwGeolocationPermissions {
}
}
+ /**
+ * Clear stored permissions for all origins.
+ */
public void clearAll() {
SharedPreferences.Editor editor = null;
for (String name : mSharedPreferences.getAll().keySet()) {
@@ -64,17 +114,25 @@ public final class AwGeolocationPermissions {
}
}
+ /**
+ * Synchronous method to get if an origin is set to be allowed.
+ */
+ public boolean isOriginAllowed(String origin) {
+ return mSharedPreferences.getBoolean(getOriginKey(origin), false);
+ }
+
+ /**
+ * Returns true if the origin is either set to allowed or denied.
+ */
+ public boolean hasOrigin(String origin) {
+ return mSharedPreferences.contains(getOriginKey(origin));
+ }
+
+ /**
+ * Asynchronous method to get if an origin set to be allowed.
+ */
public void getAllowed(String origin, final ValueCallback<Boolean> callback) {
- boolean allowed = false;
- try {
- String key = getOriginKey(origin);
- if (key != null) {
- allowed = mSharedPreferences.getBoolean(key, false);
- }
- } catch (ClassCastException e) {
- // Want to return false in this case, do nothing here
- }
- final boolean finalAllowed = allowed;
+ final boolean finalAllowed = isOriginAllowed(origin);
ThreadUtils.postOnUiThread(new Runnable() {
@Override
public void run() {
@@ -83,6 +141,9 @@ public final class AwGeolocationPermissions {
});
}
+ /**
+ * Async method to get the domains currently allowed or denied.
+ */
public void getOrigins(final ValueCallback<Set<String>> callback) {
final Set<String> origins = new HashSet<String>();
for (String name : mSharedPreferences.getAll().keySet()) {
@@ -98,6 +159,9 @@ public final class AwGeolocationPermissions {
});
}
+ /**
+ * Get the domain of an URL using the GURL library.
+ */
private String getOriginKey(String url) {
String origin = GURLUtils.getOrigin(url);
if (origin.isEmpty()) {
diff --git a/android_webview/java/src/org/chromium/android_webview/AwSettings.java b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
index cb91126..65b0c34 100644
--- a/android_webview/java/src/org/chromium/android_webview/AwSettings.java
+++ b/android_webview/java/src/org/chromium/android_webview/AwSettings.java
@@ -26,6 +26,7 @@ public class AwSettings {
private boolean mAllowFileUrlAccess = true;
private int mCacheMode = WebSettings.LOAD_DEFAULT;
private boolean mShouldFocusFirstNode = true;
+ private boolean mGeolocationEnabled = true;
public AwSettings(Context context) {
mContext = context;
@@ -137,4 +138,24 @@ public class AwSettings {
return mShouldFocusFirstNode;
}
}
+
+ /**
+ * See {@link android.webkit.WebSettings#setGeolocationEnabled}.
+ */
+ public void setGeolocationEnabled(boolean flag) {
+ synchronized (mAwSettingsLock) {
+ if (mGeolocationEnabled != flag) {
+ mGeolocationEnabled = flag;
+ }
+ }
+ }
+
+ /**
+ * @return Returns if geolocation is currently enabled.
+ */
+ boolean getGeolocationEnabled() {
+ synchronized (mAwSettingsLock) {
+ return mGeolocationEnabled;
+ }
+ }
}
diff --git a/android_webview/native/aw_contents.cc b/android_webview/native/aw_contents.cc
index 1fd2ec1..60f1f69 100644
--- a/android_webview/native/aw_contents.cc
+++ b/android_webview/native/aw_contents.cc
@@ -727,20 +727,88 @@ bool RegisterAwContents(JNIEnv* env) {
return RegisterNativesImpl(env) >= 0;
}
-void AwContents::OnGeolocationShowPrompt(int render_process_id,
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame) {
+namespace {
+
+void ShowGeolocationPromptHelperTask(const JavaObjectWeakGlobalRef& java_ref,
+ const GURL& origin) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> j_ref = java_ref.get(env);
+ if (j_ref.obj()) {
+ ScopedJavaLocalRef<jstring> j_origin(
+ ConvertUTF8ToJavaString(env, origin.spec()));
+ Java_AwContents_onGeolocationPermissionsShowPrompt(env,
+ j_ref.obj(),
+ j_origin.obj());
+ }
+}
+
+void ShowGeolocationPromptHelper(const JavaObjectWeakGlobalRef& java_ref,
+ const GURL& origin) {
JNIEnv* env = AttachCurrentThread();
- ScopedJavaLocalRef<jstring> j_requesting_frame(
- ConvertUTF8ToJavaString(env, requesting_frame.spec()));
- Java_AwContents_onGeolocationPermissionsShowPrompt(env,
- java_ref_.get(env).obj(), render_process_id, render_view_id, bridge_id,
- j_requesting_frame.obj());
+ if (java_ref.get(env).obj()) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(&ShowGeolocationPromptHelperTask,
+ java_ref,
+ origin));
+ }
+}
+
+} // anonymous namespace
+
+void AwContents::ShowGeolocationPrompt(const GURL& requesting_frame,
+ base::Callback<void(bool)> callback) {
+ GURL origin = requesting_frame.GetOrigin();
+ bool show_prompt = pending_geolocation_prompts_.empty();
+ pending_geolocation_prompts_.push_back(OriginCallback(origin, callback));
+ if (show_prompt) {
+ ShowGeolocationPromptHelper(java_ref_, origin);
+ }
}
-void AwContents::OnGeolocationHidePrompt() {
- // TODO(kristianm): Implement this
+// Invoked from Java
+void AwContents::InvokeGeolocationCallback(JNIEnv* env,
+ jobject obj,
+ jboolean value,
+ jstring origin) {
+ GURL callback_origin(base::android::ConvertJavaStringToUTF16(env, origin));
+ if (callback_origin.GetOrigin() ==
+ pending_geolocation_prompts_.front().first) {
+ pending_geolocation_prompts_.front().second.Run(value);
+ pending_geolocation_prompts_.pop_front();
+ if (!pending_geolocation_prompts_.empty()) {
+ ShowGeolocationPromptHelper(java_ref_,
+ pending_geolocation_prompts_.front().first);
+ }
+ }
+}
+
+void AwContents::HideGeolocationPrompt(const GURL& origin) {
+ bool removed_current_outstanding_callback = false;
+ std::list<OriginCallback>::iterator it = pending_geolocation_prompts_.begin();
+ while (it != pending_geolocation_prompts_.end()) {
+ if ((*it).first == origin.GetOrigin()) {
+ if (it == pending_geolocation_prompts_.begin()) {
+ removed_current_outstanding_callback = true;
+ }
+ it = pending_geolocation_prompts_.erase(it);
+ } else {
+ ++it;
+ }
+ }
+
+ if (removed_current_outstanding_callback) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jobject> j_ref = java_ref_.get(env);
+ if (j_ref.obj()) {
+ Java_AwContents_onGeolocationPermissionsHidePrompt(env, j_ref.obj());
+ }
+ if (!pending_geolocation_prompts_.empty()) {
+ ShowGeolocationPromptHelper(java_ref_,
+ pending_geolocation_prompts_.front().first);
+ }
+ }
}
jint AwContents::FindAllSync(JNIEnv* env, jobject obj, jstring search_string) {
diff --git a/android_webview/native/aw_contents.h b/android_webview/native/aw_contents.h
index 31a921d..7313027 100644
--- a/android_webview/native/aw_contents.h
+++ b/android_webview/native/aw_contents.h
@@ -6,7 +6,9 @@
#define ANDROID_WEBVIEW_NATIVE_AW_CONTENTS_H_
#include <jni.h>
+#include <list>
#include <string>
+#include <utility>
#include "android_webview/browser/find_helper.h"
#include "android_webview/browser/icon_helper.h"
@@ -14,6 +16,7 @@
#include "android_webview/public/browser/draw_gl.h"
#include "base/android/scoped_java_ref.h"
#include "base/android/jni_helper.h"
+#include "base/callback_forward.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/android/compositor.h"
#include "content/public/browser/javascript_dialog_manager.h"
@@ -131,11 +134,12 @@ class AwContents : public FindHelper::Listener,
jboolean invalidation_only);
// Geolocation API support
- void OnGeolocationShowPrompt(int render_process_id,
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame);
- void OnGeolocationHidePrompt();
+ void ShowGeolocationPrompt(const GURL& origin, base::Callback<void(bool)>);
+ void HideGeolocationPrompt(const GURL& origin);
+ void InvokeGeolocationCallback(JNIEnv* env,
+ jobject obj,
+ jboolean value,
+ jstring origin);
// Find-in-page API and related methods.
jint FindAllSync(JNIEnv* env, jobject obj, jstring search_string);
@@ -187,6 +191,13 @@ class AwContents : public FindHelper::Listener,
scoped_ptr<IconHelper> icon_helper_;
scoped_ptr<content::WebContents> pending_contents_;
+ // GURL is supplied by the content layer as requesting frame.
+ // Callback is supplied by the content layer, and is invoked with the result
+ // from the permission prompt.
+ typedef std::pair<const GURL, base::Callback<void(bool)> > OriginCallback;
+ // The first element in the list is always the currently pending request.
+ std::list<OriginCallback> pending_geolocation_prompts_;
+
// Compositor-specific state.
scoped_ptr<content::Compositor> compositor_;
scoped_refptr<cc::Layer> scissor_clip_layer_;
diff --git a/android_webview/native/aw_geolocation_permission_context.cc b/android_webview/native/aw_geolocation_permission_context.cc
index 959c464..3b67862 100644
--- a/android_webview/native/aw_geolocation_permission_context.cc
+++ b/android_webview/native/aw_geolocation_permission_context.cc
@@ -10,7 +10,6 @@
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/web_contents.h"
-#include "googleurl/src/gurl.h"
namespace android_webview {
@@ -25,16 +24,14 @@ AwGeolocationPermissionContext::RequestGeolocationPermissionOnUIThread(
const GURL& requesting_frame,
base::Callback<void(bool)> callback) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- const content::RenderViewHost* host =
- content::RenderViewHost::FromID(render_process_id, render_view_id);
- content::WebContents* web_contents =
- content::WebContents::FromRenderViewHost(host);
- AwContents* aw_contents = AwContents::FromWebContents(web_contents);
- aw_contents->OnGeolocationShowPrompt(
- render_process_id,
- render_view_id,
- bridge_id,
- requesting_frame);
+
+ AwContents* aw_contents =
+ AwContents::FromID(render_process_id, render_view_id);
+ if (!aw_contents) {
+ callback.Run(false);
+ return;
+ }
+ aw_contents->ShowGeolocationPrompt(requesting_frame, callback);
}
void
@@ -70,7 +67,12 @@ AwGeolocationPermissionContext::CancelGeolocationPermissionRequestOnUIThread(
int bridge_id,
const GURL& requesting_frame) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- // TODO(kristianm): Implement this
+
+ AwContents* aw_contents =
+ AwContents::FromID(render_process_id, render_view_id);
+ if (aw_contents) {
+ aw_contents->HideGeolocationPrompt(requesting_frame);
+ }
}
void
@@ -91,13 +93,4 @@ AwGeolocationPermissionContext::CancelGeolocationPermissionRequest(
requesting_frame));
}
-void InvokeCallback(
- int render_process_id,
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame,
- bool value) {
- // TODO(kristianm): Implement this
-}
-
} // namespace android_webview
diff --git a/android_webview/native/aw_geolocation_permission_context.h b/android_webview/native/aw_geolocation_permission_context.h
index 3235c4d..9e1cf53 100644
--- a/android_webview/native/aw_geolocation_permission_context.h
+++ b/android_webview/native/aw_geolocation_permission_context.h
@@ -5,7 +5,6 @@
#ifndef ANDROID_WEBVIEW_NATIVE_AW_GEOLOCATION_PERMISSION_CONTEXT_H_
#define ANDROID_WEBVIEW_NATIVE_AW_GEOLOCATION_PERMISSION_CONTEXT_H_
-#include "base/callback_forward.h"
#include "content/public/browser/geolocation_permission_context.h"
class GURL;
@@ -30,13 +29,6 @@ class AwGeolocationPermissionContext :
int bridge_id,
const GURL& requesting_frame) OVERRIDE;
- void InvokeCallback(
- int render_process_id,
- int render_view_id,
- int bridge_id,
- const GURL& requesting_frame,
- bool value);
-
protected:
virtual ~AwGeolocationPermissionContext();