// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/permissions/permission_request.h"

#include <string>
#include <utility>
#include <variant>

#include "base/check.h"
#include "base/feature_list.h"
#include "base/no_destructor.h"
#include "base/notreached.h"
#include "build/build_config.h"
#include "components/content_settings/core/common/features.h"
#include "components/permissions/permission_decision.h"
#include "components/permissions/permission_prompt_decision.h"
#include "components/permissions/permission_util.h"
#include "components/permissions/request_type.h"
#include "components/strings/grit/components_strings.h"
#include "components/url_formatter/elide_url.h"
#include "content/public/browser/permission_controller.h"
#include "content/public/browser/render_frame_host.h"
#include "services/device/public/cpp/device_features.h"
#include "third_party/blink/public/mojom/permissions/permission.mojom.h"
#include "ui/base/device_form_factor.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/gfx/text_elider.h"
#include "ui/strings/grit/ui_strings.h"

namespace permissions {

namespace {

bool AreGenericSensorExtraClassesEnabled() {
  return base::FeatureList::IsEnabled(::features::kGenericSensorExtraClasses);
}

}  // namespace

PermissionRequest::PermissionRequest(
    std::unique_ptr<PermissionRequestData> request_data,
    PermissionDecidedCallback permission_decided_callback,
    base::OnceClosure request_finished_callback,
    bool uses_automatic_embargo)
    : data_(std::move(request_data)),
      permission_decided_callback_(std::move(permission_decided_callback)),
      request_finished_callback_(std::move(request_finished_callback)),
      uses_automatic_embargo_(uses_automatic_embargo) {}

PermissionRequest::~PermissionRequest() {
  std::move(request_finished_callback_).Run();
}

RequestType PermissionRequest::request_type() const {
  CHECK(data_->request_type);
  return data_->request_type.value();
}

bool PermissionRequest::IsDuplicateOf(PermissionRequest* other_request) const {
  return request_type() == other_request->request_type() &&
         requesting_origin() == other_request->requesting_origin();
}

base::SafeRef<PermissionRequest> PermissionRequest::GetSafeRef() {
  return weak_factory_.GetSafeRef();
}

#if BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)
PermissionRequest::AnnotatedMessageText::AnnotatedMessageText(
    std::u16string text,
    std::vector<std::pair<size_t, size_t>> bolded_ranges)
    : text(text), bolded_ranges(bolded_ranges) {}

PermissionRequest::AnnotatedMessageText::~AnnotatedMessageText() = default;

PermissionRequest::AnnotatedMessageText
PermissionRequest::GetDialogAnnotatedMessageText(
    const GURL& embedding_origin) const {
  int message_id = 0;
  std::u16string requesting_origin_string_formatted =
      url_formatter::FormatUrlForSecurityDisplay(
          requesting_origin(),
          url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);
  std::u16string embedding_origin_string_formatted =
      url_formatter::FormatUrlForSecurityDisplay(
          embedding_origin, url_formatter::SchemeDisplay::OMIT_CRYPTOGRAPHIC);

  switch (request_type()) {
    case RequestType::kArSession:
      message_id = IDS_AR_INFOBAR_TEXT;
      break;
    case RequestType::kCameraStream:
      message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_INFOBAR_TEXT;
      break;
    case RequestType::kClipboard:
      message_id = IDS_CLIPBOARD_INFOBAR_TEXT;
      break;
    case RequestType::kDiskQuota:
      // Handled by an override in `QuotaPermissionRequest`.
      NOTREACHED();
    case RequestType::kFileSystemAccess:
      NOTREACHED();
    case RequestType::kHandTracking:
      message_id = IDS_HAND_TRACKING_INFOBAR_TEXT;
      break;
    case RequestType::kGeolocation: {
      message_id = IDS_GEOLOCATION_INFOBAR_TEXT;
      if (base::FeatureList::IsEnabled(
              content_settings::features::kApproximateGeolocationPermission)) {
        std::optional<GeolocationPromptType> type = GetGeolocationPromptType();
        CHECK(type.has_value());
        switch (*type) {
          case GeolocationPromptType::kApproximateOrPrecise:
            message_id = IDS_GEOLOCATION_INFOBAR_TEXT;
            break;
          case GeolocationPromptType::kApproximateOnly:
            message_id = IDS_GEOLOCATION_APPROXIMATE_INFOBAR_TEXT;
            break;
          case GeolocationPromptType::kUpgradeToPrecise:
            message_id = IDS_GEOLOCATION_UPGRADE_INFOBAR_TEXT;
            break;
          default:
            NOTREACHED();
        }
      }
      break;
    }
    case RequestType::kIdleDetection:
      message_id = IDS_IDLE_DETECTION_INFOBAR_TEXT;
      break;
    case RequestType::kLocalNetwork:
      message_id = IDS_LOCAL_NETWORK_INFOBAR_TEXT;
      break;
    case RequestType::kLoopbackNetwork:
      message_id = IDS_LOOPBACK_NETWORK_INFOBAR_TEXT;
      break;
    case RequestType::kMicStream:
      message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_INFOBAR_TEXT;
      break;
    case RequestType::kMidiSysex:
      message_id = IDS_MIDI_SYSEX_INFOBAR_TEXT;
      break;
    case RequestType::kMultipleDownloads:
      message_id = IDS_MULTI_DOWNLOAD_WARNING;
      break;
    case RequestType::kNfcDevice:
      message_id = IDS_NFC_INFOBAR_TEXT;
      break;
    case RequestType::kNotifications:
      message_id = IDS_NOTIFICATIONS_INFOBAR_TEXT;
      break;
    case RequestType::kSensors:
      message_id = AreGenericSensorExtraClassesEnabled()
                       ? IDS_MOTION_AND_LIGHT_SENSORS_INFOBAR_TEXT
                       : IDS_MOTION_SENSORS_INFOBAR_TEXT;
      break;
#if BUILDFLAG(IS_ANDROID)
    case RequestType::kProtectedMediaIdentifier:
      message_id =
          IDS_PROTECTED_MEDIA_IDENTIFIER_PER_ORIGIN_PROVISIONING_INFOBAR_TEXT;
      break;
#endif  // BUILDFLAG(IS_ANDROID)
    case RequestType::kStorageAccess:
      // The SA prompt does not currently bold any part of its message.
      return AnnotatedMessageText(
          l10n_util::GetStringFUTF16(
              IDS_CONCAT_TWO_STRINGS_WITH_PERIODS,
              l10n_util::GetStringFUTF16(
                  IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_PROMPT_TITLE,
                  requesting_origin_string_formatted),
              l10n_util::GetStringFUTF16(
                  IDS_STORAGE_ACCESS_PERMISSION_TWO_ORIGIN_EXPLANATION,
                  requesting_origin_string_formatted,
                  embedding_origin_string_formatted)),
          /*bolded_ranges=*/{});
    case RequestType::kTopLevelStorageAccess:
      NOTREACHED();
    case RequestType::kVrSession:
      message_id = IDS_VR_INFOBAR_TEXT;
      break;
    case RequestType::kIdentityProvider:
      message_id = IDS_IDENTITY_PROVIDER_INFOBAR_TEXT;
      break;
    case RequestType::kWindowManagement:
      message_id = IDS_WINDOW_MANAGEMENT_INFOBAR_TEXT;
      break;
  }
  DCHECK_NE(0, message_id);

  // Only format origins bold if it's one time allowable or on tablet (which
  // uses a new prompt design on Clank)
  return GetDialogAnnotatedMessageText(
      requesting_origin_string_formatted, message_id, /*format_origin_bold=*/
      ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET ||
          permissions::PermissionUtil::DoesSupportTemporaryGrants(
              GetContentSettingsType()));
}

// static
PermissionRequest::AnnotatedMessageText
PermissionRequest::GetDialogAnnotatedMessageText(
    std::u16string requesting_origin_formatted_for_display,
    int message_id,
    bool format_origin_bold) {
  std::vector<size_t> offsets;
  std::u16string text = l10n_util::GetStringFUTF16(
      message_id, {requesting_origin_formatted_for_display}, &offsets);

  std::vector<std::pair<size_t, size_t>> bolded_ranges;
  if (format_origin_bold) {
    for (auto offset : offsets) {
      bolded_ranges.emplace_back(
          offset, offset + requesting_origin_formatted_for_display.length());
    }
  }

  return AnnotatedMessageText(text, bolded_ranges);
}
#endif  // BUILDFLAG(IS_ANDROID) || BUILDFLAG(IS_IOS)

bool PermissionRequest::IsEmbeddedPermissionElementInitiated() const {
  return data_->IsEmbeddedPermissionElementInitiated();
}

bool PermissionRequest::IsGeolocationElementInitiated() const {
  return data_->IsGeolocationElementInitiated();
}

bool PermissionRequest::IsEligibleForHeuristicAutoGrant() const {
  return data_->IsEligibleForHeuristicAutoGrant();
}

std::optional<gfx::Rect> PermissionRequest::GetAnchorElementPosition() const {
  return data_->GetAnchorElementPosition();
}

#if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)

bool PermissionRequest::IsConfirmationChipSupported() {
  return permissions::IsConfirmationChipSupported(request_type());
}

IconId PermissionRequest::GetIconForChip() {
  return permissions::GetIconId(request_type());
}

IconId PermissionRequest::GetBlockedIconForChip() {
  return permissions::GetBlockedIconId(request_type());
}

std::optional<std::u16string> PermissionRequest::GetRequestChipText(
    ChipTextType type) const {
  static base::NoDestructor<std::map<RequestType, std::vector<int>>> kMessageIds(
      {{RequestType::kArSession,
        {IDS_AR_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_AR_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_AR_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_AR_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kCameraStream,
        {IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_CAMERA_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_CAMERA_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_CAMERA_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kCapturedSurfaceControl,
        {IDS_CAPTURED_SURFACE_CONTROL_PERMISSION_CHIP,
         IDS_CAPTURED_SURFACE_CONTROL_PERMISSION_BLOCKED_CHIP,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_CAPTURED_SURFACE_CONTROL_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_CAPTURED_SURFACE_CONTROL_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kClipboard,
        {IDS_CLIPBOARD_PERMISSION_CHIP, -1, -1, -1, -1, -1, -1, -1}},
       {RequestType::kGeolocation,
        {IDS_GEOLOCATION_PERMISSION_CHIP,
         IDS_GEOLOCATION_PERMISSION_BLOCKED_CHIP,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_GEOLOCATION_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_GEOLOCATION_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kHandTracking,
        {IDS_HAND_TRACKING_PERMISSION_CHIP,
         IDS_HAND_TRACKING_PERMISSION_BLOCKED_CHIP,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_HAND_TRACKING_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_HAND_TRACKING_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_HAND_TRACKING_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kIdleDetection,
        {IDS_IDLE_DETECTION_PERMISSION_CHIP, -1, -1, -1, -1, -1, -1, -1}},
       {RequestType::kKeyboardLock,
        {IDS_KEYBOARD_LOCK_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_KEYBOARD_LOCK_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_KEYBOARD_LOCK_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kMicStream,
        {IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_MICROPHONE_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_MICROPHONE_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_MICROPHONE_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kMidiSysex,
        {IDS_MIDI_SYSEX_PERMISSION_CHIP, -1, -1, -1, -1, -1, -1, -1}},
       {RequestType::kNotifications,
        {IDS_NOTIFICATION_PERMISSIONS_CHIP,
         IDS_NOTIFICATION_PERMISSIONS_BLOCKED_CHIP,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION, -1,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_NOTIFICATION_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         -1,
         IDS_PERMISSIONS_NOTIFICATION_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kPointerLock,
        {IDS_POINTER_LOCK_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_POINTER_LOCK_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_POINTER_LOCK_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kSensors,
        {AreGenericSensorExtraClassesEnabled()
             ? IDS_MOTION_AND_LIGHT_SENSORS_PERMISSION_CHIP
             : IDS_MOTION_SENSORS_PERMISSION_CHIP,
         -1 /* QUIET_REQUEST not supported */,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         AreGenericSensorExtraClassesEnabled()
             ? IDS_PERMISSIONS_MOTION_AND_LIGHT_SENSORS_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT
             : IDS_PERMISSIONS_MOTION_SENSORS_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         AreGenericSensorExtraClassesEnabled()
             ? IDS_PERMISSIONS_MOTION_AND_LIGHT_SENSORS_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT
             : IDS_PERMISSIONS_MOTION_SENSORS_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         AreGenericSensorExtraClassesEnabled()
             ? IDS_PERMISSIONS_MOTION_AND_LIGHT_SENSORS_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT
             : IDS_PERMISSIONS_MOTION_SENSORS_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kStorageAccess,
        {IDS_SAA_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION, -1,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_SAA_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT, -1,
         IDS_PERMISSIONS_SAA_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kVrSession,
        {IDS_VR_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_VR_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_VR_ALLOWED_ONCE_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_VR_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}},
       {RequestType::kWebAppInstallation,
        {IDS_WEB_APP_INSTALLATION_PERMISSION_CHIP, -1,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_PERMISSION_NOT_ALLOWED_CONFIRMATION,
         IDS_PERMISSIONS_WEB_INSTALL_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT,
         IDS_PERMISSIONS_PERMISSION_ALLOWED_ONCE_CONFIRMATION,
         IDS_PERMISSIONS_WEB_INSTALL_NOT_ALLOWED_CONFIRMATION_SCREENREADER_ANNOUNCEMENT}}});

  auto messages = kMessageIds->find(request_type());
  if (messages != kMessageIds->end() && messages->second[type] != -1) {
    return l10n_util::GetStringUTF16(messages->second[type]);
  }

  return std::nullopt;
}

std::u16string PermissionRequest::GetMessageTextFragment() const {
  int message_id = 0;
  switch (request_type()) {
    case RequestType::kArSession:
      message_id = IDS_AR_PERMISSION_FRAGMENT;
      break;
    case RequestType::kCameraPanTiltZoom:
      message_id = IDS_MEDIA_CAPTURE_CAMERA_PAN_TILT_ZOOM_PERMISSION_FRAGMENT;
      break;
    case RequestType::kCameraStream:
      message_id = IDS_MEDIA_CAPTURE_VIDEO_ONLY_PERMISSION_FRAGMENT;
      break;
    case RequestType::kCapturedSurfaceControl:
      message_id = IDS_CAPTURED_SURFACE_CONTROL_PERMISSION_FRAGMENT;
      break;
    case RequestType::kClipboard:
      message_id = IDS_CLIPBOARD_PERMISSION_FRAGMENT;
      break;
    case RequestType::kDiskQuota:
      message_id = IDS_REQUEST_QUOTA_PERMISSION_FRAGMENT;
      break;
    case RequestType::kFileSystemAccess:
      message_id = IDS_SITE_SETTINGS_TYPE_FILE_SYSTEM_ACCESS_WRITE;
      break;
    case RequestType::kGeolocation:
      message_id = IDS_GEOLOCATION_INFOBAR_PERMISSION_FRAGMENT;
      break;
    case RequestType::kHandTracking:
      message_id = IDS_HAND_TRACKING_PERMISSION_FRAGMENT;
      break;
    case RequestType::kIdleDetection:
      message_id = IDS_IDLE_DETECTION_PERMISSION_FRAGMENT;
      break;
    case RequestType::kKeyboardLock:
      message_id = IDS_KEYBOARD_LOCK_PERMISSIONS_FRAGMENT;
      break;
    case RequestType::kLocalFonts:
      message_id = IDS_FONT_ACCESS_PERMISSION_FRAGMENT;
      break;
    case RequestType::kLocalNetwork:
      message_id = IDS_LOCAL_NETWORK_PERMISSION_FRAGMENT;
      break;
    case RequestType::kLoopbackNetwork:
      message_id = IDS_LOOPBACK_NETWORK_PERMISSION_FRAGMENT;
      break;
    case RequestType::kMicStream:
      message_id = IDS_MEDIA_CAPTURE_AUDIO_ONLY_PERMISSION_FRAGMENT;
      break;
    case RequestType::kMidiSysex:
      message_id = IDS_MIDI_SYSEX_PERMISSION_FRAGMENT;
      break;
    case RequestType::kMultipleDownloads:
      message_id = IDS_MULTI_DOWNLOAD_PERMISSION_FRAGMENT;
      break;
    case RequestType::kNotifications:
      message_id = IDS_NOTIFICATION_PERMISSIONS_FRAGMENT;
      break;
    case RequestType::kSensors:
      message_id = AreGenericSensorExtraClassesEnabled()
                       ? IDS_MOTION_AND_LIGHT_SENSORS_PERMISSION_FRAGMENT
                       : IDS_MOTION_SENSORS_PERMISSION_FRAGMENT;
      break;
    case RequestType::kPointerLock:
      message_id = IDS_POINTER_LOCK_PERMISSIONS_FRAGMENT;
      break;
#if BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_WIN)
    case RequestType::kProtectedMediaIdentifier:
      message_id = IDS_PROTECTED_MEDIA_IDENTIFIER_PERMISSION_FRAGMENT;
      break;
#endif
    case RequestType::kRegisterProtocolHandler:
      // Handled by an override in `RegisterProtocolHandlerPermissionRequest`.
      NOTREACHED();
#if BUILDFLAG(IS_CHROMEOS)
    case RequestType::kSmartCard:
      // Handled by an override in `SmartCardPermissionRequest`.
      NOTREACHED();
#endif
    case RequestType::kStorageAccess:
    case RequestType::kTopLevelStorageAccess:
      message_id = IDS_STORAGE_ACCESS_PERMISSION_FRAGMENT;
      break;
    case RequestType::kVrSession:
      message_id = IDS_VR_PERMISSION_FRAGMENT;
      break;
    case RequestType::kWebAppInstallation:
      message_id = IDS_WEB_APP_INSTALLATION_PERMISSION_FRAGMENT;
      break;
#if BUILDFLAG(IS_CHROMEOS) && BUILDFLAG(USE_CUPS)
    case RequestType::kWebPrinting:
      message_id = IDS_WEB_PRINTING_PERMISSION_FRAGMENT;
      break;
#endif
    case RequestType::kWindowManagement:
      message_id = IDS_WINDOW_MANAGEMENT_PERMISSION_FRAGMENT;
      break;
    case RequestType::kIdentityProvider:
      message_id = IDS_IDENTITY_PROVIDER_PERMISSION_FRAGMENT;
      break;
  }
  DCHECK_NE(0, message_id);
  return l10n_util::GetStringUTF16(message_id);
}
#endif  // !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS)

std::optional<std::u16string> PermissionRequest::GetAllowAlwaysText() const {
  return std::nullopt;
}

std::optional<std::u16string> PermissionRequest::GetBlockText() const {
  return std::nullopt;
}

bool PermissionRequest::ShouldUseTwoOriginPrompt() const {
  return request_type() == RequestType::kStorageAccess;
}

std::optional<GeolocationPromptType>
PermissionRequest::GetGeolocationPromptType() const {
  return data_->geolocation_prompt_type;
}

void PermissionRequest::PermissionGranted(const PromptOptions& prompt_options,
                                          bool is_one_time) {
  std::move(permission_decided_callback_)
      .Run(PermissionPromptDecision{.overall_decision =
                                        is_one_time
                                            ? PermissionDecision::kAllowThisTime
                                            : PermissionDecision::kAllow,
                                    .prompt_options = prompt_options,
                                    .is_final = true},
           /*request_data=*/*data_);
}

void PermissionRequest::PermissionDenied() {
  std::move(permission_decided_callback_)
      .Run(PermissionPromptDecision{.overall_decision =
                                        PermissionDecision::kDeny,
                                    .prompt_options = std::monostate(),
                                    .is_final = true},
           /*request_data=*/*data_);
}

void PermissionRequest::Cancelled(bool is_final_decision) {
  if (permission_decided_callback_) {
    permission_decided_callback_.Run(
        PermissionPromptDecision{.overall_decision = PermissionDecision::kNone,
                                 .prompt_options = std::monostate(),
                                 .is_final = is_final_decision},
        /*request_data=*/*data_);
  }
}

PermissionRequestGestureType PermissionRequest::GetGestureType() const {
  return PermissionUtil::GetGestureType(data_->user_gesture);
}

const std::vector<std::string>&
PermissionRequest::GetRequestedAudioCaptureDeviceIds() const {
  return data_->requested_audio_capture_device_ids;
}

const std::vector<std::string>&
PermissionRequest::GetRequestedVideoCaptureDeviceIds() const {
  return data_->requested_video_capture_device_ids;
}

ContentSettingsType PermissionRequest::GetContentSettingsType() const {
  auto type = RequestTypeToContentSettingsType(request_type());
  if (type.has_value()) {
    return type.value();
  }
  return ContentSettingsType::DEFAULT;
}

std::u16string PermissionRequest::GetPermissionNameTextFragment() const {
  int message_id = 0;
  switch (request_type()) {
    case RequestType::kCameraStream:
      message_id = IDS_CAMERA_PERMISSION_NAME_FRAGMENT;
      break;
    case RequestType::kGeolocation:
      message_id = IDS_GEOLOCATION_NAME_FRAGMENT;
      break;
    case RequestType::kMicStream:
      message_id = IDS_MICROPHONE_PERMISSION_NAME_FRAGMENT;
      break;
    default:
      NOTREACHED();
  }
  DCHECK_NE(0, message_id);
  return l10n_util::GetStringUTF16(message_id);
}

void PermissionRequest::SetEmbeddedPermissionElementInitiatedForTesting(
    bool embedded_permission_element_initiated) {
  if (embedded_permission_element_initiated) {
    data_->embedded_permission_request_descriptor =
        blink::mojom::EmbeddedPermissionRequestDescriptor::New();
  }
}

bool PermissionRequest::IsSourceSubscribedToPermissionChangeEvent(
    content::PermissionController* controller) const {
  DCHECK(controller);
  content::RenderFrameHost* rfh =
      content::RenderFrameHost::FromID(get_requesting_frame_id());

  if (rfh == nullptr) {
    return false;
  }

  blink::PermissionType permission_type =
      permissions::PermissionUtil::ContentSettingsTypeToPermissionType(
          GetContentSettingsType());

  return controller->IsSubscribedToPermissionChangeEvent(permission_type, rfh);
}

}  // namespace permissions
