blob: de461d3f6e1739a7bfea8a0a839104d3ddfce24f [file] [log] [blame]
// Copyright 2019 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 "chrome/browser/vr/webxr_permission_context.h"
#include "base/check.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
#if defined(OS_ANDROID)
#include "chrome/browser/permissions/permission_update_infobar_delegate_android.h"
#include "components/permissions/android/android_permission_util.h"
#include "components/permissions/permission_request_id.h"
#include "content/public/browser/web_contents.h"
#endif
WebXrPermissionContext::WebXrPermissionContext(
content::BrowserContext* browser_context,
ContentSettingsType content_settings_type)
: PermissionContextBase(browser_context,
content_settings_type,
blink::mojom::FeaturePolicyFeature::kWebXr),
content_settings_type_(content_settings_type) {
DCHECK(content_settings_type_ == ContentSettingsType::VR ||
content_settings_type_ == ContentSettingsType::AR);
}
WebXrPermissionContext::~WebXrPermissionContext() = default;
bool WebXrPermissionContext::IsRestrictedToSecureOrigins() const {
return true;
}
#if defined(OS_ANDROID)
// There are two other permissions that need to check corresponding OS-level
// permissions, and they take two different approaches to this. Geolocation only
// stores the permission ContentSetting if both requests are granted (or if the
// site permission is "Block"). The media permissions follow something more
// similar to this approach, first querying and storing the site-specific
// ContentSetting and then querying for the additional OS permissions as needed.
// However, this is done in MediaStreamDevicesController, not their permission
// context. By persisting and then running additional code as needed, we thus
// mimic that flow, but keep all logic contained into the permission context
// class.
void WebXrPermissionContext::NotifyPermissionSet(
const permissions::PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
permissions::BrowserPermissionCallback callback,
bool persist,
ContentSetting content_setting) {
// Only AR needs to check for additional permissions, and then only if it was
// actually allowed.
if (!(content_settings_type_ == ContentSettingsType::AR &&
content_setting == ContentSetting::CONTENT_SETTING_ALLOW)) {
PermissionContextBase::NotifyPermissionSet(
id, requesting_origin, embedding_origin, std::move(callback), persist,
content_setting);
return;
}
// Whether or not the user will ultimately accept the OS permissions, we want
// to save the content_setting here if we should.
if (persist) {
PermissionContextBase::UpdateContentSetting(
requesting_origin, embedding_origin, content_setting);
}
content::WebContents* web_contents =
content::WebContents::FromRenderFrameHost(
content::RenderFrameHost::FromID(id.render_process_id(),
id.render_frame_id()));
if (!web_contents) {
// If we can't get the web contents, we don't know the state of the OS
// permission, so assume we don't have it.
OnAndroidPermissionDecided(id, requesting_origin, embedding_origin,
std::move(callback),
false /*permission_granted*/);
return;
}
// Otherwise, the user granted permission to use AR, so now we need to check
// if we need to prompt for android system permissions.
std::vector<ContentSettingsType> permission_type = {content_settings_type_};
permissions::PermissionRepromptState reprompt_state =
permissions::ShouldRepromptUserForPermissions(web_contents,
permission_type);
switch (reprompt_state) {
case permissions::PermissionRepromptState::kNoNeed:
// We have already returned if permission was denied by the user, and this
// indicates that we have all the OS permissions we need.
OnAndroidPermissionDecided(id, requesting_origin, embedding_origin,
std::move(callback),
true /*permission_granted*/);
return;
case permissions::PermissionRepromptState::kCannotShow:
// If we cannot show the info bar, then we have to assume we don't have
// the permissions we need.
OnAndroidPermissionDecided(id, requesting_origin, embedding_origin,
std::move(callback),
false /*permission_granted*/);
return;
case permissions::PermissionRepromptState::kShow:
// Otherwise, prompt the user that we need additional permissions.
PermissionUpdateInfoBarDelegate::Create(
web_contents, permission_type,
base::BindOnce(&WebXrPermissionContext::OnAndroidPermissionDecided,
weak_ptr_factory_.GetWeakPtr(), id, requesting_origin,
embedding_origin, std::move(callback)));
return;
}
}
void WebXrPermissionContext::OnAndroidPermissionDecided(
const permissions::PermissionRequestID& id,
const GURL& requesting_origin,
const GURL& embedding_origin,
permissions::BrowserPermissionCallback callback,
bool permission_granted) {
// If we were supposed to persist the setting we've already done so in the
// initial override of |NotifyPermissionSet|. At this point, if the user
// has denied the OS level permission, we want to notify the requestor that
// the permission has been blocked.
// TODO(https://crbug.com/1060163): Ensure that this is taken into account
// when returning navigator.permissions results.
ContentSetting setting = permission_granted
? ContentSetting::CONTENT_SETTING_ALLOW
: ContentSetting::CONTENT_SETTING_BLOCK;
permissions::PermissionContextBase::NotifyPermissionSet(
id, requesting_origin, embedding_origin, std::move(callback),
false /*persist*/, setting);
}
#endif // defined(OS_ANDROID)