Commit 94c082d4 authored by Alexander Shalamov's avatar Alexander Shalamov Committed by Commit Bot

[sensors] Add sensors usage indicator

This CL adds indicator to the location bar to inform the user
that the web page is using device sensors. Clicking the indicator
allows the user to change site specific settings or go to corresponding
global content settings menu.

UI can be enabled by flipping kGenericSensorExtraClasses feature flag.

Bug: 796904
Change-Id: Idac4c1fdd04041dae27982e5c5173edc65e0679c
Reviewed-on: https://chromium-review.googlesource.com/836887
Commit-Queue: Alexander Shalamov <alexander.shalamov@intel.com>
Reviewed-by: default avatarReilly Grant <reillyg@chromium.org>
Reviewed-by: default avatarBernhard Bauer <bauerb@chromium.org>
Reviewed-by: default avatarRaymes Khoury <raymes@chromium.org>
Reviewed-by: default avatarMikhail Pozdnyakov <mikhail.pozdnyakov@intel.com>
Cr-Commit-Position: refs/heads/master@{#563630}
parent 4ae3d8f6
......@@ -8908,6 +8908,38 @@ Please help our engineers fix this problem. Tell us what happened right before y
Block
</message>
<!-- Sensor messages -->
<message name="IDS_SENSORS_ALLOWED_TOOLTIP" desc="Location bar icon tooltip text when a page is allowed to use device's sensors.">
This site is using motion or light sensors.
</message>
<message name="IDS_SENSORS_BLOCKED_TOOLTIP" desc="Location bar icon tooltip text when a page is blocked from using device's sensors.">
This site has been blocked from using motion and light sensors.
</message>
<message name="IDS_BLOCKED_SENSORS_UNBLOCK" desc="Radio button choice to unblock a site from using device's sensors, displayed in bubble when blocked indicator icon is clicked.">
Always allow <ph name="HOST">$1<ex>mail.google.com</ex></ph> to access sensors
</message>
<message name="IDS_BLOCKED_SENSORS_NO_ACTION" desc="Radio button choice to continue blocking a site from using device's motion or light sensors, displayed in bubble when blocked indicator icon is clicked.">
Continue blocking sensor access
</message>
<message name="IDS_ALLOWED_SENSORS_TITLE" desc="Bubble info header text when a page is allowed to use device's sensors.">
Sensors allowed
</message>
<message name="IDS_BLOCKED_SENSORS_TITLE" desc="Bubble info header text when a page is not allowed to use device's sensors.">
Sensors blocked
</message>
<message name="IDS_ALLOWED_SENSORS_MESSAGE" desc="Message for the page action when access to sensors was allowed">
This site is accessing your motion or light sensors.
</message>
<message name="IDS_BLOCKED_SENSORS_MESSAGE" desc="Message for the page action when access to sensors was blocked">
This site has been blocked from accessing your motion or light sensors.
</message>
<message name="IDS_ALLOWED_SENSORS_NO_ACTION" desc="Radio button choice to keep allowing a site to use device's sensors, displayed in bubble when location bar is clicked.">
Continue allowing sensor access
</message>
<message name="IDS_ALLOWED_SENSORS_BLOCK" desc="Radio button choice to block a site from accessing device's sensors, displayed in bubble when location bar indicator inside is clicked.">
Always block <ph name="HOST">$1<ex>mail.google.com</ex></ph> from accessing sensors
</message>
<!-- Quota messages -->
<if expr="is_android">
<message name="IDS_REQUEST_QUOTA_INFOBAR_TEXT" desc="Mobile: For Android device. Text requesting permission for a site to use a new (larger) quota to persistently store data on the device (e.g. for persistent-type filesystem).">
......
......@@ -272,7 +272,8 @@ bool TabSpecificContentSettings::IsContentBlocked(
content_type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX ||
content_type == CONTENT_SETTINGS_TYPE_ADS ||
content_type == CONTENT_SETTINGS_TYPE_SOUND ||
content_type == CONTENT_SETTINGS_TYPE_CLIPBOARD_READ) {
content_type == CONTENT_SETTINGS_TYPE_CLIPBOARD_READ ||
content_type == CONTENT_SETTINGS_TYPE_SENSORS) {
const auto& it = content_settings_status_.find(content_type);
if (it != content_settings_status_.end())
return it->second.blocked;
......@@ -300,13 +301,15 @@ bool TabSpecificContentSettings::IsContentAllowed(
<< "Automatic downloads handled by DownloadRequestLimiter";
// This method currently only returns meaningful values for the content type
// cookies, media, PPAPI broker, downloads, MIDI sysex, and clipboard.
// cookies, media, PPAPI broker, downloads, MIDI sysex, clipboard, and
// sensors.
if (content_type != CONTENT_SETTINGS_TYPE_COOKIES &&
content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC &&
content_type != CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA &&
content_type != CONTENT_SETTINGS_TYPE_PPAPI_BROKER &&
content_type != CONTENT_SETTINGS_TYPE_MIDI_SYSEX &&
content_type != CONTENT_SETTINGS_TYPE_CLIPBOARD_READ) {
content_type != CONTENT_SETTINGS_TYPE_CLIPBOARD_READ &&
content_type != CONTENT_SETTINGS_TYPE_SENSORS) {
return false;
}
......
......@@ -4,8 +4,12 @@
#include "chrome/browser/generic_sensor/sensor_permission_context.h"
#include "base/feature_list.h"
#include "chrome/browser/content_settings/tab_specific_content_settings.h"
#include "chrome/browser/permissions/permission_request_id.h"
#include "components/content_settings/core/common/content_settings.h"
#include "components/content_settings/core/common/content_settings_types.h"
#include "services/device/public/cpp/device_features.h"
#include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
#include "url/gurl.h"
......@@ -16,6 +20,25 @@ SensorPermissionContext::SensorPermissionContext(Profile* profile)
SensorPermissionContext::~SensorPermissionContext() {}
void SensorPermissionContext::UpdateTabContext(const PermissionRequestID& id,
const GURL& requesting_frame,
bool allowed) {
// Show location bar indicator only when features::kGenericSensorExtraClasses
// feature is enabled.
if (!base::FeatureList::IsEnabled(features::kGenericSensorExtraClasses))
return;
auto* content_settings = TabSpecificContentSettings::GetForFrame(
id.render_process_id(), id.render_frame_id());
if (!content_settings)
return;
if (allowed)
content_settings->OnContentAllowed(CONTENT_SETTINGS_TYPE_SENSORS);
else
content_settings->OnContentBlocked(CONTENT_SETTINGS_TYPE_SENSORS);
}
ContentSetting SensorPermissionContext::GetPermissionStatusInternal(
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
......
......@@ -16,6 +16,9 @@ class SensorPermissionContext : public PermissionContextBase {
private:
// PermissionContextBase:
void UpdateTabContext(const PermissionRequestID& id,
const GURL& requesting_frame,
bool allowed) override;
ContentSetting GetPermissionStatusInternal(
content::RenderFrameHost* render_frame_host,
const GURL& requesting_origin,
......
......@@ -330,6 +330,7 @@ const ContentTypeToNibPath kNibPaths[] = {
{CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, @"ContentProtocolHandlers"},
{CONTENT_SETTINGS_TYPE_MIDI_SYSEX, @"ContentBlockedMIDISysEx"},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, @"ContentBlockedSimple"},
{CONTENT_SETTINGS_TYPE_SENSORS, @"ContentBlockedSimple"},
};
- (id)initWithModel:(ContentSettingBubbleModel*)contentSettingBubbleModel
......
......@@ -139,12 +139,14 @@ void ContentSettingSimpleBubbleModel::SetTitle() {
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_TITLE},
{CONTENT_SETTINGS_TYPE_SOUND, IDS_BLOCKED_SOUND_TITLE},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_BLOCKED_CLIPBOARD_TITLE},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_BLOCKED_SENSORS_TITLE},
};
// Fields as for kBlockedTitleIDs, above.
static const ContentSettingsTypeIdEntry kAccessedTitleIDs[] = {
{CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_TITLE},
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_TITLE},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_ALLOWED_CLIPBOARD_TITLE},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_ALLOWED_SENSORS_TITLE},
};
const ContentSettingsTypeIdEntry* title_ids = kBlockedTitleIDs;
size_t num_title_ids = arraysize(kBlockedTitleIDs);
......@@ -173,12 +175,14 @@ void ContentSettingSimpleBubbleModel::SetMessage() {
IDS_BLOCKED_DISPLAYING_INSECURE_CONTENT},
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_MESSAGE},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_BLOCKED_CLIPBOARD_MESSAGE},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_BLOCKED_SENSORS_MESSAGE},
};
// Fields as for kBlockedMessageIDs, above.
static const ContentSettingsTypeIdEntry kAccessedMessageIDs[] = {
{CONTENT_SETTINGS_TYPE_COOKIES, IDS_ACCESSED_COOKIES_MESSAGE},
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_MESSAGE},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_ALLOWED_CLIPBOARD_MESSAGE},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_ALLOWED_SENSORS_MESSAGE},
};
const ContentSettingsTypeIdEntry* message_ids = kBlockedMessageIDs;
size_t num_message_ids = arraysize(kBlockedMessageIDs);
......@@ -789,12 +793,14 @@ void ContentSettingSingleRadioGroup::SetRadioGroup() {
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_UNBLOCK},
{CONTENT_SETTINGS_TYPE_SOUND, IDS_BLOCKED_SOUND_UNBLOCK},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_BLOCKED_CLIPBOARD_UNBLOCK},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_BLOCKED_SENSORS_UNBLOCK},
};
// Fields as for kBlockedAllowIDs, above.
static const ContentSettingsTypeIdEntry kAllowedAllowIDs[] = {
{CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_NO_ACTION},
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_NO_ACTION},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_ALLOWED_CLIPBOARD_NO_ACTION},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_ALLOWED_SENSORS_NO_ACTION},
};
base::string16 radio_allow_label;
......@@ -817,11 +823,13 @@ void ContentSettingSingleRadioGroup::SetRadioGroup() {
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_BLOCKED_PPAPI_BROKER_NO_ACTION},
{CONTENT_SETTINGS_TYPE_SOUND, IDS_BLOCKED_SOUND_NO_ACTION},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_BLOCKED_CLIPBOARD_NO_ACTION},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_BLOCKED_SENSORS_NO_ACTION},
};
static const ContentSettingsTypeIdEntry kAllowedBlockIDs[] = {
{CONTENT_SETTINGS_TYPE_COOKIES, IDS_ALLOWED_COOKIES_BLOCK},
{CONTENT_SETTINGS_TYPE_PPAPI_BROKER, IDS_ALLOWED_PPAPI_BROKER_BLOCK},
{CONTENT_SETTINGS_TYPE_CLIPBOARD_READ, IDS_ALLOWED_CLIPBOARD_BLOCK},
{CONTENT_SETTINGS_TYPE_SENSORS, IDS_ALLOWED_SENSORS_BLOCK},
};
base::string16 radio_block_label;
......@@ -1708,7 +1716,8 @@ ContentSettingBubbleModel*
content_type == CONTENT_SETTINGS_TYPE_JAVASCRIPT ||
content_type == CONTENT_SETTINGS_TYPE_PPAPI_BROKER ||
content_type == CONTENT_SETTINGS_TYPE_SOUND ||
content_type == CONTENT_SETTINGS_TYPE_CLIPBOARD_READ) {
content_type == CONTENT_SETTINGS_TYPE_CLIPBOARD_READ ||
content_type == CONTENT_SETTINGS_TYPE_SENSORS) {
return new ContentSettingSingleRadioGroup(delegate, web_contents, profile,
content_type);
}
......
......@@ -47,6 +47,7 @@ using content::WebContents;
// ContentSettingMIDISysExImageModel - midi sysex
// ContentSettingDownloadsImageModel - automatic downloads
// ContentSettingClipboardReadImageModel - clipboard read
// ContentSettingSensorsImageModel - sensors
// ContentSettingMediaImageModel - media
// ContentSettingSubresourceFilterImageModel - deceptive content
// ContentSettingFramebustBlockImageModel - blocked framebust
......@@ -135,6 +136,16 @@ class ContentSettingMediaImageModel : public ContentSettingImageModel {
DISALLOW_COPY_AND_ASSIGN(ContentSettingMediaImageModel);
};
class ContentSettingSensorsImageModel : public ContentSettingSimpleImageModel {
public:
ContentSettingSensorsImageModel();
void UpdateFromWebContents(WebContents* web_contents) override;
private:
DISALLOW_COPY_AND_ASSIGN(ContentSettingSensorsImageModel);
};
namespace {
struct ContentSettingsImageDetails {
......@@ -259,6 +270,8 @@ ContentSettingImageModel::CreateForContentType(ImageType image_type) {
return std::make_unique<ContentSettingFramebustBlockImageModel>();
case ImageType::CLIPBOARD_READ:
return std::make_unique<ContentSettingClipboardReadImageModel>();
case ImageType::SENSORS:
return std::make_unique<ContentSettingSensorsImageModel>();
case ImageType::NUM_IMAGE_TYPES:
break;
}
......@@ -682,6 +695,33 @@ void ContentSettingFramebustBlockImageModel::SetAnimationHasRun(
->set_animation_has_run();
}
// Sensors ---------------------------------------------------------------------
ContentSettingSensorsImageModel::ContentSettingSensorsImageModel()
: ContentSettingSimpleImageModel(ImageType::SENSORS,
CONTENT_SETTINGS_TYPE_SENSORS) {}
void ContentSettingSensorsImageModel::UpdateFromWebContents(
WebContents* web_contents) {
set_visible(false);
if (!web_contents)
return;
auto* content_settings =
TabSpecificContentSettings::FromWebContents(web_contents);
if (!content_settings)
return;
bool blocked = content_settings->IsContentBlocked(content_type());
bool allowed = content_settings->IsContentAllowed(content_type());
if (!blocked && !allowed)
return;
set_visible(true);
set_icon(kSensorsIcon, allowed ? gfx::kNoneIcon : kBlockedBadgeIcon);
set_tooltip(l10n_util::GetStringUTF16(allowed ? IDS_SENSORS_ALLOWED_TOOLTIP
: IDS_SENSORS_BLOCKED_TOOLTIP));
}
// Base class ------------------------------------------------------------------
gfx::Image ContentSettingImageModel::GetIcon(SkColor icon_color) const {
......@@ -726,6 +766,7 @@ ContentSettingImageModel::GenerateContentSettingImageModels() {
ImageType::MIXEDSCRIPT,
ImageType::PROTOCOL_HANDLERS,
ImageType::MEDIASTREAM,
ImageType::SENSORS,
ImageType::ADS,
ImageType::AUTOMATIC_DOWNLOADS,
ImageType::MIDI_SYSEX,
......
......@@ -47,6 +47,7 @@ class ContentSettingImageModel {
SOUND = 13,
FRAMEBUST = 14,
CLIPBOARD_READ = 15,
SENSORS = 16,
NUM_IMAGE_TYPES
};
......
......@@ -29,7 +29,8 @@ SensorProviderProxyImpl::SensorProviderProxyImpl(
PermissionManager* permission_manager,
RenderFrameHost* render_frame_host)
: permission_manager_(permission_manager),
render_frame_host_(render_frame_host) {
render_frame_host_(render_frame_host),
weak_factory_(this) {
DCHECK(permission_manager);
DCHECK(render_frame_host);
}
......@@ -43,36 +44,46 @@ void SensorProviderProxyImpl::Bind(
void SensorProviderProxyImpl::GetSensor(SensorType type,
GetSensorCallback callback) {
ServiceManagerConnection* connection =
ServiceManagerConnection::GetForProcess();
if (!connection) {
std::move(callback).Run(SensorCreationResult::ERROR_NOT_AVAILABLE, nullptr);
return;
}
if (!CheckFeaturePolicies(type) || !CheckPermission()) {
if (!CheckFeaturePolicies(type)) {
std::move(callback).Run(SensorCreationResult::ERROR_NOT_ALLOWED, nullptr);
return;
}
if (!sensor_provider_) {
auto* connection = ServiceManagerConnection::GetForProcess();
if (!connection) {
std::move(callback).Run(SensorCreationResult::ERROR_NOT_AVAILABLE,
nullptr);
return;
}
connection->GetConnector()->BindInterface(
device::mojom::kServiceName, mojo::MakeRequest(&sensor_provider_));
sensor_provider_.set_connection_error_handler(base::BindOnce(
&SensorProviderProxyImpl::OnConnectionError, base::Unretained(this)));
}
sensor_provider_->GetSensor(type, std::move(callback));
}
bool SensorProviderProxyImpl::CheckPermission() const {
const GURL& requesting_origin =
render_frame_host_->GetLastCommittedURL().GetOrigin();
// TODO(shalamov): base::BindOnce should be used (https://crbug.com/714018),
// however, PermissionManager::RequestPermission enforces use of repeating
// callback.
permission_manager_->RequestPermission(
PermissionType::SENSORS, render_frame_host_,
render_frame_host_->GetLastCommittedURL().GetOrigin(), false,
base::BindRepeating(
&SensorProviderProxyImpl::OnPermissionRequestCompleted,
weak_factory_.GetWeakPtr(), type, base::Passed(std::move(callback))));
}
blink::mojom::PermissionStatus permission_status =
permission_manager_->GetPermissionStatusForFrame(
PermissionType::SENSORS, render_frame_host_, requesting_origin);
return permission_status == blink::mojom::PermissionStatus::GRANTED;
void SensorProviderProxyImpl::OnPermissionRequestCompleted(
device::mojom::SensorType type,
GetSensorCallback callback,
blink::mojom::PermissionStatus status) {
if (status != blink::mojom::PermissionStatus::GRANTED || !sensor_provider_) {
std::move(callback).Run(SensorCreationResult::ERROR_NOT_ALLOWED, nullptr);
return;
}
sensor_provider_->GetSensor(type, std::move(callback));
}
namespace {
......
......@@ -5,9 +5,11 @@
#ifndef CONTENT_BROWSER_GENERIC_SENSOR_SENSOR_PROVIDER_PROXY_IMPL_H_
#define CONTENT_BROWSER_GENERIC_SENSOR_SENSOR_PROVIDER_PROXY_IMPL_H_
#include "base/memory/weak_ptr.h"
#include "content/public/browser/web_contents_observer.h"
#include "mojo/public/cpp/bindings/binding_set.h"
#include "services/device/public/mojom/sensor_provider.mojom.h"
#include "third_party/blink/public/platform/modules/permissions/permission_status.mojom.h"
namespace content {
......@@ -30,9 +32,10 @@ class SensorProviderProxyImpl final : public device::mojom::SensorProvider {
void GetSensor(device::mojom::SensorType type,
GetSensorCallback callback) override;
bool CheckPermission() const;
bool CheckFeaturePolicies(device::mojom::SensorType type) const;
void OnPermissionRequestCompleted(device::mojom::SensorType type,
GetSensorCallback callback,
blink::mojom::PermissionStatus);
void OnConnectionError();
mojo::BindingSet<device::mojom::SensorProvider> binding_set_;
......@@ -40,6 +43,8 @@ class SensorProviderProxyImpl final : public device::mojom::SensorProvider {
RenderFrameHost* render_frame_host_;
device::mojom::SensorProviderPtr sensor_provider_;
base::WeakPtrFactory<SensorProviderProxyImpl> weak_factory_;
DISALLOW_COPY_AND_ASSIGN(SensorProviderProxyImpl);
};
......
......@@ -6947,6 +6947,7 @@ Called by update_net_error_codes.py.-->
<int value="12" label="MIDI_SYSEX"/>
<int value="13" label="SOUND"/>
<int value="14" label="FRAMEBUST"/>
<int value="16" label="SENSORS"/>
</enum>
<enum name="ContentSettingMixedScriptAction">
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