Commit 29fb8fa2 authored by Clark DuVall's avatar Clark DuVall Committed by Commit Bot

[WebLayer] Implement Geolocation permission context in WebLayer

This change implements the delegate for the geolocation permission
context in WebLayer. In addition, it adds necessary functionality to
request Android permissions if necessary.

Still needs to be done:
- Remove FakePermissionManager which is currently being used in
  geolocation instrumentation tests.
- Make prefs persistent. Right now you have to re-allow geolocation
  permission on every restart.

Bug: 1025625, 1025609
Change-Id: I97dca79f0e1ecaa45bea1df89d126a9a244f368e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2110519
Commit-Queue: Clark DuVall <cduvall@chromium.org>
Reviewed-by: default avatarJohn Abd-El-Malek <jam@chromium.org>
Cr-Commit-Position: refs/heads/master@{#752482}
parent 9ba37d7c
......@@ -125,6 +125,8 @@ source_set("weblayer_lib_base") {
"browser/navigation_controller_impl.h",
"browser/navigation_impl.cc",
"browser/navigation_impl.h",
"browser/permissions/geolocation_permission_context_delegate.cc",
"browser/permissions/geolocation_permission_context_delegate.h",
"browser/permissions/permission_decision_auto_blocker_factory.cc",
"browser/permissions/permission_decision_auto_blocker_factory.h",
"browser/permissions/permission_manager_factory.cc",
......@@ -313,6 +315,8 @@ source_set("weblayer_lib_base") {
"browser/android/metrics/uma_utils.h",
"browser/android/metrics/weblayer_metrics_service_client.cc",
"browser/android/metrics/weblayer_metrics_service_client.h",
"browser/android/permission_request_utils.cc",
"browser/android/permission_request_utils.h",
"browser/android/resource_mapper.cc",
"browser/android/resource_mapper.h",
"browser/content_view_render_view.cc",
......@@ -356,6 +360,7 @@ source_set("weblayer_lib_base") {
"//components/embedder_support/android/metrics",
"//components/external_intents/android",
"//components/javascript_dialogs",
"//components/location/android:settings",
"//components/metrics",
"//components/minidump_uploader",
"//components/navigation_interception",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "weblayer/browser/android/permission_request_utils.h"
#include "base/android/jni_android.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/window_android.h"
#include "weblayer/browser/java/jni/PermissionRequestUtils_jni.h"
namespace weblayer {
void RequestAndroidPermission(content::WebContents* web_contents,
ContentSettingsType content_settings_type,
PermissionUpdatedCallback callback) {
if (!web_contents) {
std::move(callback).Run(false);
return;
}
auto* window = web_contents->GetTopLevelNativeWindow();
if (!window) {
std::move(callback).Run(false);
return;
}
// The callback allocated here will be deleted in the call to OnResult, which
// is guaranteed to be called.
Java_PermissionRequestUtils_requestPermission(
base::android::AttachCurrentThread(), window->GetJavaObject(),
reinterpret_cast<jlong>(
new PermissionUpdatedCallback(std::move(callback))),
static_cast<int>(content_settings_type));
}
void JNI_PermissionRequestUtils_OnResult(JNIEnv* env,
jlong callback_ptr,
jboolean result) {
auto* callback = reinterpret_cast<PermissionUpdatedCallback*>(callback_ptr);
std::move(*callback).Run(result);
delete callback;
}
} // namespace weblayer
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBLAYER_BROWSER_ANDROID_PERMISSION_REQUEST_UTILS_H_
#define WEBLAYER_BROWSER_ANDROID_PERMISSION_REQUEST_UTILS_H_
#include "base/callback_forward.h"
#include "components/content_settings/core/common/content_settings_types.h"
namespace content {
class WebContents;
}
namespace weblayer {
using PermissionUpdatedCallback = base::OnceCallback<void(bool)>;
// Requests all necessary Android permissions related to
// |content_settings_type|, and calls |callback|. |callback| will be called with
// true if all permissions were successfully granted, and false otherwise.
void RequestAndroidPermission(content::WebContents* web_contents,
ContentSettingsType content_settings_type,
PermissionUpdatedCallback callback);
} // namespace weblayer
#endif // WEBLAYER_BROWSER_ANDROID_PERMISSION_REQUEST_UTILS_H_
......@@ -30,6 +30,7 @@
#if defined(OS_ANDROID)
#include "base/android/path_utils.h"
#include "components/permissions/contexts/geolocation_permission_context_android.h"
#elif defined(OS_WIN)
#include <KnownFolders.h>
#include <shlobj.h>
......@@ -236,6 +237,10 @@ void BrowserContextImpl::RegisterPrefs(
StatefulSSLHostStateDelegate::RegisterProfilePrefs(pref_registry);
HostContentSettingsMap::RegisterProfilePrefs(pref_registry);
safe_browsing::RegisterProfilePrefs(pref_registry);
#if defined(OS_ANDROID)
permissions::GeolocationPermissionContextAndroid::RegisterProfilePrefs(
pref_registry);
#endif
}
class BrowserContextImpl::WebLayerVariationsClient
......
......@@ -60,6 +60,8 @@ class BrowserContextImpl : public content::BrowserContext {
ProfileImpl* profile_impl() const { return profile_impl_; }
PrefService* pref_service() const { return user_pref_service_.get(); }
private:
class WebLayerVariationsClient;
......
......@@ -70,6 +70,7 @@ android_library("java") {
"org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java",
"org/chromium/weblayer_private/metrics/MetricsServiceClient.java",
"org/chromium/weblayer_private/metrics/UmaUtils.java",
"org/chromium/weblayer_private/permissions/PermissionRequestUtils.java",
"org/chromium/weblayer_private/resources/ResourceMapper.java",
]
......@@ -94,6 +95,7 @@ android_library("java") {
"//components/external_intents/android:java",
"//components/find_in_page/android:java",
"//components/javascript_dialogs/android:java",
"//components/location/android:settings_java",
"//components/metrics:metrics_java",
"//components/minidump_uploader:minidump_uploader_java",
"//components/navigation_interception/android:navigation_interception_java",
......@@ -171,6 +173,7 @@ generate_jni("jni") {
"org/chromium/weblayer_private/WebViewCompatibilityHelperImpl.java",
"org/chromium/weblayer_private/metrics/MetricsServiceClient.java",
"org/chromium/weblayer_private/metrics/UmaUtils.java",
"org/chromium/weblayer_private/permissions/PermissionRequestUtils.java",
"org/chromium/weblayer_private/resources/ResourceMapper.java",
]
}
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package org.chromium.weblayer_private.permissions;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.base.annotations.NativeMethods;
import org.chromium.components.permissions.AndroidPermissionRequester;
import org.chromium.components.permissions.PermissionsClient;
import org.chromium.ui.base.WindowAndroid;
/** Util functions to request Android permissions for a content setting. */
@JNINamespace("weblayer")
public final class PermissionRequestUtils {
@CalledByNative
private static void requestPermission(
WindowAndroid windowAndroid, long nativeCallback, int contentSettingsType) {
if (!AndroidPermissionRequester.requestAndroidPermissions(windowAndroid,
new int[] {contentSettingsType},
new AndroidPermissionRequester.RequestDelegate() {
@Override
public void onAndroidPermissionAccepted() {
PermissionRequestUtilsJni.get().onResult(nativeCallback, true);
}
@Override
public void onAndroidPermissionCanceled() {
PermissionRequestUtilsJni.get().onResult(nativeCallback, false);
}
},
new PermissionsClient())) {
PermissionRequestUtilsJni.get().onResult(nativeCallback, false);
}
}
@NativeMethods
interface Natives {
void onResult(long callback, boolean result);
}
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "weblayer/browser/permissions/geolocation_permission_context_delegate.h"
#include "build/build_config.h"
#if defined(OS_ANDROID)
#include "components/content_settings/core/common/content_settings.h"
#include "components/permissions/permission_util.h"
#include "content/public/browser/web_contents.h"
#include "ui/android/window_android.h"
#include "weblayer/browser/android/permission_request_utils.h"
#include "weblayer/browser/browser_context_impl.h"
#include "weblayer/browser/tab_impl.h"
#endif
namespace weblayer {
bool GeolocationPermissionContextDelegate::DecidePermission(
content::WebContents* web_contents,
const permissions::PermissionRequestID& id,
const GURL& requesting_origin,
bool user_gesture,
permissions::BrowserPermissionCallback* callback,
permissions::GeolocationPermissionContext* context) {
return false;
}
void GeolocationPermissionContextDelegate::UpdateTabContext(
const permissions::PermissionRequestID& id,
const GURL& requesting_frame,
bool allowed) {}
#if defined(OS_ANDROID)
bool GeolocationPermissionContextDelegate::
ShouldRequestAndroidLocationPermission(content::WebContents* web_contents) {
if (!web_contents)
return false;
auto* window_android = web_contents->GetTopLevelNativeWindow();
if (!window_android)
return false;
std::vector<std::string> android_permissions;
permissions::PermissionUtil::GetAndroidPermissionsForContentSetting(
ContentSettingsType::GEOLOCATION, &android_permissions);
for (const auto& android_permission : android_permissions) {
if (!window_android->HasPermission(android_permission))
return true;
}
return false;
}
void GeolocationPermissionContextDelegate::RequestAndroidPermission(
content::WebContents* web_contents,
PermissionUpdatedCallback callback) {
weblayer::RequestAndroidPermission(
web_contents, ContentSettingsType::GEOLOCATION, std::move(callback));
}
bool GeolocationPermissionContextDelegate::IsInteractable(
content::WebContents* web_contents) {
auto* tab = TabImpl::FromWebContents(web_contents);
return tab && tab->IsActive();
}
PrefService* GeolocationPermissionContextDelegate::GetPrefs(
content::BrowserContext* browser_context) {
return static_cast<BrowserContextImpl*>(browser_context)->pref_service();
}
bool GeolocationPermissionContextDelegate::IsRequestingOriginDSE(
content::BrowserContext* browser_context,
const GURL& requesting_origin) {
// TODO(crbug.com/1063433): This may need to be implemented for phase 3.
return false;
}
void GeolocationPermissionContextDelegate::FinishNotifyPermissionSet(
const permissions::PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin) {}
#endif
} // namespace weblayer
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef WEBLAYER_BROWSER_PERMISSIONS_GEOLOCATION_PERMISSION_CONTEXT_DELEGATE_H_
#define WEBLAYER_BROWSER_PERMISSIONS_GEOLOCATION_PERMISSION_CONTEXT_DELEGATE_H_
#include "build/build_config.h"
#include "components/permissions/contexts/geolocation_permission_context.h"
namespace weblayer {
class GeolocationPermissionContextDelegate
: public permissions::GeolocationPermissionContext::Delegate {
public:
GeolocationPermissionContextDelegate() = default;
GeolocationPermissionContextDelegate(
const GeolocationPermissionContextDelegate&) = delete;
GeolocationPermissionContextDelegate& operator=(
const GeolocationPermissionContextDelegate&) = delete;
// GeolocationPermissionContext::Delegate:
bool DecidePermission(
content::WebContents* web_contents,
const permissions::PermissionRequestID& id,
const GURL& requesting_origin,
bool user_gesture,
permissions::BrowserPermissionCallback* callback,
permissions::GeolocationPermissionContext* context) override;
void UpdateTabContext(const permissions::PermissionRequestID& id,
const GURL& requesting_frame,
bool allowed) override;
#if defined(OS_ANDROID)
bool ShouldRequestAndroidLocationPermission(
content::WebContents* web_contents) override;
void RequestAndroidPermission(content::WebContents* web_contents,
PermissionUpdatedCallback callback) override;
bool IsInteractable(content::WebContents* web_contents) override;
PrefService* GetPrefs(content::BrowserContext* browser_context) override;
bool IsRequestingOriginDSE(content::BrowserContext* browser_context,
const GURL& requesting_origin) override;
void FinishNotifyPermissionSet(const permissions::PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin) override;
#endif
};
} // namespace weblayer
#endif // WEBLAYER_BROWSER_PERMISSIONS_GEOLOCATION_PERMISSION_CONTEXT_DELEGATE_H_
......@@ -4,6 +4,7 @@
#include "weblayer/browser/permissions/permission_manager_factory.h"
#include "build/build_config.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/permissions/permission_context_base.h"
......@@ -11,6 +12,13 @@
#include "content/public/browser/permission_type.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy_feature.mojom-shared.h"
#include "weblayer/browser/host_content_settings_map_factory.h"
#include "weblayer/browser/permissions/geolocation_permission_context_delegate.h"
#if defined(OS_ANDROID)
#include "components/permissions/contexts/geolocation_permission_context_android.h"
#else
#include "components/permissions/contexts/geolocation_permission_context.h"
#endif
namespace weblayer {
namespace {
......@@ -39,15 +47,29 @@ class DeniedPermissionContext : public permissions::PermissionContextBase {
permissions::PermissionManager::PermissionContextMap CreatePermissionContexts(
content::BrowserContext* browser_context) {
permissions::PermissionManager::PermissionContextMap permission_contexts;
#if defined(OS_ANDROID)
using GeolocationPermissionContext =
permissions::GeolocationPermissionContextAndroid;
#else
using GeolocationPermissionContext =
permissions::GeolocationPermissionContext;
#endif
permission_contexts[ContentSettingsType::GEOLOCATION] =
std::make_unique<GeolocationPermissionContext>(
browser_context,
std::make_unique<GeolocationPermissionContextDelegate>());
// For now, all requests are denied. As features are added, their permission
// contexts can be added here instead of DeniedPermissionContext.
for (content::PermissionType type : content::GetAllPermissionTypes()) {
ContentSettingsType content_settings_type =
permissions::PermissionManager::PermissionTypeToContentSetting(type);
permission_contexts[content_settings_type] =
std::make_unique<DeniedPermissionContext>(
browser_context, content_settings_type,
blink::mojom::FeaturePolicyFeature::kNotFound);
if (permission_contexts.find(content_settings_type) ==
permission_contexts.end()) {
permission_contexts[content_settings_type] =
std::make_unique<DeniedPermissionContext>(
browser_context, content_settings_type,
blink::mojom::FeaturePolicyFeature::kNotFound);
}
}
return permission_contexts;
}
......
......@@ -10,6 +10,7 @@
package="org.chromium.weblayer.client">
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.INTERNET"/>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment