Require parent access code to change child's timezone

Bug: 921145
Change-Id: Ib40299cdebb289213cedc8e0bf3d9afdd5f28d88
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1673673
Commit-Queue: Henrique Grandinetti <hgrandinetti@chromium.org>
Reviewed-by: Michael Giuffrida <michaelpg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#672227}
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
index d203e70..cb52254 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.cc
@@ -52,6 +52,7 @@
 bool ParentAccessService::IsApprovalRequired(SupervisedAction action) {
   switch (action) {
     case SupervisedAction::kUpdateClock:
+    case SupervisedAction::kUpdateTimezone:
       if (!base::FeatureList::IsEnabled(
               features::kParentAccessCodeForTimeChange)) {
         return false;
diff --git a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
index 508abdc4..08bc22f 100644
--- a/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
+++ b/chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h
@@ -44,7 +44,9 @@
     // When Chrome is unable to automatically verify if the OS time is correct
     // the user becomes able to manually change the clock. The entry points are
     // the settings page (in-session) and the tray bubble (out-session).
-    kUpdateClock
+    kUpdateClock,
+    // Change timezone from the settings page.
+    kUpdateTimezone
   };
 
   // Registers preferences.
diff --git a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
index 63e56da..35f577e 100644
--- a/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
+++ b/chrome/browser/extensions/api/settings_private/chromeos_resolve_time_zone_by_geolocation_on_off.cc
@@ -66,12 +66,11 @@
   if (!value->is_bool())
     return SetPrefResult::PREF_TYPE_MISMATCH;
 
-  // Check if preference is policy or primary-user controlled, or if the user is
-  // a child, and therefore cannot deactivate automatic timezone.
+  // Check if preference is policy or primary-user controlled, and therefore
+  // cannot deactivate automatic timezone.
   if (chromeos::system::TimeZoneResolverManager::
           IsTimeZoneResolutionPolicyControlled() ||
-      !profile_->IsSameProfile(ProfileManager::GetPrimaryUserProfile()) ||
-      profile_->IsChild()) {
+      !profile_->IsSameProfile(ProfileManager::GetPrimaryUserProfile())) {
     return SetPrefResult::PREF_NOT_MODIFIABLE;
   }
 
diff --git a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
index 133958a..1e3d563 100644
--- a/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
+++ b/chrome/browser/extensions/api/settings_private/generated_time_zone_pref_base.cc
@@ -36,11 +36,8 @@
 
 void GeneratedTimeZonePrefBase::UpdateTimeZonePrefControlledBy(
     settings_api::PrefObject* out_pref) const {
-  if (profile_->IsChild()) {
-    out_pref->controlled_by = settings_api::ControlledBy::CONTROLLED_BY_PARENT;
-    out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED;
-  } else if (chromeos::system::TimeZoneResolverManager::
-                 IsTimeZoneResolutionPolicyControlled()) {
+  if (chromeos::system::TimeZoneResolverManager::
+          IsTimeZoneResolutionPolicyControlled()) {
     out_pref->controlled_by = settings_api::CONTROLLED_BY_DEVICE_POLICY;
     out_pref->enforcement = settings_api::ENFORCEMENT_ENFORCED;
   } else if (!profile_->IsSameProfile(
diff --git a/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chrome/browser/resources/settings/date_time_page/date_time_page.js
index ec58887..186c536e 100644
--- a/chrome/browser/resources/settings/date_time_page/date_time_page.js
+++ b/chrome/browser/resources/settings/date_time_page/date_time_page.js
@@ -54,13 +54,19 @@
           activeTimeZoneDisplayName,
           prefs.generated.resolve_timezone_by_geolocation_on_off.value,
           prefs.generated.resolve_timezone_by_geolocation_method_short.value)`
-    }
+    },
+
+    /** @private */
+    isChild_: {type: Boolean, value: loadTimeData.getBoolean('isChild')},
   },
 
   /** @override */
   attached: function() {
     this.addWebUIListener(
         'can-set-date-time-changed', this.onCanSetDateTimeChanged_.bind(this));
+    this.addWebUIListener(
+        'access-code-validation-complete',
+        this.openTimeZoneSubpage_.bind(this));
 
     chrome.send('dateTimePageReady');
   },
@@ -99,7 +105,24 @@
     return id ? this.i18n(id) : '';
   },
 
+  /**
+   * Called when the timezone row is clicked. Child accounts need parental
+   * approval to modify their timezone, this method starts this process on the
+   * C++ side, and once it is complete the 'access-code-validation-complete'
+   * event is triggered which invokes openTimeZoneSubpage_. For non-child
+   * accounts the method is invoked immediately.
+   * @private
+   */
   onTimeZoneSettings_: function() {
+    if (this.isChild_) {
+      chrome.send('handleShowParentAccessForTimeZone');
+      return;
+    }
+    this.openTimeZoneSubpage_();
+  },
+
+  /** @private */
+  openTimeZoneSubpage_: function() {
     settings.navigateTo(settings.routes.DATETIME_TIMEZONE_SUBPAGE);
   },
 });
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
index c3a3202..a5db2fe 100644
--- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
+++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.cc
@@ -4,10 +4,14 @@
 
 #include "chrome/browser/ui/webui/settings/chromeos/date_time_handler.h"
 
+#include "ash/public/cpp/login_screen.h"
+#include "ash/public/cpp/login_types.h"
 #include "base/bind.h"
 #include "base/command_line.h"
+#include "base/logging.h"
 #include "base/values.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/child_accounts/parent_access_code/parent_access_service.h"
 #include "chrome/browser/chromeos/set_time_dialog.h"
 #include "chrome/browser/chromeos/system/timezone_resolver_manager.h"
 #include "chrome/browser/chromeos/system/timezone_util.h"
@@ -17,6 +21,7 @@
 #include "chromeos/settings/timezone_settings.h"
 #include "components/policy/proto/chrome_device_policy.pb.h"
 #include "components/prefs/pref_service.h"
+#include "components/user_manager/user_manager.h"
 #include "content/public/browser/web_contents.h"
 #include "content/public/browser/web_ui.h"
 #include "content/public/browser/web_ui_data_source.h"
@@ -87,6 +92,10 @@
       "showSetDateTimeUI",
       base::BindRepeating(&DateTimeHandler::HandleShowSetDateTimeUI,
                           base::Unretained(this)));
+  web_ui()->RegisterMessageCallback(
+      "handleShowParentAccessForTimeZone",
+      base::BindRepeating(&DateTimeHandler::HandleShowParentAccessForTimeZone,
+                          base::Unretained(this)));
 }
 
 void DateTimeHandler::OnJavascriptAllowed() {
@@ -141,6 +150,29 @@
       web_ui()->GetWebContents()->GetTopLevelNativeWindow());
 }
 
+void DateTimeHandler::HandleShowParentAccessForTimeZone(
+    const base::ListValue* args) {
+  DCHECK(user_manager::UserManager::Get()->GetActiveUser()->IsChild());
+
+  if (!parent_access::ParentAccessService::IsApprovalRequired(
+          parent_access::ParentAccessService::SupervisedAction::
+              kUpdateTimezone)) {
+    OnParentAccessValidation(true);
+    return;
+  }
+
+  ash::LoginScreen::Get()->ShowParentAccessWidget(
+      user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(),
+      base::BindRepeating(&DateTimeHandler::OnParentAccessValidation,
+                          weak_ptr_factory_.GetWeakPtr()),
+      ash::ParentAccessRequestReason::kChangeTime);
+}
+
+void DateTimeHandler::OnParentAccessValidation(bool success) {
+  if (success)
+    FireWebUIListener("access-code-validation-complete");
+}
+
 void DateTimeHandler::NotifyTimezoneAutomaticDetectionPolicy() {
   bool managed = !IsTimezoneAutomaticDetectionUserEditable();
   bool force_enabled = managed &&
diff --git a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.h b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.h
index c4f2a32..bd69d93 100644
--- a/chrome/browser/ui/webui/settings/chromeos/date_time_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/date_time_handler.h
@@ -55,6 +55,14 @@
   // Called to show the Set Time UI.
   void HandleShowSetDateTimeUI(const base::ListValue* args);
 
+  // Handles clicks on the timezone row on the settings page. This should only
+  // be called when the current user is a child.
+  void HandleShowParentAccessForTimeZone(const base::ListValue* args);
+
+  // Called when the parent access code was validated with result equals
+  // |success|.
+  void OnParentAccessValidation(bool success);
+
   // Updates the UI, enabling or disabling the time zone automatic detection
   // setting according to policy.
   void NotifyTimezoneAutomaticDetectionPolicy();