blob: 31010b7066fb075eaa994599fbd811074810754e [file] [log] [blame]
// Copyright 2016 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.
#include "chrome/browser/ash/arc/arc_support_host.h"
#include <string>
#include <utility>
#include <vector>
#include "ash/constants/ash_features.h"
#include "base/bind.h"
#include "base/hash/sha1.h"
#include "base/i18n/timezone.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/threading/thread_task_runner_handle.h"
#include "base/values.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/browser_app_launcher.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/consent_auditor/consent_auditor_factory.h"
#include "chrome/browser/extensions/extension_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
#include "chrome/browser/ui/ash/multi_user/multi_user_util.h"
#include "chrome/browser/ui/chrome_pages.h"
#include "chrome/browser/ui/extensions/app_launch_params.h"
#include "chrome/browser/ui/webui/chromeos/diagnostics_dialog.h"
#include "chrome/common/webui_url_constants.h"
#include "chrome/grit/generated_resources.h"
#include "components/consent_auditor/consent_auditor.h"
#include "components/signin/public/base/consent_level.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "components/user_manager/known_user.h"
#include "components/user_manager/user_manager.h"
#include "extensions/browser/app_window/app_window.h"
#include "extensions/browser/app_window/app_window_registry.h"
#include "extensions/browser/extension_registry.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h"
#include "ui/chromeos/devicetype_utils.h"
#include "ui/gfx/native_widget_types.h"
using sync_pb::UserConsentTypes;
namespace {
constexpr char kAction[] = "action";
constexpr char kArcManaged[] = "arcManaged";
constexpr char kData[] = "data";
constexpr char kDeviceId[] = "deviceId";
constexpr char kActionInitialize[] = "initialize";
constexpr char kActionSetMetricsMode[] = "setMetricsMode";
constexpr char kActionBackupAndRestoreMode[] = "setBackupAndRestoreMode";
constexpr char kActionLocationServiceMode[] = "setLocationServiceMode";
constexpr char kActionSetWindowBounds[] = "setWindowBounds";
constexpr char kActionCloseWindow[] = "closeWindow";
// Action to show a page. The message should have "page" field, which is one of
// IDs for section div elements. For the "active-directory-auth" page, the
// "federationUrl" and "deviceManagementUrlPrefix" options are required.
constexpr char kActionShowPage[] = "showPage";
constexpr char kPage[] = "page";
constexpr char kOptions[] = "options";
constexpr char kFederationUrl[] = "federationUrl";
constexpr char kDeviceManagementUrlPrefix[] = "deviceManagementUrlPrefix";
// Action to show the error page. The message should have "errorMessage",
// which is a localized error text, and "shouldShowSendFeedback" boolean value.
constexpr char kActionShowErrorPage[] = "showErrorPage";
constexpr char kErrorMessage[] = "errorMessage";
constexpr char kShouldShowSendFeedback[] = "shouldShowSendFeedback";
constexpr char kShouldShowNetworkTests[] = "shouldShowNetworkTests";
// The preference update should have those two fields.
constexpr char kEnabled[] = "enabled";
constexpr char kManaged[] = "managed";
// The JSON data sent from the extension should have at least "event" field.
// Each event data is defined below.
// The key of the event type.
constexpr char kEvent[] = "event";
// "onWindowClosed" is fired when the extension window is closed.
// No data will be provided.
constexpr char kEventOnWindowClosed[] = "onWindowClosed";
// "onAuthSucceeded" is fired when Active Directory authentication succeeds.
constexpr char kEventOnAuthSucceeded[] = "onAuthSucceeded";
// "onAuthFailed" is fired when Active Directory authentication failed.
constexpr char kEventOnAuthFailed[] = "onAuthFailed";
constexpr char kAuthErrorMessage[] = "errorMessage";
// "onAgreed" is fired when a user clicks "Agree" button.
// The message should have the following fields:
// - tosContent
// - tosShown
// - isMetricsEnabled
// - isBackupRestoreEnabled
// - isBackupRestoreManaged
// - isLocationServiceEnabled
// - isLocationServiceManaged
constexpr char kEventOnAgreed[] = "onAgreed";
constexpr char kTosContent[] = "tosContent";
constexpr char kTosShown[] = "tosShown";
constexpr char kIsMetricsEnabled[] = "isMetricsEnabled";
constexpr char kIsBackupRestoreEnabled[] = "isBackupRestoreEnabled";
constexpr char kIsBackupRestoreManaged[] = "isBackupRestoreManaged";
constexpr char kIsLocationServiceEnabled[] = "isLocationServiceEnabled";
constexpr char kIsLocationServiceManaged[] = "isLocationServiceManaged";
// "onCanceled" is fired when user clicks "Cancel" button.
// The message should have the same fields as "onAgreed" above.
constexpr char kEventOnCanceled[] = "onCanceled";
// "onRetryClicked" is fired when a user clicks "RETRY" button on the error
// page.
constexpr char kEventOnRetryClicked[] = "onRetryClicked";
// "onSendFeedbackClicked" is fired when a user clicks "Send Feedback" button.
constexpr char kEventOnSendFeedbackClicked[] = "onSendFeedbackClicked";
// "onRunNetworkTestsClicked" is fired when a user clicks "Check Network"
// button.
constexpr char kEventOnRunNetworkTestsClicked[] = "onRunNetworkTestsClicked";
// "onOpenPrivacySettingsPageClicked" is fired when a user clicks privacy
// settings link.
constexpr char kEventOnOpenPrivacySettingsPageClicked[] =
"onOpenPrivacySettingsPageClicked";
void RequestOpenApp(Profile* profile) {
const extensions::Extension* extension =
extensions::ExtensionRegistry::Get(profile)->GetInstalledExtension(
arc::kPlayStoreAppId);
DCHECK(extension);
DCHECK(extensions::util::IsAppLaunchable(arc::kPlayStoreAppId, profile));
apps::AppServiceProxyFactory::GetForProfile(profile)
->BrowserAppLauncher()
->LaunchAppWithParams(CreateAppLaunchParamsUserContainer(
profile, extension, WindowOpenDisposition::NEW_WINDOW,
apps::mojom::LaunchSource::kFromChromeInternal));
}
std::ostream& operator<<(std::ostream& os, ArcSupportHost::UIPage ui_page) {
switch (ui_page) {
case ArcSupportHost::UIPage::NO_PAGE:
return os << "NO_PAGE";
case ArcSupportHost::UIPage::TERMS:
return os << "TERMS";
case ArcSupportHost::UIPage::ARC_LOADING:
return os << "ARC_LOADING";
case ArcSupportHost::UIPage::ACTIVE_DIRECTORY_AUTH:
return os << "ACTIVE_DIRECTORY_AUTH";
case ArcSupportHost::UIPage::ERROR:
return os << "ERROR";
}
// Some compiler reports an error even if all values of an enum-class are
// covered individually in a switch statement.
NOTREACHED();
return os;
}
std::ostream& operator<<(std::ostream& os, ArcSupportHost::Error error) {
#define MAP_ERROR(name) \
case ArcSupportHost::Error::name: \
return os << #name
switch (error) {
MAP_ERROR(SIGN_IN_NETWORK_ERROR);
MAP_ERROR(SIGN_IN_GMS_SIGNIN_ERROR);
MAP_ERROR(SIGN_IN_BAD_AUTHENTICATION_ERROR);
MAP_ERROR(SIGN_IN_GMS_CHECKIN_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR);
MAP_ERROR(SIGN_IN_UNKNOWN_ERROR);
MAP_ERROR(SERVER_COMMUNICATION_ERROR);
MAP_ERROR(ANDROID_MANAGEMENT_REQUIRED_ERROR);
MAP_ERROR(NETWORK_UNAVAILABLE_ERROR);
MAP_ERROR(LOW_DISK_SPACE_ERROR);
}
#undef MAP_ERROR
// Some compiler reports an error even if all values of an enum-class are
// covered individually in a switch statement.
NOTREACHED();
return os;
}
} // namespace
ArcSupportHost::ErrorInfo::ErrorInfo(Error error)
: error(error), arg(absl::nullopt) {}
ArcSupportHost::ErrorInfo::ErrorInfo(Error error,
const absl::optional<int>& arg)
: error(error), arg(arg) {}
ArcSupportHost::ErrorInfo::ErrorInfo(const ErrorInfo&) = default;
ArcSupportHost::ErrorInfo& ArcSupportHost::ErrorInfo::operator=(
const ArcSupportHost::ErrorInfo&) = default;
ArcSupportHost::ArcSupportHost(Profile* profile)
: profile_(profile),
request_open_app_callback_(base::BindRepeating(&RequestOpenApp)) {
DCHECK(profile_);
}
ArcSupportHost::~ArcSupportHost() {
// Delegates should have been reset to nullptr at this point.
DCHECK(!auth_delegate_);
DCHECK(!tos_delegate_);
DCHECK(!error_delegate_);
if (message_host_)
DisconnectMessageHost();
}
void ArcSupportHost::SetAuthDelegate(AuthDelegate* delegate) {
// Since AuthDelegate and TermsOfServiceDelegate should not have overlapping
// life cycle, both delegates can't be non-null at the same time.
DCHECK(!(delegate && tos_delegate_));
auth_delegate_ = delegate;
}
void ArcSupportHost::SetTermsOfServiceDelegate(
TermsOfServiceDelegate* delegate) {
// Since AuthDelegate and TermsOfServiceDelegate should not have overlapping
// life cycle, both delegates can't be non-null at the same time.
DCHECK(!(delegate && auth_delegate_));
tos_delegate_ = delegate;
}
void ArcSupportHost::SetErrorDelegate(ErrorDelegate* delegate) {
error_delegate_ = delegate;
}
gfx::NativeWindow ArcSupportHost::GetNativeWindow() const {
extensions::AppWindowRegistry* registry =
extensions::AppWindowRegistry::Get(profile_);
if (!registry) return gfx::kNullNativeWindow;
extensions::AppWindow* window =
registry->GetCurrentAppWindowForApp(arc::kPlayStoreAppId);
return window ? window->GetNativeWindow() : gfx::kNullNativeWindow;
}
bool ArcSupportHost::GetShouldShowRunNetworkTests() {
return should_show_run_network_tests_;
}
void ArcSupportHost::SetArcManaged(bool is_arc_managed) {
DCHECK(!message_host_ || (is_arc_managed_ == is_arc_managed));
is_arc_managed_ = is_arc_managed;
}
void ArcSupportHost::Close() {
ui_page_ = UIPage::NO_PAGE;
if (!message_host_) {
VLOG(2) << "ArcSupportHost::Close() is called "
<< "but message_host_ is not available.";
return;
}
base::DictionaryValue message;
message.SetStringKey(kAction, kActionCloseWindow);
message_host_->SendMessage(message);
// Disconnect immediately, so that onWindowClosed event will not be
// delivered to here.
DisconnectMessageHost();
}
void ArcSupportHost::ShowTermsOfService() {
ShowPage(UIPage::TERMS);
}
void ArcSupportHost::ShowArcLoading() {
ShowPage(UIPage::ARC_LOADING);
}
void ArcSupportHost::ShowActiveDirectoryAuth(
const GURL& federation_url,
const std::string& device_management_url_prefix) {
active_directory_auth_federation_url_ = federation_url;
active_directory_auth_device_management_url_prefix_ =
device_management_url_prefix;
ShowPage(UIPage::ACTIVE_DIRECTORY_AUTH);
}
void ArcSupportHost::ShowPage(UIPage ui_page) {
ui_page_ = ui_page;
if (!message_host_) {
if (app_start_pending_) {
VLOG(2) << "ArcSupportHost::ShowPage(" << ui_page << ") is called "
<< "before connection to ARC support Chrome app has finished "
<< "establishing.";
return;
}
RequestAppStart();
return;
}
base::DictionaryValue message;
message.SetStringKey(kAction, kActionShowPage);
switch (ui_page) {
case UIPage::TERMS:
message.SetStringKey(kPage, "terms");
break;
case UIPage::ARC_LOADING:
message.SetStringKey(kPage, "arc-loading");
break;
case UIPage::ACTIVE_DIRECTORY_AUTH:
DCHECK(active_directory_auth_federation_url_.is_valid());
DCHECK(!active_directory_auth_device_management_url_prefix_.empty());
message.SetStringKey(kPage, "active-directory-auth");
message.SetPath(
{kOptions, kFederationUrl},
base::Value(active_directory_auth_federation_url_.spec()));
message.SetPath(
{kOptions, kDeviceManagementUrlPrefix},
base::Value(active_directory_auth_device_management_url_prefix_));
break;
default:
NOTREACHED();
return;
}
message_host_->SendMessage(message);
}
void ArcSupportHost::ShowError(ErrorInfo error_info,
bool should_show_send_feedback,
bool should_show_run_network_tests) {
ui_page_ = UIPage::ERROR;
error_info_.emplace(error_info);
should_show_send_feedback_ = should_show_send_feedback;
should_show_run_network_tests_ = should_show_run_network_tests;
if (!message_host_) {
if (app_start_pending_) {
VLOG(2) << "ArcSupportHost::ShowError(" << error_info.error << ", "
<< error_info.arg.value_or(-1) << ", "
<< should_show_send_feedback << ", "
<< should_show_run_network_tests
<< ") is called before connection "
<< "to ARC support Chrome app is established.";
return;
}
RequestAppStart();
return;
}
base::DictionaryValue message_args;
message_args.SetStringKey(kAction, kActionShowErrorPage);
int message_id;
#define MAP_ERROR(name, id) \
case Error::name: \
message_id = id; \
break
switch (error_info.error) {
MAP_ERROR(SIGN_IN_NETWORK_ERROR, IDS_ARC_SIGN_IN_NETWORK_ERROR);
MAP_ERROR(SIGN_IN_GMS_SIGNIN_ERROR, IDS_ARC_SIGN_IN_GMS_SIGNIN_ERROR);
MAP_ERROR(SIGN_IN_BAD_AUTHENTICATION_ERROR,
IDS_ARC_SIGN_IN_BAD_AUTHENTICATION_ERROR);
MAP_ERROR(SIGN_IN_GMS_CHECKIN_ERROR, IDS_ARC_SIGN_IN_GMS_CHECKIN_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR);
MAP_ERROR(SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR,
IDS_ARC_SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR);
MAP_ERROR(SIGN_IN_UNKNOWN_ERROR, IDS_ARC_SIGN_IN_UNKNOWN_ERROR);
MAP_ERROR(SERVER_COMMUNICATION_ERROR, IDS_ARC_SERVER_COMMUNICATION_ERROR);
MAP_ERROR(ANDROID_MANAGEMENT_REQUIRED_ERROR,
IDS_ARC_ANDROID_MANAGEMENT_REQUIRED_ERROR);
MAP_ERROR(NETWORK_UNAVAILABLE_ERROR, IDS_ARC_NETWORK_UNAVAILABLE_ERROR);
MAP_ERROR(LOW_DISK_SPACE_ERROR, IDS_ARC_LOW_DISK_SPACE_ERROR);
}
#undef MAP_ERROR
std::u16string message;
switch (error_info.error) {
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_ACCOUNT_MISSING_ERROR:
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_DOMAIN_JOIN_FAIL_ERROR:
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_ENROLLMENT_TOKEN_INVALID:
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_INTERRUPTED_ERROR:
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_NETWORK_ERROR:
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_PERMANENT_ERROR:
case Error::SIGN_IN_CLOUD_PROVISION_FLOW_TRANSIENT_ERROR:
case Error::SIGN_IN_GMS_SIGNIN_ERROR:
case Error::SIGN_IN_GMS_CHECKIN_ERROR:
case Error::SIGN_IN_UNKNOWN_ERROR:
DCHECK(error_info.arg);
message = l10n_util::GetStringFUTF16(
message_id, base::NumberToString16(error_info.arg.value()));
break;
default:
message = l10n_util::GetStringUTF16(message_id);
break;
}
message_args.SetStringKey(kErrorMessage, message);
message_args.SetBoolean(kShouldShowSendFeedback, should_show_send_feedback);
message_args.SetBoolean(
kShouldShowNetworkTests,
should_show_run_network_tests &&
ash::features::IsArcNetworkDiagnosticsButtonEnabled());
message_host_->SendMessage(message_args);
}
void ArcSupportHost::SetMetricsPreferenceCheckbox(bool is_enabled,
bool is_managed) {
metrics_checkbox_ = PreferenceCheckboxData(is_enabled, is_managed);
SendPreferenceCheckboxUpdate(kActionSetMetricsMode, metrics_checkbox_);
}
void ArcSupportHost::SetBackupAndRestorePreferenceCheckbox(bool is_enabled,
bool is_managed) {
backup_and_restore_checkbox_ = PreferenceCheckboxData(is_enabled, is_managed);
SendPreferenceCheckboxUpdate(kActionBackupAndRestoreMode,
backup_and_restore_checkbox_);
}
void ArcSupportHost::SetLocationServicesPreferenceCheckbox(bool is_enabled,
bool is_managed) {
location_services_checkbox_ = PreferenceCheckboxData(is_enabled, is_managed);
SendPreferenceCheckboxUpdate(kActionLocationServiceMode,
location_services_checkbox_);
}
void ArcSupportHost::SendPreferenceCheckboxUpdate(
const std::string& action_name,
const PreferenceCheckboxData& data) {
if (!message_host_)
return;
base::DictionaryValue message;
message.SetStringKey(kAction, action_name);
message.SetBoolean(kEnabled, data.is_enabled);
message.SetBoolean(kManaged, data.is_managed);
message_host_->SendMessage(message);
}
void ArcSupportHost::SetMessageHost(arc::ArcSupportMessageHost* message_host) {
if (message_host_ == message_host)
return;
app_start_pending_ = false;
if (message_host_)
DisconnectMessageHost();
message_host_ = message_host;
message_host_->SetObserver(this);
display_observer_.emplace(this);
if (!Initialize()) {
Close();
return;
}
// Hereafter, install the requested ui state into the ARC support Chrome app.
// Set preference checkbox state.
SendPreferenceCheckboxUpdate(kActionSetMetricsMode, metrics_checkbox_);
SendPreferenceCheckboxUpdate(kActionBackupAndRestoreMode,
backup_and_restore_checkbox_);
SendPreferenceCheckboxUpdate(kActionLocationServiceMode,
location_services_checkbox_);
if (ui_page_ == UIPage::NO_PAGE) {
// Close() is called before opening the window.
Close();
} else if (ui_page_ == UIPage::ERROR) {
DCHECK(error_info_);
ShowError(error_info_.value(), should_show_send_feedback_,
should_show_run_network_tests_);
} else {
ShowPage(ui_page_);
}
}
void ArcSupportHost::UnsetMessageHost(
arc::ArcSupportMessageHost* message_host) {
if (message_host_ != message_host)
return;
DisconnectMessageHost();
}
void ArcSupportHost::DisconnectMessageHost() {
DCHECK(message_host_);
display_observer_.reset();
message_host_->SetObserver(nullptr);
message_host_ = nullptr;
}
void ArcSupportHost::RequestAppStart() {
DCHECK(!message_host_);
DCHECK(!app_start_pending_);
app_start_pending_ = true;
request_open_app_callback_.Run(profile_);
}
void ArcSupportHost::SetRequestOpenAppCallbackForTesting(
const RequestOpenAppCallback& callback) {
DCHECK(!message_host_);
DCHECK(!app_start_pending_);
DCHECK(!callback.is_null());
request_open_app_callback_ = callback;
}
bool ArcSupportHost::Initialize() {
DCHECK(message_host_);
const bool is_child =
user_manager::UserManager::Get()->IsLoggedInAsChildUser();
base::DictionaryValue loadtime_data;
loadtime_data.SetStringKey(
"appWindow",
l10n_util::GetStringUTF16(IDS_ARC_PLAYSTORE_ICON_TITLE_BETA));
loadtime_data.SetStringKey(
"greetingHeader", l10n_util::GetStringUTF16(IDS_ARC_OOBE_TERMS_HEADING));
loadtime_data.SetStringKey(
"initializingHeader",
l10n_util::GetStringUTF16(IDS_ARC_PLAYSTORE_SETTING_UP_TITLE));
loadtime_data.SetStringKey(
"greetingDescription",
l10n_util::GetStringUTF16(IDS_ARC_OOBE_TERMS_DESCRIPTION));
loadtime_data.SetStringKey(
"buttonAgree",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE));
loadtime_data.SetStringKey(
"buttonCancel",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BUTTON_CANCEL));
loadtime_data.SetStringKey(
"buttonNext",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BUTTON_NEXT));
loadtime_data.SetStringKey(
"buttonSendFeedback",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BUTTON_SEND_FEEDBACK));
loadtime_data.SetStringKey(
"buttonRunNetworkTests",
l10n_util::GetStringUTF16(
IDS_ARC_OPT_IN_DIALOG_BUTTON_RUN_NETWORK_TESTS));
loadtime_data.SetStringKey(
"buttonRetry",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_BUTTON_RETRY));
loadtime_data.SetStringKey(
"progressTermsLoading",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_PROGRESS_TERMS));
loadtime_data.SetStringKey(
"progressAndroidLoading",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_PROGRESS_ANDROID));
loadtime_data.SetStringKey(
"authorizationFailed",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_AUTHORIZATION_FAILED));
loadtime_data.SetStringKey(
"termsOfService",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_DIALOG_TERMS_OF_SERVICE));
loadtime_data.SetStringKey(
"textMetricsEnabled",
l10n_util::GetStringUTF16(
is_child ? IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED_CHILD
: IDS_ARC_OPT_IN_DIALOG_METRICS_ENABLED));
loadtime_data.SetStringKey(
"textMetricsDisabled",
l10n_util::GetStringUTF16(
is_child ? IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED_CHILD
: IDS_ARC_OPT_IN_DIALOG_METRICS_DISABLED));
loadtime_data.SetStringKey(
"textMetricsManagedEnabled",
l10n_util::GetStringUTF16(
is_child ? IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED_CHILD
: IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_ENABLED));
loadtime_data.SetStringKey(
"textMetricsManagedDisabled",
l10n_util::GetStringUTF16(
is_child ? IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED_CHILD
: IDS_ARC_OPT_IN_DIALOG_METRICS_MANAGED_DISABLED));
loadtime_data.SetStringKey(
"textBackupRestore",
l10n_util::GetStringUTF16(is_child
? IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD
: IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE));
loadtime_data.SetStringKey("textPaiService",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_PAI));
loadtime_data.SetStringKey(
"textGoogleServiceConfirmation",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_GOOGLE_SERVICE_CONFIRMATION));
loadtime_data.SetStringKey(
"textLocationService",
l10n_util::GetStringUTF16(is_child ? IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD
: IDS_ARC_OPT_IN_LOCATION_SETTING));
loadtime_data.SetStringKey(
"serverError",
l10n_util::GetStringUTF16(IDS_ARC_SERVER_COMMUNICATION_ERROR));
loadtime_data.SetStringKey(
"controlledByPolicy",
l10n_util::GetStringUTF16(IDS_CONTROLLED_SETTING_POLICY));
loadtime_data.SetStringKey(
"learnMoreStatisticsTitle",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS_TITLE));
loadtime_data.SetStringKey(
"learnMoreStatistics",
l10n_util::GetStringUTF16(is_child
? IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS_CHILD
: IDS_ARC_OPT_IN_LEARN_MORE_STATISTICS));
loadtime_data.SetStringKey(
"learnMoreBackupAndRestoreTitle",
l10n_util::GetStringUTF16(
IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE_TITLE));
loadtime_data.SetStringKey(
"learnMoreBackupAndRestore",
l10n_util::GetStringUTF16(
is_child ? IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE_CHILD
: IDS_ARC_OPT_IN_LEARN_MORE_BACKUP_AND_RESTORE));
loadtime_data.SetStringKey(
"learnMoreLocationServicesTitle",
l10n_util::GetStringUTF16(
IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES_TITLE));
loadtime_data.SetStringKey(
"learnMoreLocationServices",
l10n_util::GetStringUTF16(
is_child ? IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES_CHILD
: IDS_ARC_OPT_IN_LEARN_MORE_LOCATION_SERVICES));
loadtime_data.SetStringKey(
"learnMorePaiServiceTitle",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_LEARN_MORE_PAI_SERVICE_TITLE));
loadtime_data.SetStringKey(
"learnMorePaiService",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_LEARN_MORE_PAI_SERVICE));
loadtime_data.SetStringKey(
"overlayClose",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_LEARN_MORE_CLOSE));
loadtime_data.SetStringKey(
"privacyPolicyLink",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_PRIVACY_POLICY_LINK));
loadtime_data.SetStringKey(
"activeDirectoryAuthTitle",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_ACTIVE_DIRECTORY_AUTH_TITLE));
loadtime_data.SetStringKey(
"activeDirectoryAuthDesc",
l10n_util::GetStringUTF16(IDS_ARC_OPT_IN_ACTIVE_DIRECTORY_AUTH_DESC));
loadtime_data.SetStringKey(
"overlayLoading", l10n_util::GetStringUTF16(IDS_ARC_POPUP_HELP_LOADING));
loadtime_data.SetBoolean(kArcManaged, is_arc_managed_);
loadtime_data.SetBoolean("isOwnerProfile",
ash::ProfileHelper::IsOwnerProfile(profile_));
const std::string& country_code = base::CountryCodeForCurrentTimezone();
loadtime_data.SetStringKey("countryCode", country_code);
const std::string& app_locale = g_browser_process->GetApplicationLocale();
webui::SetLoadTimeDataDefaults(app_locale, &loadtime_data);
loadtime_data.SetStringKey("locale", app_locale);
base::DictionaryValue message;
message.SetStringKey(kAction, kActionInitialize);
message.SetKey(kData, std::move(loadtime_data));
const std::string device_id = user_manager::known_user::GetDeviceId(
multi_user_util::GetAccountIdFromProfile(profile_));
message.SetStringKey(kDeviceId, device_id);
message_host_->SendMessage(message);
return true;
}
void ArcSupportHost::OnDisplayMetricsChanged(const display::Display& display,
uint32_t changed_metrics) {
if (!message_host_)
return;
base::DictionaryValue message;
message.SetStringKey(kAction, kActionSetWindowBounds);
message_host_->SendMessage(message);
}
void ArcSupportHost::OnMessage(const base::DictionaryValue& message) {
const std::string* event = message.FindStringKey(kEvent);
if (!event) {
NOTREACHED();
return;
}
if (*event == kEventOnWindowClosed) {
// If ToS negotiation is ongoing, call the specific function.
if (tos_delegate_) {
tos_delegate_->OnTermsRejected();
} else {
DCHECK(error_delegate_);
error_delegate_->OnWindowClosed();
}
} else if (*event == kEventOnAuthSucceeded) {
DCHECK(auth_delegate_);
auth_delegate_->OnAuthSucceeded();
} else if (*event == kEventOnAuthFailed) {
DCHECK(auth_delegate_);
const std::string* error_message = message.FindStringKey(kAuthErrorMessage);
if (!error_message) {
NOTREACHED();
return;
}
// TODO(https://crbug.com/756144): Remove once reason for crash has been
// determined.
LOG_IF(ERROR, !auth_delegate_)
<< "auth_delegate_ is NULL, error: " << *error_message;
auth_delegate_->OnAuthFailed(*error_message);
} else if (*event == kEventOnAgreed || *event == kEventOnCanceled) {
DCHECK(tos_delegate_);
absl::optional<bool> tos_shown = message.FindBoolKey(kTosShown);
absl::optional<bool> is_metrics_enabled =
message.FindBoolKey(kIsMetricsEnabled);
absl::optional<bool> is_backup_restore_enabled =
message.FindBoolKey(kIsBackupRestoreEnabled);
absl::optional<bool> is_backup_restore_managed =
message.FindBoolKey(kIsBackupRestoreManaged);
absl::optional<bool> is_location_service_enabled =
message.FindBoolKey(kIsLocationServiceEnabled);
absl::optional<bool> is_location_service_managed =
message.FindBoolKey(kIsLocationServiceManaged);
const std::string* tos_content = message.FindStringKey(kTosContent);
if (!tos_content || !tos_shown.has_value() ||
!is_metrics_enabled.has_value() ||
!is_backup_restore_enabled.has_value() ||
!is_backup_restore_managed.has_value() ||
!is_location_service_enabled.has_value() ||
!is_location_service_managed.has_value()) {
NOTREACHED();
return;
}
bool accepted = *event == kEventOnAgreed;
if (!accepted) {
// Cancel is equivalent to not granting consent to the individual
// features, so ensure we don't record consent.
is_backup_restore_enabled = false;
is_location_service_enabled = false;
}
auto* identity_manager = IdentityManagerFactory::GetForProfile(profile_);
// This class doesn't care about browser sync consent.
DCHECK(identity_manager->HasPrimaryAccount(signin::ConsentLevel::kSignin));
CoreAccountId account_id =
identity_manager->GetPrimaryAccountId(signin::ConsentLevel::kSignin);
bool is_child = user_manager::UserManager::Get()->IsLoggedInAsChildUser();
// Record acceptance of ToS if it was shown to the user, otherwise simply
// record acceptance of an empty ToS.
UserConsentTypes::ArcPlayTermsOfServiceConsent play_consent;
play_consent.set_status(accepted ? UserConsentTypes::GIVEN
: UserConsentTypes::NOT_GIVEN);
play_consent.set_confirmation_grd_id(IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE);
play_consent.set_consent_flow(
UserConsentTypes::ArcPlayTermsOfServiceConsent::SETUP);
if (tos_shown.value()) {
play_consent.set_play_terms_of_service_text_length(tos_content->length());
play_consent.set_play_terms_of_service_hash(
base::SHA1HashString(*tos_content));
}
ConsentAuditorFactory::GetForProfile(profile_)->RecordArcPlayConsent(
account_id, play_consent);
// If the user - not policy - controls Backup and Restore setting, record
// whether consent was given.
if (!is_backup_restore_managed.value()) {
UserConsentTypes::ArcBackupAndRestoreConsent backup_and_restore_consent;
backup_and_restore_consent.set_confirmation_grd_id(
IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE);
backup_and_restore_consent.add_description_grd_ids(
is_child ? IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE_CHILD
: IDS_ARC_OPT_IN_DIALOG_BACKUP_RESTORE);
backup_and_restore_consent.set_status(is_backup_restore_enabled.value()
? UserConsentTypes::GIVEN
: UserConsentTypes::NOT_GIVEN);
ConsentAuditorFactory::GetForProfile(profile_)
->RecordArcBackupAndRestoreConsent(account_id,
backup_and_restore_consent);
}
// If the user - not policy - controls Location Services setting, record
// whether consent was given.
if (!is_location_service_managed.value()) {
UserConsentTypes::ArcGoogleLocationServiceConsent
location_service_consent;
location_service_consent.set_confirmation_grd_id(
IDS_ARC_OPT_IN_DIALOG_BUTTON_AGREE);
location_service_consent.add_description_grd_ids(
is_child ? IDS_ARC_OPT_IN_LOCATION_SETTING_CHILD
: IDS_ARC_OPT_IN_LOCATION_SETTING);
location_service_consent.set_status(is_location_service_enabled.value()
? UserConsentTypes::GIVEN
: UserConsentTypes::NOT_GIVEN);
ConsentAuditorFactory::GetForProfile(profile_)
->RecordArcGoogleLocationServiceConsent(account_id,
location_service_consent);
}
if (accepted) {
tos_delegate_->OnTermsAgreed(is_metrics_enabled.value(),
is_backup_restore_enabled.value(),
is_location_service_enabled.value());
}
} else if (*event == kEventOnRetryClicked) {
// If ToS negotiation or manual authentication is ongoing, call the
// corresponding delegate. Otherwise, call the general retry function.
if (tos_delegate_) {
tos_delegate_->OnTermsRetryClicked();
} else if (auth_delegate_) {
auth_delegate_->OnAuthRetryClicked();
} else {
DCHECK(error_delegate_);
error_delegate_->OnRetryClicked();
}
} else if (*event == kEventOnSendFeedbackClicked) {
DCHECK(error_delegate_);
error_delegate_->OnSendFeedbackClicked();
} else if (*event == kEventOnRunNetworkTestsClicked) {
DCHECK(error_delegate_);
error_delegate_->OnRunNetworkTestsClicked();
} else if (*event == kEventOnOpenPrivacySettingsPageClicked) {
chrome::ShowSettingsSubPageForProfile(profile_, chrome::kPrivacySubPage);
} else {
LOG(ERROR) << "Unknown message: " << *event;
NOTREACHED();
}
}