0

capture_selfie_cam: Respect managed camera policy

The camera on device can be disabled via a policy.
Capture Mode should respect this policy and disallow
selecting any cameras.

Demo: https://bugs.chromium.org/p/chromium/issues/detail?id=1311428#c3

Fixed: 1311428
Test: Manually, added a new unittest.

Change-Id: I4e44cde9dc54efc6585d5f7aaa6255d566ee0333
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3559170
Reviewed-by: James Cook <jamescook@chromium.org>
Commit-Queue: Ahmed Fakhry <afakhry@chromium.org>
Cr-Commit-Position: refs/heads/main@{#987249}
This commit is contained in:
Ahmed Fakhry
2022-03-30 23:28:53 +00:00
committed by Chromium LUCI CQ
parent 72db80693a
commit d1950963b5
16 changed files with 244 additions and 38 deletions

@ -3886,6 +3886,9 @@ Here are some things you can try to get started.
<message name="IDS_ASH_SCREEN_CAPTURE_POLICY_DISABLED_TITLE" desc="The title of the notification when capture mode is disabled because of a policy.">
Can't capture content
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY" desc="The title of the tooltip for a setting that is managed by a policy controlled by the admin.">
This setting is managed by your administrator
</message>
<message name="IDS_ASH_SCREEN_CAPTURE_FAILURE_TITLE" desc="The title of the notification when capture mode fails.">
An error occurred
</message>

@ -0,0 +1 @@
917ef49911d0966bea6d26163799e1d266f71b4d

@ -248,6 +248,10 @@ void CaptureModeCameraController::RemoveObserver(Observer* observer) {
observers_.RemoveObserver(observer);
}
bool CaptureModeCameraController::IsCameraDisabledByPolicy() const {
return delegate_->IsCameraDisabledByPolicy();
}
std::string CaptureModeCameraController::GetDisplayNameOfSelectedCamera()
const {
if (selected_camera_.is_valid()) {
@ -260,6 +264,13 @@ std::string CaptureModeCameraController::GetDisplayNameOfSelectedCamera()
}
void CaptureModeCameraController::SetSelectedCamera(CameraId camera_id) {
// When cameras are disabled by policy, we don't allow any camera selection.
if (IsCameraDisabledByPolicy()) {
LOG(WARNING) << "Camera is disabled by policy. Selecting camera: "
<< camera_id.ToString() << " will be ignored.";
camera_id = CameraId{};
}
if (selected_camera_ == camera_id)
return;
@ -526,6 +537,8 @@ void CaptureModeCameraController::RefreshCameraPreview() {
camera_preview_view_ = nullptr;
}
DCHECK(!IsCameraDisabledByPolicy());
if (!camera_preview_widget_) {
const auto preview_bounds = GetPreviewWidgetBounds();
camera_preview_widget_ = std::make_unique<views::Widget>();

@ -148,6 +148,10 @@ class ASH_EXPORT CaptureModeCameraController
void AddObserver(Observer* observer);
void RemoveObserver(Observer* observer);
// Returns true if camera support is disabled by admins via
// the `SystemFeaturesDisableList` policy, false otherwise.
bool IsCameraDisabledByPolicy() const;
// Returns the display name of `selected_camera_`. Returns an empty string if
// the selected camera is not set.
std::string GetDisplayNameOfSelectedCamera() const;

@ -629,6 +629,42 @@ TEST_F(CaptureModeCameraTest, ShouldShowPreviewTest) {
EXPECT_FALSE(camera_controller->should_show_preview());
}
TEST_F(CaptureModeCameraTest, ManagedByPolicyCameraOptions) {
GetTestDelegate()->set_is_camera_disabled_by_policy(true);
StartCaptureSession(CaptureModeSource::kFullscreen, CaptureModeType::kVideo);
OpenSettingsView();
// At this moment, there are no camera devices connected. The camera menu
// group should be hidden.
CaptureModeSettingsTestApi test_api;
CaptureModeMenuGroup* camera_menu_group = test_api.GetCameraMenuGroup();
ASSERT_TRUE(camera_menu_group);
EXPECT_FALSE(camera_menu_group->GetVisible());
// Camera addition/removal are still observed even when managed by policy, but
// once a camera is added, the group becomes visible, but shows only a dimmed
// "Off" option.
AddDefaultCamera();
EXPECT_TRUE(camera_menu_group->GetVisible());
EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
EXPECT_FALSE(camera_menu_group->IsOptionEnabled(kCameraOff));
EXPECT_FALSE(test_api.GetCameraOption(kCameraDevicesBegin));
// Selecting a camera will be ignored.
auto* camera_controller = GetCameraController();
camera_controller->SetSelectedCamera(CameraId(kDefaultCameraModelId, 1));
EXPECT_FALSE(camera_controller->selected_camera().is_valid());
EXPECT_TRUE(camera_menu_group->IsOptionChecked(kCameraOff));
EXPECT_FALSE(camera_controller->camera_preview_widget());
// Removing the existing camera should hide the camera menu group and remove
// all its options.
RemoveDefaultCamera();
EXPECT_FALSE(camera_menu_group->GetVisible());
EXPECT_FALSE(test_api.GetCameraOption(kCameraOff));
}
// Tests that the options on camera menu are shown and checked correctly when
// adding or removing cameras. Also tests that `selected_camera_` is updated
// correspondently.

@ -17,6 +17,7 @@
#include "base/containers/cxx20_erase_vector.h"
#include "base/ranges/algorithm.h"
#include "ui/accessibility/ax_enums.mojom-shared.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/gfx/paint_vector_icon.h"
#include "ui/views/accessibility/view_accessibility.h"
@ -80,19 +81,34 @@ class CaptureModeMenuHeader
METADATA_HEADER(CaptureModeMenuHeader);
CaptureModeMenuHeader(const gfx::VectorIcon& icon,
std::u16string header_laber)
std::u16string header_laber,
bool managed_by_policy)
: icon_view_(AddChildView(std::make_unique<views::ImageView>())),
label_view_(AddChildView(
std::make_unique<views::Label>(std::move(header_laber)))) {
std::make_unique<views::Label>(std::move(header_laber)))),
managed_icon_view_(
managed_by_policy
? AddChildView(std::make_unique<views::ImageView>())
: nullptr) {
icon_view_->SetImageSize(kIconSize);
icon_view_->SetPreferredSize(kIconSize);
icon_view_->SetImage(gfx::CreateVectorIcon(
icon, AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kButtonIconColor)));
const auto icon_color = AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kButtonIconColor);
icon_view_->SetImage(gfx::CreateVectorIcon(icon, icon_color));
if (managed_icon_view_) {
managed_icon_view_->SetImageSize(kIconSize);
managed_icon_view_->SetPreferredSize(kIconSize);
managed_icon_view_->SetImage(
gfx::CreateVectorIcon(kCaptureModeManagedIcon, icon_color));
managed_icon_view_->SetTooltipText(
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_MANAGED_BY_POLICY));
}
SetBorder(views::CreateEmptyBorder(kMenuHeaderPadding));
ConfigLabelView(label_view_);
CreateAndInitBoxLayoutForView(this);
auto* box_layout = CreateAndInitBoxLayoutForView(this);
box_layout->SetFlexForView(label_view_, 1);
}
CaptureModeMenuHeader(const CaptureModeMenuHeader&) = delete;
@ -116,6 +132,9 @@ class CaptureModeMenuHeader
private:
views::ImageView* icon_view_;
views::Label* label_view_;
// `nullptr` if the menu group is not for a setting that is managed by a
// policy.
views::ImageView* managed_icon_view_;
};
BEGIN_METADATA(CaptureModeMenuHeader, views::View)
@ -184,10 +203,6 @@ class CaptureModeOption
id_(option_id) {
checked_icon_view_->SetImageSize(kIconSize);
checked_icon_view_->SetPreferredSize(kIconSize);
checked_icon_view_->SetImage(gfx::CreateVectorIcon(
kHollowCheckCircleIcon,
AshColorProvider::Get()->GetContentLayerColor(
AshColorProvider::ContentLayerType::kButtonLabelColorBlue)));
SetBorder(views::CreateEmptyBorder(kOptionPadding));
ConfigLabelView(label_view_);
@ -198,7 +213,14 @@ class CaptureModeOption
SetAccessibleName(GetOptionLabel());
checked_icon_view_->SetVisible(checked);
SetEnabled(enabled);
// Calling `SetEnabled()` will result in calling `UpdateState()` only when
// the state changes, but by default the view's state is enabled, so we only
// need to call `UpdateState()` explicitly if `enabled` is true.
if (enabled)
UpdateState();
else
SetEnabled(false);
}
CaptureModeOption(const CaptureModeOption&) = delete;
@ -223,14 +245,7 @@ class CaptureModeOption
bool IsOptionChecked() { return checked_icon_view_->GetVisible(); }
// views::Button:
void StateChanged(ButtonState old_state) override {
auto* provider = AshColorProvider::Get();
const auto enabled_color = provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary);
label_view_->SetEnabledColor(GetState() == STATE_DISABLED
? provider->GetDisabledColor(enabled_color)
: enabled_color);
}
void StateChanged(ButtonState old_state) override { UpdateState(); }
void GetAccessibleNodeData(ui::AXNodeData* node_data) override {
Button::GetAccessibleNodeData(node_data);
@ -245,6 +260,23 @@ class CaptureModeOption
views::View* GetView() override { return this; }
private:
// Dims out the label and the checked icon if this view is disabled.
void UpdateState() {
auto* provider = AshColorProvider::Get();
const auto label_enabled_color = provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kTextColorPrimary);
const auto icon_enabled_color = provider->GetContentLayerColor(
AshColorProvider::ContentLayerType::kButtonLabelColorBlue);
const bool is_disabled = GetState() == STATE_DISABLED;
label_view_->SetEnabledColor(
is_disabled ? provider->GetDisabledColor(label_enabled_color)
: label_enabled_color);
checked_icon_view_->SetImage(gfx::CreateVectorIcon(
kHollowCheckCircleIcon,
is_disabled ? provider->GetDisabledColor(icon_enabled_color)
: icon_enabled_color));
}
views::Label* label_view_;
views::ImageView* checked_icon_view_;
const int id_;
@ -258,11 +290,13 @@ END_METADATA
CaptureModeMenuGroup::CaptureModeMenuGroup(Delegate* delegate,
const gfx::VectorIcon& header_icon,
std::u16string header_label)
std::u16string header_label,
bool managed_by_policy)
: delegate_(delegate),
menu_header_(AddChildView(
std::make_unique<CaptureModeMenuHeader>(header_icon,
std::move(header_label)))) {
std::move(header_label),
managed_by_policy))) {
options_container_ = AddChildView(std::make_unique<views::View>());
options_container_->SetLayoutManager(std::make_unique<views::BoxLayout>(
views::BoxLayout::Orientation::kVertical));
@ -330,6 +364,11 @@ bool CaptureModeMenuGroup::IsOptionChecked(int option_id) const {
return option && option->IsOptionChecked();
}
bool CaptureModeMenuGroup::IsOptionEnabled(int option_id) const {
auto* option = GetOptionById(option_id);
return option && option->GetEnabled();
}
void CaptureModeMenuGroup::AppendHighlightableItems(
std::vector<CaptureModeSessionFocusCycler::HighlightableView*>&
highlightable_items) {

@ -45,9 +45,12 @@ class ASH_EXPORT CaptureModeMenuGroup : public views::View {
virtual ~Delegate() = default;
};
// If `managed_by_policy` is true, the header of this menu group will show an
// enterprise-managed feature icon next to the `header_label`.
CaptureModeMenuGroup(Delegate* delegate,
const gfx::VectorIcon& header_icon,
std::u16string header_label);
std::u16string header_label,
bool managed_by_policy = false);
CaptureModeMenuGroup(const CaptureModeMenuGroup&) = delete;
CaptureModeMenuGroup& operator=(const CaptureModeMenuGroup&) = delete;
~CaptureModeMenuGroup() override;
@ -81,10 +84,14 @@ class ASH_EXPORT CaptureModeMenuGroup : public views::View {
void AddMenuItem(views::Button::PressedCallback callback,
std::u16string item_label);
// Returns true if the option with the given |option_id| is checked, if such
// Returns true if the option with the given `option_id` is checked, if such
// option exists.
bool IsOptionChecked(int option_id) const;
// Returns true if the option with the given `option_id` is enabled, if such
// option exists.
bool IsOptionEnabled(int option_id) const;
// Appends the enabled items from `options_` and `menu_items_` to the given
// `highlightable_items`.
void AppendHighlightableItems(

@ -87,14 +87,18 @@ CaptureModeSettingsView::CaptureModeSettingsView(CaptureModeSession* session,
separator_1_ = AddChildView(std::make_unique<views::Separator>());
separator_1_->SetColor(separator_color);
auto* camera_controller = controller->camera_controller();
const bool managed_by_policy =
camera_controller->IsCameraDisabledByPolicy();
// Even if the camera feature is managed by policy, we still want to observe
// the camera controller, since we need to be notified with camera additions
// and removals, which affect the visibility of the `camera_menu_group_`.
camera_controller->AddObserver(this);
camera_menu_group_ = AddChildView(std::make_unique<CaptureModeMenuGroup>(
this, kCaptureModeCameraIcon,
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_CAMERA)));
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_CAMERA),
managed_by_policy));
const CameraInfoList& cameras = camera_controller->available_cameras();
AddCameraOptions(cameras);
AddCameraOptions(camera_controller->available_cameras(), managed_by_policy);
}
if (!is_in_projector_mode) {
@ -219,6 +223,7 @@ void CaptureModeSettingsView::OnOptionSelected(int option_id) const {
camera_controller->SetSelectedCamera(CameraId());
break;
default:
DCHECK(!camera_controller->IsCameraDisabledByPolicy());
DCHECK_GE(option_id, kCameraDevicesBegin);
const CameraId* camera_id = FindCameraIdByOptionId(option_id);
DCHECK(camera_id);
@ -244,6 +249,7 @@ bool CaptureModeSettingsView::IsOptionChecked(int option_id) const {
case kCameraOff:
return !camera_controller->selected_camera().is_valid();
default:
DCHECK(!camera_controller->IsCameraDisabledByPolicy());
DCHECK_GE(option_id, kCameraDevicesBegin);
const CameraId* camera_id = FindCameraIdByOptionId(option_id);
DCHECK(camera_id);
@ -257,9 +263,14 @@ bool CaptureModeSettingsView::IsOptionEnabled(int option_id) const {
return !capture_mode_session_->is_in_projector_mode();
case kCustomFolder:
return is_custom_folder_available_.value_or(false);
case kCameraOff: {
auto* camera_controller =
CaptureModeController::Get()->camera_controller();
DCHECK(camera_controller);
return !camera_controller->IsCameraDisabledByPolicy();
}
case kAudioMicrophone:
case kDownloadsFolder:
case kCameraOff:
default:
return true;
}
@ -267,9 +278,12 @@ bool CaptureModeSettingsView::IsOptionEnabled(int option_id) const {
void CaptureModeSettingsView::OnAvailableCamerasChanged(
const CameraInfoList& cameras) {
DCHECK(!CaptureModeController::Get()->is_recording_in_progress());
auto* controller = CaptureModeController::Get();
DCHECK(!controller->is_recording_in_progress());
DCHECK(camera_menu_group_);
AddCameraOptions(cameras);
auto* camera_controller = controller->camera_controller();
DCHECK(camera_controller);
AddCameraOptions(cameras, camera_controller->IsCameraDisabledByPolicy());
// If the size of the given `cameras` is equal to the size of the current
// available cameras, the bounds of the `camera_menu_group_` won't be updated,
@ -320,7 +334,8 @@ const CameraId* CaptureModeSettingsView::FindCameraIdByOptionId(
return nullptr;
}
void CaptureModeSettingsView::AddCameraOptions(const CameraInfoList& cameras) {
void CaptureModeSettingsView::AddCameraOptions(const CameraInfoList& cameras,
bool managed_by_policy) {
DCHECK(camera_menu_group_);
camera_menu_group_->DeleteOptions();
option_camera_id_map_.clear();
@ -329,11 +344,14 @@ void CaptureModeSettingsView::AddCameraOptions(const CameraInfoList& cameras) {
camera_menu_group_->AddOption(
l10n_util::GetStringUTF16(IDS_ASH_SCREEN_CAPTURE_CAMERA_OFF),
kCameraOff);
int camera_option_id_begin = kCameraDevicesBegin;
for (const CameraInfo& camera_info : cameras) {
option_camera_id_map_[camera_option_id_begin] = camera_info.camera_id;
camera_menu_group_->AddOption(base::UTF8ToUTF16(camera_info.display_name),
camera_option_id_begin++);
if (!managed_by_policy) {
int camera_option_id_begin = kCameraDevicesBegin;
for (const CameraInfo& camera_info : cameras) {
option_camera_id_map_[camera_option_id_begin] = camera_info.camera_id;
camera_menu_group_->AddOption(
base::UTF8ToUTF16(camera_info.display_name),
camera_option_id_begin++);
}
}
}
UpdateCameraMenuGroupVisibility(/*visible=*/has_cameras);
@ -347,4 +365,4 @@ void CaptureModeSettingsView::UpdateCameraMenuGroupVisibility(bool visible) {
BEGIN_METADATA(CaptureModeSettingsView, views::View)
END_METADATA
} // namespace ash
} // namespace ash

@ -114,7 +114,11 @@ class ASH_EXPORT CaptureModeSettingsView
// `camera_menu_group_` before adding options. Called when initializing `this`
// or `OnAvailableCamerasChanged` is triggered. It will also trigger
// `UpdateCameraMenuGroupVisibility` at the end.
void AddCameraOptions(const CameraInfoList& cameras);
// Note that camera options are only added when `cameras` is not empty.
// When cameras are disabled by policy (i.e. `managed_by_policy` is true),
// only the "Off" option is added. Users are not allowed to choose any cameras
// in that case.
void AddCameraOptions(const CameraInfoList& cameras, bool managed_by_policy);
void UpdateCameraMenuGroupVisibility(bool visible);

@ -178,4 +178,8 @@ void TestCaptureModeDelegate::GetDriveFsFreeSpaceBytes(
std::move(callback).Run(fake_drive_fs_free_bytes_);
}
bool TestCaptureModeDelegate::IsCameraDisabledByPolicy() const {
return is_camera_disabled_by_policy_;
}
} // namespace ash

@ -49,6 +49,9 @@ class TestCaptureModeDelegate : public CaptureModeDelegate {
void set_should_save_after_dlp_check(bool value) {
should_save_after_dlp_check_ = value;
}
void set_is_camera_disabled_by_policy(bool value) {
is_camera_disabled_by_policy_ = value;
}
void set_fake_drive_fs_free_bytes(int64_t bytes) {
fake_drive_fs_free_bytes_ = bytes;
}
@ -108,6 +111,7 @@ class TestCaptureModeDelegate : public CaptureModeDelegate {
mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
override;
void GetDriveFsFreeSpaceBytes(OnGotDriveFsFreeSpace callback) override;
bool IsCameraDisabledByPolicy() const override;
private:
std::unique_ptr<recording::RecordingServiceTestApi> recording_service_;
@ -118,6 +122,7 @@ class TestCaptureModeDelegate : public CaptureModeDelegate {
bool is_allowed_by_dlp_ = true;
bool is_allowed_by_policy_ = true;
bool should_save_after_dlp_check_ = true;
bool is_camera_disabled_by_policy_ = false;
base::ScopedTempDir fake_drive_fs_mount_path_;
base::ScopedTempDir fake_android_files_path_;
base::ScopedTempDir fake_linux_files_path_;

@ -168,6 +168,10 @@ class ASH_PUBLIC_EXPORT CaptureModeDelegate {
// Gets the remaining free space on DriveFS and invokes `callback` with that
// value, or -1 if there's an error in computing the DriveFS quota.
virtual void GetDriveFsFreeSpaceBytes(OnGotDriveFsFreeSpace callback) = 0;
// Returns true if camera support is disabled by admins via
// the `SystemFeaturesDisableList` policy, false otherwise.
virtual bool IsCameraDisabledByPolicy() const = 0;
};
} // namespace ash

@ -48,6 +48,7 @@ aggregate_vector_icons("ash_vector_icons") {
"capture_mode_folder.icon",
"capture_mode_fullscreen.icon",
"capture_mode_image.icon",
"capture_mode_managed.icon",
"capture_mode_mic.icon",
"capture_mode_mic_off.icon",
"capture_mode_play.icon",

@ -0,0 +1,59 @@
// Copyright 2022 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.
CANVAS_DIMENSIONS, 20,
MOVE_TO, 2, 17,
V_LINE_TO, 3,
R_H_LINE_TO, 10,
R_V_LINE_TO, 4,
R_H_LINE_TO, 6,
R_V_LINE_TO, 10,
H_LINE_TO, 2,
CLOSE,
R_MOVE_TO, 6, -8,
R_H_LINE_TO, 2,
R_V_LINE_TO, 2,
H_LINE_TO, 8,
V_LINE_TO, 9,
CLOSE,
R_MOVE_TO, 4, 2,
R_H_LINE_TO, 2,
R_V_LINE_TO, 2,
R_H_LINE_TO, -2,
R_V_LINE_TO, 2,
R_H_LINE_TO, 4,
V_LINE_TO, 9,
R_H_LINE_TO, -4,
R_V_LINE_TO, 2,
CLOSE,
R_MOVE_TO, -4, 2,
R_H_LINE_TO, 2,
R_V_LINE_TO, 2,
H_LINE_TO, 8,
R_V_LINE_TO, -2,
CLOSE,
R_MOVE_TO, -2, 0,
H_LINE_TO, 4,
R_V_LINE_TO, 2,
R_H_LINE_TO, 2,
R_V_LINE_TO, -2,
CLOSE,
R_MOVE_TO, 0, -4,
H_LINE_TO, 4,
R_V_LINE_TO, 2,
R_H_LINE_TO, 2,
V_LINE_TO, 9,
CLOSE,
R_MOVE_TO, 2, -4,
R_H_LINE_TO, 2,
R_V_LINE_TO, 2,
H_LINE_TO, 8,
V_LINE_TO, 5,
CLOSE,
MOVE_TO, 6, 5,
H_LINE_TO, 4,
R_V_LINE_TO, 2,
R_H_LINE_TO, 2,
V_LINE_TO, 5,
CLOSE

@ -21,6 +21,7 @@
#include "chrome/browser/browser_process.h"
#include "chrome/browser/download/download_prefs.h"
#include "chrome/browser/platform_util.h"
#include "chrome/browser/policy/system_features_disable_list_policy_handler.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/capture_mode/recording_overlay_view_impl.h"
#include "chrome/browser/ui/ash/screenshot_area.h"
@ -255,6 +256,12 @@ void ChromeCaptureModeDelegate::GetDriveFsFreeSpaceBytes(
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
bool ChromeCaptureModeDelegate::IsCameraDisabledByPolicy() const {
return policy::SystemFeaturesDisableListPolicyHandler::
IsSystemFeatureDisabled(policy::SystemFeature::kCamera,
g_browser_process->local_state());
}
void ChromeCaptureModeDelegate::OnGetDriveQuotaUsage(
ash::OnGotDriveFsFreeSpace callback,
drive::FileError error,

@ -71,6 +71,7 @@ class ChromeCaptureModeDelegate : public ash::CaptureModeDelegate {
mojo::PendingReceiver<video_capture::mojom::VideoSourceProvider> receiver)
override;
void GetDriveFsFreeSpaceBytes(ash::OnGotDriveFsFreeSpace callback) override;
bool IsCameraDisabledByPolicy() const override;
private:
// Called back by the Drive integration service when the quota usage is