// Copyright 2021 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/permissions/permission_update_message_controller_android.h"
#include <memory>
#include <utility>
#include <vector>
#include "chrome/browser/android/android_theme_resources.h"
#include "chrome/grit/branded_strings.h"
#include "components/permissions/android/android_permission_util.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "device/vr/buildflags/buildflags.h"
#include "ui/android/window_android.h"
#if BUILDFLAG(ENABLE_OPENXR)
#include "base/feature_list.h"
#include "device/vr/public/cpp/features.h"
#endif
void PermissionUpdateMessageController::ShowMessage(
const std::vector<ContentSettingsType>& content_settings_types,
const std::vector<ContentSettingsType>& filtered_content_settings_types,
const std::vector<std::string>& required_permissions,
const std::vector<std::string>& optional_permissions,
PermissionUpdatedCallback callback) {
DCHECK_EQ(permissions::ShouldRepromptUserForPermissions(
&GetWebContents(), content_settings_types),
permissions::PermissionRepromptState::kShow)
<< "Caller should check ShouldRepromptUserForPermissions before "
"creating the message ui.";
const std::tuple<int, int, int> res =
GetPermissionUpdateUiResourcesId(filtered_content_settings_types);
ShowMessageInternal(required_permissions, optional_permissions,
content_settings_types, std::get<0>(res),
std::get<1>(res), std::get<2>(res), std::move(callback));
}
void PermissionUpdateMessageController::ShowMessage(
const std::vector<std::string>& required_android_permissions,
int icon_id,
int title_id,
int description_id,
PermissionUpdatedCallback callback) {
std::vector<ContentSettingsType> empty_content_settings_types;
std::vector<std::string> empty_optional_android_permissions;
ShowMessageInternal(required_android_permissions,
empty_optional_android_permissions,
empty_content_settings_types, icon_id, title_id,
description_id, std::move(callback));
}
void PermissionUpdateMessageController::ShowMessageInternal(
const std::vector<std::string>& required_android_permissions,
const std::vector<std::string>& optional_android_permissions,
const std::vector<ContentSettingsType> content_settings_types,
int icon_id,
int title_id,
int description_id,
PermissionUpdatedCallback callback) {
for (auto& delegate : message_delegates_) {
if (delegate->GetTitleId() == title_id) {
// Duplicated messages must be filtered out in permission layer, except
// Download.
DCHECK(title_id == IDS_MESSAGE_MISSING_STORAGE_ACCESS_PERMISSION_TITLE);
delegate->AttachAdditionalCallback(std::move(callback));
return;
}
}
auto delegate = std::make_unique<PermissionUpdateMessageDelegate>(
&GetWebContents(), required_android_permissions,
optional_android_permissions, content_settings_types, icon_id, title_id,
description_id, std::move(callback),
base::BindOnce(&PermissionUpdateMessageController::DeleteMessage,
base::Unretained(this)));
message_delegates_.push_back(std::move(delegate));
}
void PermissionUpdateMessageController::DeleteMessage(
PermissionUpdateMessageDelegate* delegate) {
std::erase_if(
message_delegates_,
[delegate](const std::unique_ptr<PermissionUpdateMessageDelegate>& d) {
return delegate == d.get();
});
}
std::tuple<int, int, int>
PermissionUpdateMessageController::GetPermissionUpdateUiResourcesId(
const std::vector<ContentSettingsType>& content_settings_types) {
int message_id = -1;
for (ContentSettingsType content_settings_type : content_settings_types) {
switch (message_id) {
case -1:
if (content_settings_type == ContentSettingsType::GEOLOCATION) {
message_id = IDS_MESSAGE_MISSING_LOCATION_PERMISSION_TEXT;
} else if (content_settings_type ==
ContentSettingsType::MEDIASTREAM_MIC) {
message_id = IDS_MESSAGE_MISSING_MICROPHONE_PERMISSION_TEXT;
} else if (content_settings_type ==
ContentSettingsType::MEDIASTREAM_CAMERA) {
message_id = IDS_MESSAGE_MISSING_CAMERA_PERMISSION_TEXT;
} else if (content_settings_type == ContentSettingsType::AR) {
message_id = IDS_MESSAGE_MISSING_AR_CAMERA_PERMISSION_TEXT;
#if BUILDFLAG(ENABLE_OPENXR)
if (device::features::IsOpenXrEnabled()) {
message_id = IDS_MESSAGE_MISSING_XR_PERMISSION_TEXT;
}
#endif
} else if (content_settings_type == ContentSettingsType::VR) {
#if BUILDFLAG(ENABLE_OPENXR)
if (device::features::IsOpenXrEnabled()) {
message_id = IDS_MESSAGE_MISSING_XR_PERMISSION_TEXT;
}
#endif
} else if (content_settings_type ==
ContentSettingsType::HAND_TRACKING) {
message_id = IDS_MESSAGE_MISSING_HAND_TRACKING_PERMISSION_TEXT;
} else {
NOTREACHED_IN_MIGRATION();
}
break;
case IDS_MESSAGE_MISSING_CAMERA_PERMISSION_TEXT:
DCHECK(content_settings_type == ContentSettingsType::MEDIASTREAM_MIC);
return std::make_tuple(
IDR_ANDORID_MESSAGE_PERMISSION_VIDEOCAM,
IDS_MESSAGE_MISSING_MICROPHONE_CAMERA_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_MICROPHONE_CAMERA_PERMISSIONS_TEXT);
case IDS_MESSAGE_MISSING_MICROPHONE_PERMISSION_TEXT:
DCHECK(content_settings_type ==
ContentSettingsType::MEDIASTREAM_CAMERA);
return std::make_tuple(
IDR_ANDORID_MESSAGE_PERMISSION_VIDEOCAM,
IDS_MESSAGE_MISSING_MICROPHONE_CAMERA_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_MICROPHONE_CAMERA_PERMISSIONS_TEXT);
default:
NOTREACHED_IN_MIGRATION();
break;
}
}
switch (message_id) {
case IDS_MESSAGE_MISSING_LOCATION_PERMISSION_TEXT:
return std::make_tuple(IDR_ANDROID_INFOBAR_GEOLOCATION,
IDS_MESSAGE_MISSING_LOCATION_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_LOCATION_PERMISSION_TEXT);
case IDS_MESSAGE_MISSING_MICROPHONE_PERMISSION_TEXT:
return std::make_tuple(IDR_ANDROID_INFOBAR_MEDIA_STREAM_MIC,
IDS_MESSAGE_MISSING_MICROPHONE_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_MICROPHONE_PERMISSION_TEXT);
case IDS_MESSAGE_MISSING_CAMERA_PERMISSION_TEXT:
return std::make_tuple(IDR_ANDORID_MESSAGE_PERMISSION_CAMERA,
IDS_MESSAGE_MISSING_CAMERA_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_CAMERA_PERMISSION_TEXT);
case IDS_MESSAGE_MISSING_AR_CAMERA_PERMISSION_TEXT:
return std::make_tuple(IDR_ANDORID_MESSAGE_PERMISSION_CAMERA,
IDS_MESSAGE_MISSING_CAMERA_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_AR_CAMERA_PERMISSION_TEXT);
case IDS_MESSAGE_MISSING_XR_PERMISSION_TEXT:
return std::make_tuple(IDR_ANDROID_MESSAGE_PERMISSION_XR,
IDS_MESSAGE_MISSING_XR_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_XR_PERMISSION_TEXT);
case IDS_MESSAGE_MISSING_HAND_TRACKING_PERMISSION_TEXT:
return std::make_tuple(IDR_ANDROID_MESSAGE_PERMISSION_HAND_TRACKING,
IDS_MESSAGE_MISSING_HAND_TRACKING_PERMISSION_TITLE,
IDS_MESSAGE_MISSING_HAND_TRACKING_PERMISSION_TEXT);
default:
NOTREACHED_IN_MIGRATION();
break;
}
return std::make_tuple(-1, -1, -1);
}
PermissionUpdateMessageController::PermissionUpdateMessageController(
content::WebContents* web_contents)
: content::WebContentsUserData<PermissionUpdateMessageController>(
*web_contents) {}
PermissionUpdateMessageController::~PermissionUpdateMessageController() {
message_delegates_.clear();
}
WEB_CONTENTS_USER_DATA_KEY_IMPL(PermissionUpdateMessageController);