// 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/ash/shimless_rma/chrome_shimless_rma_delegate.h"
#include <string>
#include <utility>
#include "ash/constants/ash_features.h"
#include "ash/constants/ash_switches.h"
#include "base/check.h"
#include "base/command_line.h"
#include "base/containers/span.h"
#include "base/debug/crash_logging.h"
#include "base/debug/dump_without_crashing.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/ash/accessibility/accessibility_manager.h"
#include "chrome/browser/ash/login/chrome_restart_request.h"
#include "chrome/browser/ash/shimless_rma/diagnostics_app_profile_helper.h"
#include "chrome/browser/ash/system/device_disabling_manager.h"
#include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h"
#include "chrome/browser/ui/webui/ash/diagnostics_dialog.h"
#include "chrome/common/chromeos/extensions/chromeos_system_extension_info.h"
#include "components/qr_code_generator/bitmap_generator.h"
#include "content/public/browser/web_ui.h"
#include "extensions/common/extension.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/image/image_skia.h"
namespace ash {
namespace shimless_rma {
ChromeShimlessRmaDelegate::ChromeShimlessRmaDelegate(content::WebUI* web_ui) {}
ChromeShimlessRmaDelegate::~ChromeShimlessRmaDelegate() = default;
void ChromeShimlessRmaDelegate::ExitRmaThenRestartChrome() {
const base::CommandLine& browser_command_line =
*base::CommandLine::ForCurrentProcess();
base::CommandLine command_line(browser_command_line);
command_line.AppendSwitch(::ash::switches::kRmaNotAllowed);
// Remove any attempts to launch RMA.
command_line.RemoveSwitch(::ash::switches::kLaunchRma);
ash::RestartChrome(command_line, ash::RestartChromeReason::kUserless);
}
void ChromeShimlessRmaDelegate::ShowDiagnosticsDialog() {
// Don't launch Diagnostics if device is disabled.
if (system::DeviceDisablingManager::IsDeviceDisabledDuringNormalOperation()) {
return;
}
DiagnosticsDialog::ShowDialog();
}
void ChromeShimlessRmaDelegate::RefreshAccessibilityManagerProfile() {
AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
DCHECK(accessibility_manager);
accessibility_manager->OnShimlessRmaLaunched();
}
void ChromeShimlessRmaDelegate::GenerateQrCode(
const std::string& url,
base::OnceCallback<void(const std::string& qr_code_image)> callback) {
// TODO(https://crbug.com/325664342): Audit if `QuietZone::kIncluded`
// can/should be used instead (this may require testing if the different image
// size works well with surrounding UI elements). Note that the absence of a
// quiet zone may interfere with decoding of QR codes even for small codes
// (for examples see #comment8, #comment9 and #comment6 in the bug).
auto response = qr_code_generator::GenerateBitmap(
base::as_byte_span(url), qr_code_generator::ModuleStyle::kSquares,
qr_code_generator::LocatorStyle::kSquare,
qr_code_generator::CenterImage::kDino,
qr_code_generator::QuietZone::kWillBeAddedByClient);
// The inputs are controlled/generated by our code - they cannot trigger a QR
// generation error (e.g. they can't trigger input-too-long error). OTOH we
// don't want to introduce unnecessary risk into the RMA flow, so let's handle
// this situation gracefully by returning empty data/string/image.
DCHECK(response.has_value()) << "url: " << url;
if (response.has_value()) {
std::vector<unsigned char> bytes;
gfx::PNGCodec::EncodeBGRASkBitmap(response.value(), false, &bytes);
std::move(callback).Run(std::string(bytes.begin(), bytes.end()));
} else {
SCOPED_CRASH_KEY_STRING1024("RMA", "QRCodeGeneration", url);
base::debug::DumpWithoutCrashing();
std::move(callback).Run(std::string());
}
}
void ChromeShimlessRmaDelegate::PrepareDiagnosticsAppBrowserContext(
const base::FilePath& crx_path,
const base::FilePath& swbn_path,
PrepareDiagnosticsAppBrowserContextCallback callback) {
CHECK(::ash::features::IsShimlessRMA3pDiagnosticsEnabled());
PrepareDiagnosticsAppProfile(diagnostics_app_profile_helper_delegete_ptr_,
crx_path, swbn_path, std::move(callback));
}
bool ChromeShimlessRmaDelegate::IsChromeOSSystemExtensionProvider(
const std::string& manufacturer) {
return chromeos::IsChromeOSSystemExtensionProvider(manufacturer);
}
void ChromeShimlessRmaDelegate::ProcessMediaAccessRequest(
content::WebContents* web_contents,
const content::MediaStreamRequest& request,
content::MediaResponseCallback callback,
const extensions::Extension* extension) {
MediaCaptureDevicesDispatcher::GetInstance()->ProcessMediaAccessRequest(
web_contents, request, std::move(callback), extension);
}
base::WeakPtr<ShimlessRmaDelegate> ChromeShimlessRmaDelegate::GetWeakPtr() {
return weak_ptr_factory_.GetWeakPtr();
}
void ChromeShimlessRmaDelegate::
SetDiagnosticsAppProfileHelperDelegateForTesting(
DiagnosticsAppProfileHelperDelegate* delegate) {
diagnostics_app_profile_helper_delegete_ptr_ = delegate;
}
} // namespace shimless_rma
} // namespace ash