blob: 428655e877a6dfaae1f7ce3b8655d2489d410380 [file] [log] [blame]
// Copyright 2015 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/chromeos/arc/intent_helper/arc_settings_service.h"
#include <string>
#include "ash/public/cpp/ash_pref_names.h"
#include "base/command_line.h"
#include "base/gtest_prod_util.h"
#include "base/json/json_writer.h"
#include "base/memory/singleton.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/chromeos/arc/policy/arc_policy_util.h"
#include "chrome/browser/chromeos/settings/cros_settings.h"
#include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/zoom/chrome_zoom_level_prefs.h"
#include "chrome/common/pref_names.h"
#include "chromeos/chromeos_switches.h"
#include "chromeos/network/network_handler.h"
#include "chromeos/network/network_state.h"
#include "chromeos/network/network_state_handler.h"
#include "chromeos/network/network_state_handler_observer.h"
#include "chromeos/network/onc/onc_utils.h"
#include "chromeos/network/proxy/proxy_config_service_impl.h"
#include "chromeos/settings/cros_settings_names.h"
#include "chromeos/settings/timezone_settings.h"
#include "components/arc/arc_bridge_service.h"
#include "components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "components/arc/arc_prefs.h"
#include "components/arc/common/backup_settings.mojom.h"
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
#include "components/arc/intent_helper/font_size_util.h"
#include "components/onc/onc_pref_names.h"
#include "components/prefs/pref_change_registrar.h"
#include "components/prefs/pref_service.h"
#include "components/proxy_config/pref_proxy_config_tracker_impl.h"
#include "components/proxy_config/proxy_config_dictionary.h"
#include "components/proxy_config/proxy_config_pref_names.h"
#include "content/public/common/page_zoom.h"
#include "net/proxy_resolution/proxy_config.h"
using ::chromeos::CrosSettings;
using ::chromeos::system::TimezoneSettings;
namespace {
bool GetHttpProxyServer(const ProxyConfigDictionary* proxy_config_dict,
std::string* host,
int* port) {
std::string proxy_rules_string;
if (!proxy_config_dict->GetProxyServer(&proxy_rules_string))
return false;
net::ProxyConfig::ProxyRules proxy_rules;
proxy_rules.ParseFromString(proxy_rules_string);
const net::ProxyList* proxy_list = nullptr;
if (proxy_rules.type == net::ProxyConfig::ProxyRules::Type::PROXY_LIST) {
proxy_list = &proxy_rules.single_proxies;
} else if (proxy_rules.type ==
net::ProxyConfig::ProxyRules::Type::PROXY_LIST_PER_SCHEME) {
proxy_list = proxy_rules.MapUrlSchemeToProxyList(url::kHttpScheme);
}
if (!proxy_list || proxy_list->IsEmpty())
return false;
const net::ProxyServer& server = proxy_list->Get();
*host = server.host_port_pair().host();
*port = server.host_port_pair().port();
return !host->empty() && *port;
}
} // namespace
namespace arc {
namespace {
// Singleton factory for ArcSettingsService.
class ArcSettingsServiceFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase<
ArcSettingsService,
ArcSettingsServiceFactory> {
public:
// Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
static constexpr const char* kName = "ArcSettingsServiceFactory";
static ArcSettingsServiceFactory* GetInstance() {
return base::Singleton<ArcSettingsServiceFactory>::get();
}
private:
friend base::DefaultSingletonTraits<ArcSettingsServiceFactory>;
ArcSettingsServiceFactory() = default;
~ArcSettingsServiceFactory() override = default;
};
} // namespace
// Listens to changes for select Chrome settings (prefs) that Android cares
// about and sends the new values to Android to keep the state in sync.
class ArcSettingsServiceImpl
: public chromeos::system::TimezoneSettings::Observer,
public ConnectionObserver<mojom::AppInstance>,
public chromeos::NetworkStateHandlerObserver {
public:
ArcSettingsServiceImpl(Profile* profile,
ArcBridgeService* arc_bridge_service);
~ArcSettingsServiceImpl() override;
// Called when a Chrome pref we have registered an observer for has changed.
// Obtains the new pref value and sends it to Android.
void OnPrefChanged(const std::string& pref_name) const;
// TimezoneSettings::Observer:
void TimezoneChanged(const icu::TimeZone& timezone) override;
// NetworkStateHandlerObserver:
void DefaultNetworkChanged(const chromeos::NetworkState* network) override;
// Retrieves Chrome's state for the settings that need to be synced on the
// initial Android boot and send it to Android. Called by ArcSettingsService.
void SyncInitialSettings() const;
private:
PrefService* GetPrefs() const { return profile_->GetPrefs(); }
// Returns whether kProxy pref proxy config is applied.
bool IsPrefProxyConfigApplied() const;
// Registers to observe changes for Chrome settings we care about.
void StartObservingSettingsChanges();
// Stops listening for Chrome settings changes.
void StopObservingSettingsChanges();
// Retrieves Chrome's state for the settings that need to be synced on each
// Android boot and send it to Android.
void SyncBootTimeSettings() const;
// Retrieves Chrome's state for the settings that need to be synced on each
// Android boot after AppInstance is ready and send it to Android.
void SyncAppTimeSettings();
// Send particular settings to Android.
// Keep these lines ordered lexicographically.
void SyncAccessibilityLargeMouseCursorEnabled() const;
void SyncAccessibilityVirtualKeyboardEnabled() const;
void SyncBackupEnabled() const;
void SyncFocusHighlightEnabled() const;
void SyncFontSize() const;
void SyncPageZoom() const;
void SyncLocale() const;
void SyncLocationServiceEnabled() const;
void SyncProxySettings() const;
void SyncReportingConsent(bool initial_sync) const;
void SyncSelectToSpeakEnabled() const;
void SyncSpokenFeedbackEnabled() const;
void SyncSwitchAccessEnabled() const;
void SyncTimeZone() const;
void SyncTimeZoneByGeolocation() const;
void SyncUse24HourClock() const;
// Registers to listen to a particular perf.
void AddPrefToObserve(const std::string& pref_name);
// Returns the integer value of the pref. pref_name must exist.
int GetIntegerPref(const std::string& pref_name) const;
// Gets whether this is a managed pref.
bool IsBooleanPrefManaged(const std::string& pref_name) const;
// Sends boolean pref broadcast to the delegate.
void SendBoolPrefSettingsBroadcast(const std::string& pref_name,
const std::string& action) const;
// Same as above, except sends a specific boolean value.
void SendBoolValueSettingsBroadcast(bool value,
bool managed,
const std::string& action) const;
// Sends a broadcast to the delegate.
void SendSettingsBroadcast(const std::string& action,
const base::DictionaryValue& extras) const;
// ConnectionObserver<mojom::AppInstance>:
void OnConnectionReady() override;
Profile* const profile_;
ArcBridgeService* const arc_bridge_service_; // Owned by ArcServiceManager.
// Manages pref observation registration.
PrefChangeRegistrar registrar_;
std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>
reporting_consent_subscription_;
// Subscription for preference change of default zoom level. Subscription
// automatically unregisters a callback when it's destructed.
std::unique_ptr<ChromeZoomLevelPrefs::DefaultZoomLevelSubscription>
default_zoom_level_subscription_;
DISALLOW_COPY_AND_ASSIGN(ArcSettingsServiceImpl);
};
ArcSettingsServiceImpl::ArcSettingsServiceImpl(
Profile* profile,
ArcBridgeService* arc_bridge_service)
: profile_(profile), arc_bridge_service_(arc_bridge_service) {
StartObservingSettingsChanges();
SyncBootTimeSettings();
// Note: if App connection is already established, OnConnectionReady()
// is synchronously called, so that initial sync is done in the method.
arc_bridge_service_->app()->AddObserver(this);
}
ArcSettingsServiceImpl::~ArcSettingsServiceImpl() {
StopObservingSettingsChanges();
arc_bridge_service_->app()->RemoveObserver(this);
}
void ArcSettingsServiceImpl::OnPrefChanged(const std::string& pref_name) const {
VLOG(1) << "OnPrefChanged: " << pref_name;
// Keep these lines ordered lexicographically by pref_name.
if (pref_name == onc::prefs::kDeviceOpenNetworkConfiguration ||
pref_name == onc::prefs::kOpenNetworkConfiguration) {
// Only update proxy settings if kProxy pref is not applied.
if (IsPrefProxyConfigApplied()) {
LOG(ERROR) << "Open Network Configuration proxy settings are not applied,"
<< " because kProxy preference is configured.";
return;
}
SyncProxySettings();
} else if (pref_name == ash::prefs::kAccessibilityFocusHighlightEnabled) {
SyncFocusHighlightEnabled();
} else if (pref_name == ash::prefs::kAccessibilityLargeCursorEnabled) {
SyncAccessibilityLargeMouseCursorEnabled();
} else if (pref_name == ash::prefs::kAccessibilitySelectToSpeakEnabled) {
SyncSelectToSpeakEnabled();
} else if (pref_name == ash::prefs::kAccessibilitySpokenFeedbackEnabled) {
SyncSpokenFeedbackEnabled();
} else if (pref_name == ash::prefs::kAccessibilitySwitchAccessEnabled) {
SyncSwitchAccessEnabled();
} else if (pref_name == ash::prefs::kAccessibilityVirtualKeyboardEnabled) {
SyncAccessibilityVirtualKeyboardEnabled();
} else if (pref_name == ::prefs::kApplicationLocale ||
pref_name == ::prefs::kLanguagePreferredLanguages) {
SyncLocale();
} else if (pref_name == ::prefs::kUse24HourClock) {
SyncUse24HourClock();
} else if (pref_name == ::prefs::kResolveTimezoneByGeolocationMethod) {
SyncTimeZoneByGeolocation();
} else if (pref_name == ::prefs::kWebKitDefaultFixedFontSize ||
pref_name == ::prefs::kWebKitDefaultFontSize ||
pref_name == ::prefs::kWebKitMinimumFontSize) {
SyncFontSize();
} else if (pref_name == proxy_config::prefs::kProxy) {
SyncProxySettings();
} else {
LOG(ERROR) << "Unknown pref changed.";
}
}
void ArcSettingsServiceImpl::TimezoneChanged(const icu::TimeZone& timezone) {
SyncTimeZone();
}
void ArcSettingsServiceImpl::DefaultNetworkChanged(
const chromeos::NetworkState* network) {
// kProxy pref has more priority than the default network update.
// If a default network is changed to the network with ONC policy with proxy
// settings, it should be translated here.
if (network && !IsPrefProxyConfigApplied())
SyncProxySettings();
}
bool ArcSettingsServiceImpl::IsPrefProxyConfigApplied() const {
net::ProxyConfigWithAnnotation config;
return PrefProxyConfigTrackerImpl::PrefPrecedes(
PrefProxyConfigTrackerImpl::ReadPrefConfig(GetPrefs(), &config));
}
void ArcSettingsServiceImpl::StartObservingSettingsChanges() {
registrar_.Init(GetPrefs());
// Keep these lines ordered lexicographically.
AddPrefToObserve(ash::prefs::kAccessibilityFocusHighlightEnabled);
AddPrefToObserve(ash::prefs::kAccessibilityLargeCursorEnabled);
AddPrefToObserve(ash::prefs::kAccessibilitySelectToSpeakEnabled);
AddPrefToObserve(ash::prefs::kAccessibilitySpokenFeedbackEnabled);
AddPrefToObserve(ash::prefs::kAccessibilitySwitchAccessEnabled);
AddPrefToObserve(ash::prefs::kAccessibilityVirtualKeyboardEnabled);
AddPrefToObserve(::prefs::kResolveTimezoneByGeolocationMethod);
AddPrefToObserve(::prefs::kUse24HourClock);
AddPrefToObserve(::prefs::kWebKitDefaultFixedFontSize);
AddPrefToObserve(::prefs::kWebKitDefaultFontSize);
AddPrefToObserve(::prefs::kWebKitMinimumFontSize);
AddPrefToObserve(proxy_config::prefs::kProxy);
AddPrefToObserve(onc::prefs::kDeviceOpenNetworkConfiguration);
AddPrefToObserve(onc::prefs::kOpenNetworkConfiguration);
// Note that some preferences, such as kArcBackupRestoreEnabled and
// kArcLocationServiceEnabled, are not dynamically updated after initial
// ARC setup and therefore are not observed here.
reporting_consent_subscription_ = CrosSettings::Get()->AddSettingsObserver(
chromeos::kStatsReportingPref,
base::Bind(&ArcSettingsServiceImpl::SyncReportingConsent,
base::Unretained(this), /*initial_sync=*/false));
// It's safe to use base::Unretained. This is unregistered when
// default_zoom_level_subscription_ is destructed which is stored as
// unique_ptr in member of this class.
default_zoom_level_subscription_ =
profile_->GetZoomLevelPrefs()->RegisterDefaultZoomLevelCallback(
base::BindRepeating(&ArcSettingsServiceImpl::SyncPageZoom,
base::Unretained(this)));
TimezoneSettings::GetInstance()->AddObserver(this);
chromeos::NetworkHandler::Get()->network_state_handler()->AddObserver(
this, FROM_HERE);
}
void ArcSettingsServiceImpl::StopObservingSettingsChanges() {
registrar_.RemoveAll();
reporting_consent_subscription_.reset();
TimezoneSettings::GetInstance()->RemoveObserver(this);
chromeos::NetworkHandler::Get()->network_state_handler()->RemoveObserver(
this, FROM_HERE);
}
void ArcSettingsServiceImpl::SyncInitialSettings() const {
// Keep these lines ordered lexicographically.
SyncBackupEnabled();
SyncLocationServiceEnabled();
SyncReportingConsent(/*initial_sync=*/true);
}
void ArcSettingsServiceImpl::SyncBootTimeSettings() const {
// Keep these lines ordered lexicographically.
SyncAccessibilityLargeMouseCursorEnabled();
SyncAccessibilityVirtualKeyboardEnabled();
SyncFocusHighlightEnabled();
SyncFontSize();
SyncPageZoom();
SyncProxySettings();
SyncReportingConsent(/*initial_sync=*/false);
SyncSelectToSpeakEnabled();
SyncSpokenFeedbackEnabled();
SyncSwitchAccessEnabled();
SyncTimeZone();
SyncTimeZoneByGeolocation();
SyncUse24HourClock();
}
void ArcSettingsServiceImpl::SyncAppTimeSettings() {
// Applying system locales change on ARC will cause restarting other services
// and applications on ARC and doing such change in early phase may lead to
// ARC OptIn failure b/65385376. So that observing preferred languages change
// should be deferred at least until |mojom::AppInstance| is ready.
// Note that locale and preferred languages are passed to Android container on
// boot time and current sync is redundant in most cases. However there is
// race when preferred languages may be changed during the ARC booting.
// Tracking and applying this information is complex task thar requires
// syncronization ARC session start, ArcSettingsService and
// ArcSettingsServiceImpl creation/destroying. Android framework has ability
// to supress reduntant calls so having this little overhead simplifies common
// implementation.
SyncLocale();
AddPrefToObserve(::prefs::kApplicationLocale);
AddPrefToObserve(::prefs::kLanguagePreferredLanguages);
}
void ArcSettingsServiceImpl::SyncAccessibilityLargeMouseCursorEnabled() const {
SendBoolPrefSettingsBroadcast(
ash::prefs::kAccessibilityLargeCursorEnabled,
"org.chromium.arc.intent_helper.ACCESSIBILITY_LARGE_POINTER_ICON");
}
void ArcSettingsServiceImpl::SyncAccessibilityVirtualKeyboardEnabled() const {
SendBoolPrefSettingsBroadcast(
ash::prefs::kAccessibilityVirtualKeyboardEnabled,
"org.chromium.arc.intent_helper.SET_SHOW_IME_WITH_HARD_KEYBOARD");
}
void ArcSettingsServiceImpl::SyncBackupEnabled() const {
auto* backup_settings = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->backup_settings(), SetBackupEnabled);
if (backup_settings) {
const PrefService::Preference* pref =
registrar_.prefs()->FindPreference(prefs::kArcBackupRestoreEnabled);
DCHECK(pref);
const base::Value* value = pref->GetValue();
DCHECK(value->is_bool());
backup_settings->SetBackupEnabled(value->GetBool(),
!pref->IsUserModifiable());
}
}
void ArcSettingsServiceImpl::SyncFocusHighlightEnabled() const {
SendBoolPrefSettingsBroadcast(
ash::prefs::kAccessibilityFocusHighlightEnabled,
"org.chromium.arc.intent_helper.SET_FOCUS_HIGHLIGHT_ENABLED");
}
void ArcSettingsServiceImpl::SyncFontSize() const {
int default_size = GetIntegerPref(::prefs::kWebKitDefaultFontSize);
int default_fixed_size = GetIntegerPref(::prefs::kWebKitDefaultFixedFontSize);
int minimum_size = GetIntegerPref(::prefs::kWebKitMinimumFontSize);
double android_scale = ConvertFontSizeChromeToAndroid(
default_size, default_fixed_size, minimum_size);
base::DictionaryValue extras;
extras.SetDouble("scale", android_scale);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_FONT_SCALE",
extras);
}
void ArcSettingsServiceImpl::SyncPageZoom() const {
double zoom_level = profile_->GetZoomLevelPrefs()->GetDefaultZoomLevelPref();
double zoom_factor = content::ZoomLevelToZoomFactor(zoom_level);
base::DictionaryValue extras;
extras.SetDouble("zoomFactor", zoom_factor);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_PAGE_ZOOM", extras);
}
void ArcSettingsServiceImpl::SyncLocale() const {
const PrefService::Preference* pref =
registrar_.prefs()->FindPreference(::prefs::kApplicationLocale);
DCHECK(pref);
std::string locale;
bool value_exists = pref->GetValue()->GetAsString(&locale);
DCHECK(value_exists);
base::DictionaryValue extras;
// Chrome OS locale may contain only the language part (e.g. fr) but country
// code (e.g. fr_FR). Since Android expects locale to contain country code,
// ARC will derive a likely locale with country code from such.
extras.SetString("locale", locale);
const std::string preferredLanguages =
registrar_.prefs()->GetString(::prefs::kLanguagePreferredLanguages);
// |preferredLanguages| consists of comma separated locale strings. It may be
// empty or contain empty items, but those are ignored on ARC. If an item
// has no country code, it is derived in ARC. In such a case, it may
// conflict with another item in the list, then these will be dedupped (the
// first one is taken) in ARC.
extras.SetString("preferredLanguages", preferredLanguages);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_LOCALE", extras);
}
void ArcSettingsServiceImpl::SyncLocationServiceEnabled() const {
SendBoolPrefSettingsBroadcast(
prefs::kArcLocationServiceEnabled,
"org.chromium.arc.intent_helper.SET_LOCATION_SERVICE_ENABLED");
}
void ArcSettingsServiceImpl::SyncProxySettings() const {
std::unique_ptr<ProxyConfigDictionary> proxy_config_dict =
chromeos::ProxyConfigServiceImpl::GetActiveProxyConfigDictionary(
GetPrefs(), g_browser_process->local_state());
if (!proxy_config_dict)
return;
ProxyPrefs::ProxyMode mode;
if (!proxy_config_dict || !proxy_config_dict->GetMode(&mode))
mode = ProxyPrefs::MODE_DIRECT;
base::DictionaryValue extras;
extras.SetString("mode", ProxyPrefs::ProxyModeToString(mode));
switch (mode) {
case ProxyPrefs::MODE_DIRECT:
break;
case ProxyPrefs::MODE_SYSTEM:
VLOG(1) << "The system mode is not translated.";
return;
case ProxyPrefs::MODE_AUTO_DETECT:
extras.SetString("pacUrl", "http://wpad/wpad.dat");
break;
case ProxyPrefs::MODE_PAC_SCRIPT: {
std::string pac_url;
if (!proxy_config_dict->GetPacUrl(&pac_url)) {
LOG(ERROR) << "No pac URL for pac_script proxy mode.";
return;
}
extras.SetString("pacUrl", pac_url);
break;
}
case ProxyPrefs::MODE_FIXED_SERVERS: {
std::string host;
int port = 0;
if (!GetHttpProxyServer(proxy_config_dict.get(), &host, &port)) {
LOG(ERROR) << "No Http proxy server is sent.";
return;
}
extras.SetString("host", host);
extras.SetInteger("port", port);
std::string bypass_list;
if (proxy_config_dict->GetBypassList(&bypass_list) &&
!bypass_list.empty()) {
extras.SetString("bypassList", bypass_list);
}
break;
}
default:
LOG(ERROR) << "Incorrect proxy mode.";
return;
}
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_PROXY", extras);
}
void ArcSettingsServiceImpl::SyncReportingConsent(bool initial_sync) const {
bool consent = IsArcStatsReportingEnabled();
if (consent && !initial_sync && policy_util::IsAccountManaged(profile_)) {
// Don't enable reporting for managed users who might not have seen the
// reporting notice during ARC setup.
return;
}
if (consent && initial_sync &&
profile_->GetPrefs()->GetBoolean(prefs::kArcSkippedReportingNotice)) {
// Explicitly leave reporting off for users who did not get a reporting
// notice during setup, but otherwise would have reporting on due to the
// result of |IsArcStatsReportingEnabled()| during setup. Typically this is
// due to the fact that ArcSessionManager was able to skip the setup UI for
// managed users.
consent = false;
}
base::DictionaryValue extras;
extras.SetBoolean("reportingConsent", consent);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_REPORTING_CONSENT",
extras);
}
void ArcSettingsServiceImpl::SyncSelectToSpeakEnabled() const {
SendBoolPrefSettingsBroadcast(
ash::prefs::kAccessibilitySelectToSpeakEnabled,
"org.chromium.arc.intent_helper.SET_SELECT_TO_SPEAK_ENABLED");
}
void ArcSettingsServiceImpl::SyncSpokenFeedbackEnabled() const {
SendBoolPrefSettingsBroadcast(
ash::prefs::kAccessibilitySpokenFeedbackEnabled,
"org.chromium.arc.intent_helper.SET_SPOKEN_FEEDBACK_ENABLED");
}
void ArcSettingsServiceImpl::SyncSwitchAccessEnabled() const {
SendBoolPrefSettingsBroadcast(
ash::prefs::kAccessibilitySwitchAccessEnabled,
"org.chromium.arc.intent_helper.SET_SWITCH_ACCESS_ENABLED");
}
void ArcSettingsServiceImpl::SyncTimeZone() const {
TimezoneSettings* timezone_settings = TimezoneSettings::GetInstance();
base::string16 timezoneID = timezone_settings->GetCurrentTimezoneID();
base::DictionaryValue extras;
extras.SetString("olsonTimeZone", timezoneID);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_TIME_ZONE", extras);
}
void ArcSettingsServiceImpl::SyncTimeZoneByGeolocation() const {
const PrefService::Preference* pref = registrar_.prefs()->FindPreference(
::prefs::kResolveTimezoneByGeolocationMethod);
DCHECK(pref);
int setTimeZoneByGeolocation =
static_cast<int>(chromeos::system::TimeZoneResolverManager::
TimeZoneResolveMethod::DISABLED);
bool value_exists = pref->GetValue()->GetAsInteger(&setTimeZoneByGeolocation);
DCHECK(value_exists);
base::DictionaryValue extras;
extras.SetBoolean("autoTimeZone",
chromeos::system::TimeZoneResolverManager::
GetEffectiveUserTimeZoneResolveMethod(
registrar_.prefs(), false) !=
chromeos::system::TimeZoneResolverManager::
TimeZoneResolveMethod::DISABLED);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_AUTO_TIME_ZONE",
extras);
}
void ArcSettingsServiceImpl::SyncUse24HourClock() const {
const PrefService::Preference* pref =
registrar_.prefs()->FindPreference(::prefs::kUse24HourClock);
DCHECK(pref);
bool use24HourClock = false;
bool value_exists = pref->GetValue()->GetAsBoolean(&use24HourClock);
DCHECK(value_exists);
base::DictionaryValue extras;
extras.SetBoolean("use24HourClock", use24HourClock);
SendSettingsBroadcast("org.chromium.arc.intent_helper.SET_USE_24_HOUR_CLOCK",
extras);
}
void ArcSettingsServiceImpl::AddPrefToObserve(const std::string& pref_name) {
registrar_.Add(pref_name, base::Bind(&ArcSettingsServiceImpl::OnPrefChanged,
base::Unretained(this)));
}
int ArcSettingsServiceImpl::GetIntegerPref(const std::string& pref_name) const {
const PrefService::Preference* pref =
registrar_.prefs()->FindPreference(pref_name);
DCHECK(pref);
int val = -1;
bool value_exists = pref->GetValue()->GetAsInteger(&val);
DCHECK(value_exists);
return val;
}
bool ArcSettingsServiceImpl::IsBooleanPrefManaged(
const std::string& pref_name) const {
const PrefService::Preference* pref =
registrar_.prefs()->FindPreference(pref_name);
DCHECK(pref);
bool value_exists = pref->GetValue()->is_bool();
DCHECK(value_exists);
return !pref->IsUserModifiable();
}
void ArcSettingsServiceImpl::SendBoolPrefSettingsBroadcast(
const std::string& pref_name,
const std::string& action) const {
const PrefService::Preference* pref =
registrar_.prefs()->FindPreference(pref_name);
DCHECK(pref);
bool enabled = false;
bool value_exists = pref->GetValue()->GetAsBoolean(&enabled);
DCHECK(value_exists);
SendBoolValueSettingsBroadcast(enabled, !pref->IsUserModifiable(), action);
}
void ArcSettingsServiceImpl::SendBoolValueSettingsBroadcast(
bool enabled,
bool managed,
const std::string& action) const {
base::DictionaryValue extras;
extras.SetBoolean("enabled", enabled);
extras.SetBoolean("managed", managed);
SendSettingsBroadcast(action, extras);
}
void ArcSettingsServiceImpl::SendSettingsBroadcast(
const std::string& action,
const base::DictionaryValue& extras) const {
auto* instance = ARC_GET_INSTANCE_FOR_METHOD(
arc_bridge_service_->intent_helper(), SendBroadcast);
if (!instance)
return;
std::string extras_json;
bool write_success = base::JSONWriter::Write(extras, &extras_json);
DCHECK(write_success);
instance->SendBroadcast(
action, ArcIntentHelperBridge::kArcIntentHelperPackageName,
ArcIntentHelperBridge::AppendStringToIntentHelperPackageName(
"SettingsReceiver"),
extras_json);
}
// ConnectionObserver<mojom::AppInstance>:
void ArcSettingsServiceImpl::OnConnectionReady() {
arc_bridge_service_->app()->RemoveObserver(this);
SyncAppTimeSettings();
}
// static
ArcSettingsService* ArcSettingsService::GetForBrowserContext(
content::BrowserContext* context) {
return ArcSettingsServiceFactory::GetForBrowserContext(context);
}
ArcSettingsService::ArcSettingsService(content::BrowserContext* context,
ArcBridgeService* bridge_service)
: profile_(Profile::FromBrowserContext(context)),
arc_bridge_service_(bridge_service) {
arc_bridge_service_->intent_helper()->AddObserver(this);
ArcSessionManager::Get()->AddObserver(this);
if (!IsArcPlayStoreEnabledForProfile(profile_))
SetInitialSettingsPending(false);
}
ArcSettingsService::~ArcSettingsService() {
ArcSessionManager::Get()->RemoveObserver(this);
arc_bridge_service_->intent_helper()->RemoveObserver(this);
}
void ArcSettingsService::OnConnectionReady() {
impl_ =
std::make_unique<ArcSettingsServiceImpl>(profile_, arc_bridge_service_);
if (!IsInitialSettingsPending())
return;
impl_->SyncInitialSettings();
SetInitialSettingsPending(false);
}
void ArcSettingsService::OnConnectionClosed() {
impl_.reset();
}
void ArcSettingsService::OnArcPlayStoreEnabledChanged(bool enabled) {
if (!enabled)
SetInitialSettingsPending(false);
}
void ArcSettingsService::OnArcInitialStart() {
DCHECK(!IsInitialSettingsPending());
if (!impl_) {
SetInitialSettingsPending(true);
return;
}
impl_->SyncInitialSettings();
}
void ArcSettingsService::SetInitialSettingsPending(bool pending) {
profile_->GetPrefs()->SetBoolean(prefs::kArcInitialSettingsPending, pending);
}
bool ArcSettingsService::IsInitialSettingsPending() const {
return profile_->GetPrefs()->GetBoolean(prefs::kArcInitialSettingsPending);
}
} // namespace arc