Commit fe049488 authored by yilkal's avatar yilkal Committed by Commit Bot

Introduce EDUCoexistence ARC Migration UI

This CL introduces EDUCoexistence ARC Migration
UI. The UI is triggered only in the following scenario:
1. The supervised user has an EDU account on device.
2. The EDU account has not yet been added to ARC++.

Regardless of the number of EDU accounts on the supervised user,
the migration ui will be shown only once.

Bug: 1115313
Change-Id: Ieded997c99be6708bef7d441aa5d07ce3b1cf95e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2360575Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarKush Sinha <sinhak@chromium.org>
Reviewed-by: default avatarAga Wronska <agawronska@chromium.org>
Commit-Queue: Yilkal Abe <yilkal@chromium.org>
Cr-Commit-Position: refs/heads/master@{#804047}
parent a83acf84
...@@ -34,12 +34,15 @@ ...@@ -34,12 +34,15 @@
#include "chrome/browser/ui/settings_window_manager_chromeos.h" #include "chrome/browser/ui/settings_window_manager_chromeos.h"
#include "chrome/browser/ui/webui/chromeos/account_manager/account_manager_welcome_dialog.h" #include "chrome/browser/ui/webui/chromeos/account_manager/account_manager_welcome_dialog.h"
#include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h" #include "chrome/browser/ui/webui/settings/chromeos/constants/routes.mojom.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/url_constants.h" #include "chrome/common/url_constants.h"
#include "chrome/grit/chromium_strings.h" #include "chrome/grit/chromium_strings.h"
#include "chrome/grit/generated_resources.h" #include "chrome/grit/generated_resources.h"
#include "chrome/grit/theme_resources.h" #include "chrome/grit/theme_resources.h"
#include "chromeos/components/account_manager/account_manager_factory.h" #include "chromeos/components/account_manager/account_manager_factory.h"
#include "components/account_id/account_id.h" #include "components/account_id/account_id.h"
#include "components/prefs/pref_registry_simple.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/consent_level.h" #include "components/signin/public/identity_manager/consent_level.h"
#include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_manager.h"
#include "components/user_manager/user_manager.h" #include "components/user_manager/user_manager.h"
...@@ -72,6 +75,22 @@ bool AreAllAccountsMigrated( ...@@ -72,6 +75,22 @@ bool AreAllAccountsMigrated(
return true; return true;
} }
// Returns true if the child user has migrated at least one of their
// secondary edu accounts to ARC++.
bool IsSecondaryEduAccountMigratedForChildUser(
Profile* profile,
const std::vector<chromeos::AccountManager::Account>& accounts) {
// If the profile is not a child then there is no migration required.
// If the profile is child but has only one account on device, then there is
// no migration required; i.e. there is no secondary edu account to migrate.
if (!profile->IsChild() || accounts.size() < 2) {
return true;
}
return profile->GetPrefs()->GetBoolean(
prefs::kEduCoexistenceArcMigrationCompleted);
}
} // namespace } // namespace
SigninErrorNotifier::SigninErrorNotifier(SigninErrorController* controller, SigninErrorNotifier::SigninErrorNotifier(SigninErrorController* controller,
...@@ -124,6 +143,12 @@ SigninErrorNotifier::IgnoreSyncErrorsForTesting() { ...@@ -124,6 +143,12 @@ SigninErrorNotifier::IgnoreSyncErrorsForTesting() {
&g_ignore_sync_errors_for_test_, true); &g_ignore_sync_errors_for_test_, true);
} }
// static
void SigninErrorNotifier::RegisterPrefs(PrefRegistrySimple* registry) {
registry->RegisterBooleanPref(prefs::kEduCoexistenceArcMigrationCompleted,
false);
}
void SigninErrorNotifier::Shutdown() { void SigninErrorNotifier::Shutdown() {
error_controller_->RemoveObserver(this); error_controller_->RemoveObserver(this);
error_controller_ = nullptr; error_controller_ = nullptr;
...@@ -242,7 +267,9 @@ void SigninErrorNotifier::OnGetAccounts( ...@@ -242,7 +267,9 @@ void SigninErrorNotifier::OnGetAccounts(
multi_user_util::GetAccountIdFromProfile(profile_).GetUserEmail(); multi_user_util::GetAccountIdFromProfile(profile_).GetUserEmail();
const bool are_all_accounts_migrated = const bool are_all_accounts_migrated =
AreAllAccountsMigrated(account_manager_, accounts); AreAllAccountsMigrated(account_manager_, accounts) &&
IsSecondaryEduAccountMigratedForChildUser(profile_, accounts);
const base::string16 message_title = const base::string16 message_title =
are_all_accounts_migrated are_all_accounts_migrated
? l10n_util::GetStringUTF16( ? l10n_util::GetStringUTF16(
...@@ -280,6 +307,16 @@ void SigninErrorNotifier::OnGetAccounts( ...@@ -280,6 +307,16 @@ void SigninErrorNotifier::OnGetAccounts(
void SigninErrorNotifier::HandleSecondaryAccountReauthNotificationClick( void SigninErrorNotifier::HandleSecondaryAccountReauthNotificationClick(
base::Optional<int> button_index) { base::Optional<int> button_index) {
if (profile_->IsChild() && !profile_->GetPrefs()->GetBoolean(
prefs::kEduCoexistenceArcMigrationCompleted)) {
if (!chromeos::AccountManagerWelcomeDialog::
ShowIfRequiredForEduCoexistence()) {
chrome::SettingsWindowManager::GetInstance()->ShowOSSettings(
profile_, chromeos::settings::mojom::kMyAccountsSubpagePath);
}
return;
}
if (!chromeos::AccountManagerWelcomeDialog::ShowIfRequired()) { if (!chromeos::AccountManagerWelcomeDialog::ShowIfRequired()) {
// The welcome dialog was not shown (because it has been shown too many // The welcome dialog was not shown (because it has been shown too many
// times already). Take users to Account Manager UI directly. // times already). Take users to Account Manager UI directly.
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "components/signin/core/browser/signin_error_controller.h" #include "components/signin/core/browser/signin_error_controller.h"
class Profile; class Profile;
class PrefRegistrySimple;
namespace signin { namespace signin {
class IdentityManager; class IdentityManager;
...@@ -34,6 +35,8 @@ class SigninErrorNotifier : public SigninErrorController::Observer, ...@@ -34,6 +35,8 @@ class SigninErrorNotifier : public SigninErrorController::Observer,
static std::unique_ptr<base::AutoReset<bool>> IgnoreSyncErrorsForTesting(); static std::unique_ptr<base::AutoReset<bool>> IgnoreSyncErrorsForTesting();
static void RegisterPrefs(PrefRegistrySimple* registry);
// KeyedService: // KeyedService:
void Shutdown() override; void Shutdown() override;
......
...@@ -17,10 +17,13 @@ ...@@ -17,10 +17,13 @@
#include "chrome/browser/chromeos/login/users/mock_user_manager.h" #include "chrome/browser/chromeos/login/users/mock_user_manager.h"
#include "chrome/browser/notifications/notification_display_service_tester.h" #include "chrome/browser/notifications/notification_display_service_tester.h"
#include "chrome/browser/signin/identity_test_environment_profile_adaptor.h" #include "chrome/browser/signin/identity_test_environment_profile_adaptor.h"
#include "chrome/browser/supervised_user/supervised_user_constants.h"
#include "chrome/browser/supervised_user/supervised_user_service.h" #include "chrome/browser/supervised_user/supervised_user_service.h"
#include "chrome/browser/supervised_user/supervised_user_service_factory.h" #include "chrome/browser/supervised_user/supervised_user_service_factory.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/browser_with_test_window_test.h" #include "chrome/test/base/browser_with_test_window_test.h"
#include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/identity_test_environment.h" #include "components/signin/public/identity_manager/identity_test_environment.h"
#include "components/signin/public/identity_manager/identity_test_utils.h" #include "components/signin/public/identity_manager/identity_test_utils.h"
#include "components/user_manager/scoped_user_manager.h" #include "components/user_manager/scoped_user_manager.h"
...@@ -30,6 +33,7 @@ ...@@ -30,6 +33,7 @@
namespace { namespace {
const char kTestEmail[] = "email@example.com"; const char kTestEmail[] = "email@example.com";
const char kTestSecondaryEmail[] = "email2@example.com";
// Notification ID corresponding to kProfileSigninNotificationId + // Notification ID corresponding to kProfileSigninNotificationId +
// kTestAccountId. // kTestAccountId.
...@@ -235,4 +239,46 @@ TEST_F(SigninErrorNotifierTest, AuthStatusEnumerateAllErrors) { ...@@ -235,4 +239,46 @@ TEST_F(SigninErrorNotifierTest, AuthStatusEnumerateAllErrors) {
} }
} }
TEST_F(SigninErrorNotifierTest, ChildSecondaryAccountMigrationTest) {
CoreAccountId primary_account =
identity_test_env()->MakePrimaryAccountAvailable(kTestEmail).account_id;
CoreAccountId secondary_account =
identity_test_env()->MakeAccountAvailable(kTestSecondaryEmail).account_id;
// Mark the profile as a child user.
GetProfile()->SetSupervisedUserId(supervised_users::kChildAccountSUID);
base::RunLoop().RunUntilIdle();
// Invalidate the secondary account.
SetAuthError(
secondary_account,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
// Expect that there is a notification, accounts didn't migrate yet.
base::Optional<message_center::Notification> notification =
display_service_->GetNotification(kSecondaryAccountErrorNotificationId);
ASSERT_TRUE(notification);
base::string16 message = notification->message();
EXPECT_FALSE(message.empty());
// Clear error.
SetAuthError(secondary_account, GoogleServiceAuthError::AuthErrorNone());
EXPECT_FALSE(
display_service_->GetNotification(kSecondaryAccountErrorNotificationId));
// Mark secondary account as migrated, message should be different.
profile()->GetPrefs()->SetBoolean(prefs::kEduCoexistenceArcMigrationCompleted,
true);
// Invalidate the secondary account.
SetAuthError(
secondary_account,
GoogleServiceAuthError(GoogleServiceAuthError::INVALID_GAIA_CREDENTIALS));
notification =
display_service_->GetNotification(kSecondaryAccountErrorNotificationId);
ASSERT_TRUE(notification);
base::string16 new_message = notification->message();
EXPECT_NE(new_message, message);
}
} // namespace } // namespace
...@@ -297,6 +297,7 @@ ...@@ -297,6 +297,7 @@
#include "chrome/browser/chromeos/login/screens/enable_adb_sideloading_screen.h" #include "chrome/browser/chromeos/login/screens/enable_adb_sideloading_screen.h"
#include "chrome/browser/chromeos/login/screens/reset_screen.h" #include "chrome/browser/chromeos/login/screens/reset_screen.h"
#include "chrome/browser/chromeos/login/session/user_session_manager.h" #include "chrome/browser/chromeos/login/session/user_session_manager.h"
#include "chrome/browser/chromeos/login/signin/signin_error_notifier_ash.h"
#include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/login/startup_utils.h"
#include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h" #include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
#include "chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.h" #include "chrome/browser/chromeos/login/users/avatar/user_image_sync_observer.h"
...@@ -1084,6 +1085,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry, ...@@ -1084,6 +1085,7 @@ void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry,
chromeos::RegisterSamlProfilePrefs(registry); chromeos::RegisterSamlProfilePrefs(registry);
chromeos::ScreenTimeController::RegisterProfilePrefs(registry); chromeos::ScreenTimeController::RegisterProfilePrefs(registry);
SecondaryAccountConsentLogger::RegisterPrefs(registry); SecondaryAccountConsentLogger::RegisterPrefs(registry);
SigninErrorNotifier::RegisterPrefs(registry);
chromeos::ServicesCustomizationDocument::RegisterProfilePrefs(registry); chromeos::ServicesCustomizationDocument::RegisterProfilePrefs(registry);
chromeos::settings::OSSettingsUI::RegisterProfilePrefs(registry); chromeos::settings::OSSettingsUI::RegisterProfilePrefs(registry);
chromeos::UserImageSyncObserver::RegisterProfilePrefs(registry); chromeos::UserImageSyncObserver::RegisterProfilePrefs(registry);
......
...@@ -278,7 +278,7 @@ class ChromeBrowserMainExtraPartsAsh::NotificationObserver ...@@ -278,7 +278,7 @@ class ChromeBrowserMainExtraPartsAsh::NotificationObserver
Profile* profile = content::Details<Profile>(details).ptr(); Profile* profile = content::Details<Profile>(details).ptr();
if (!chromeos::ProfileHelper::IsSigninProfile(profile) && if (!chromeos::ProfileHelper::IsSigninProfile(profile) &&
!chromeos::ProfileHelper::IsLockScreenAppProfile(profile) && !chromeos::ProfileHelper::IsLockScreenAppProfile(profile) &&
!profile->IsGuestSession() && !profile->IsSupervised()) { !profile->IsGuestSession()) {
// Start the error notifier services to show auth/sync notifications. // Start the error notifier services to show auth/sync notifications.
SigninErrorNotifierFactory::GetForProfile(profile); SigninErrorNotifierFactory::GetForProfile(profile);
SyncErrorNotifierFactory::GetForProfile(profile); SyncErrorNotifierFactory::GetForProfile(profile);
......
...@@ -44,21 +44,6 @@ AccountManagerWelcomeDialog::~AccountManagerWelcomeDialog() { ...@@ -44,21 +44,6 @@ AccountManagerWelcomeDialog::~AccountManagerWelcomeDialog() {
// static // static
bool AccountManagerWelcomeDialog::ShowIfRequired() { bool AccountManagerWelcomeDialog::ShowIfRequired() {
if (g_dialog) {
// If the dialog is already being displayed, bring it to focus instead of
// creating another window.
g_dialog->dialog_window()->Focus();
return true;
}
// Check if the dialog should be shown.
// It should not be shown in kiosk mode since there are no actual accounts to
// manage, but the service account.
if (user_manager::UserManager::Get()
->IsCurrentUserCryptohomeDataEphemeral() ||
user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()) {
return false;
}
PrefService* pref_service = PrefService* pref_service =
ProfileManager::GetActiveUserProfile()->GetPrefs(); ProfileManager::GetActiveUserProfile()->GetPrefs();
const int num_times_shown = pref_service->GetInteger( const int num_times_shown = pref_service->GetInteger(
...@@ -66,15 +51,22 @@ bool AccountManagerWelcomeDialog::ShowIfRequired() { ...@@ -66,15 +51,22 @@ bool AccountManagerWelcomeDialog::ShowIfRequired() {
if (num_times_shown >= kMaxNumTimesShown) { if (num_times_shown >= kMaxNumTimesShown) {
return false; return false;
} }
if (!ShowIfRequiredInternal()) {
return false;
}
pref_service->SetInteger(prefs::kAccountManagerNumTimesWelcomeScreenShown, pref_service->SetInteger(prefs::kAccountManagerNumTimesWelcomeScreenShown,
num_times_shown + 1); num_times_shown + 1);
// Will be deleted by |SystemWebDialogDelegate::OnDialogClosed|.
g_dialog = new AccountManagerWelcomeDialog();
g_dialog->ShowSystemDialog();
return true; return true;
} }
// static
bool AccountManagerWelcomeDialog::ShowIfRequiredForEduCoexistence() {
return ShowIfRequiredInternal();
}
void AccountManagerWelcomeDialog::AdjustWidgetInitParams( void AccountManagerWelcomeDialog::AdjustWidgetInitParams(
views::Widget::InitParams* params) { views::Widget::InitParams* params) {
params->z_order = ui::ZOrderLevel::kNormal; params->z_order = ui::ZOrderLevel::kNormal;
...@@ -111,4 +103,28 @@ bool AccountManagerWelcomeDialog::ShouldShowCloseButton() const { ...@@ -111,4 +103,28 @@ bool AccountManagerWelcomeDialog::ShouldShowCloseButton() const {
return false; return false;
} }
// static
bool AccountManagerWelcomeDialog::ShowIfRequiredInternal() {
if (g_dialog) {
// If the dialog is already being displayed, bring it to focus instead of
// creating another window.
g_dialog->dialog_window()->Focus();
return true;
}
// Check if the dialog should be shown.
// It should not be shown in kiosk mode since there are no actual accounts to
// manage, but the service account.
if (user_manager::UserManager::Get()
->IsCurrentUserCryptohomeDataEphemeral() ||
user_manager::UserManager::Get()->IsLoggedInAsAnyKioskApp()) {
return false;
}
// Will be deleted by |SystemWebDialogDelegate::OnDialogClosed|.
g_dialog = new AccountManagerWelcomeDialog();
g_dialog->ShowSystemDialog();
return true;
}
} // namespace chromeos } // namespace chromeos
...@@ -19,6 +19,11 @@ class AccountManagerWelcomeDialog : public SystemWebDialogDelegate { ...@@ -19,6 +19,11 @@ class AccountManagerWelcomeDialog : public SystemWebDialogDelegate {
// false otherwise. // false otherwise.
static bool ShowIfRequired(); static bool ShowIfRequired();
// Displays the Chrome OS Account Manager welcome screen. Only to be used for
// the EDUCoexistence use case. Returns true if the screen was displayed,
// false otherwise.
static bool ShowIfRequiredForEduCoexistence();
protected: protected:
AccountManagerWelcomeDialog(); AccountManagerWelcomeDialog();
~AccountManagerWelcomeDialog() override; ~AccountManagerWelcomeDialog() override;
...@@ -32,6 +37,8 @@ class AccountManagerWelcomeDialog : public SystemWebDialogDelegate { ...@@ -32,6 +37,8 @@ class AccountManagerWelcomeDialog : public SystemWebDialogDelegate {
bool ShouldShowCloseButton() const override; bool ShouldShowCloseButton() const override;
private: private:
static bool ShowIfRequiredInternal();
DISALLOW_COPY_AND_ASSIGN(AccountManagerWelcomeDialog); DISALLOW_COPY_AND_ASSIGN(AccountManagerWelcomeDialog);
}; };
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_process_platform_part.h" #include "chrome/browser/browser_process_platform_part.h"
#include "chrome/browser/chromeos/arc/arc_util.h"
#include "chrome/browser/chromeos/child_accounts/secondary_account_consent_logger.h" #include "chrome/browser/chromeos/child_accounts/secondary_account_consent_logger.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/chrome_device_id_helper.h" #include "chrome/browser/signin/chrome_device_id_helper.h"
...@@ -22,8 +23,10 @@ ...@@ -22,8 +23,10 @@
#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h" #include "chrome/browser/ui/webui/signin/inline_login_dialog_chromeos.h"
#include "chrome/browser/ui/webui/signin/inline_login_handler.h" #include "chrome/browser/ui/webui/signin/inline_login_handler.h"
#include "chrome/common/pref_names.h"
#include "chromeos/components/account_manager/account_manager_factory.h" #include "chromeos/components/account_manager/account_manager_factory.h"
#include "chromeos/constants/chromeos_features.h" #include "chromeos/constants/chromeos_features.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/identity_manager/account_info.h" #include "components/signin/public/identity_manager/account_info.h"
#include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_manager.h"
#include "crypto/sha2.h" #include "crypto/sha2.h"
...@@ -214,6 +217,13 @@ class ChildSigninHelper : public SigninHelper { ...@@ -214,6 +217,13 @@ class ChildSigninHelper : public SigninHelper {
UMA_HISTOGRAM_ENUMERATION("Signin.SecondaryAccountConsentLog", result); UMA_HISTOGRAM_ENUMERATION("Signin.SecondaryAccountConsentLog", result);
secondary_account_consent_logger_.reset(); secondary_account_consent_logger_.reset();
if (result == SecondaryAccountConsentLogger::Result::kSuccess) { if (result == SecondaryAccountConsentLogger::Result::kSuccess) {
// The EDU account has been added/reauthenticated. Mark migration to ARC++
// as completed.
if (arc::IsSecondaryAccountForChildEnabled()) {
pref_service_->SetBoolean(prefs::kEduCoexistenceArcMigrationCompleted,
true);
}
UpsertAccount(refresh_token); UpsertAccount(refresh_token);
} else { } else {
LOG(ERROR) << "Could not log parent consent, the result was: " LOG(ERROR) << "Could not log parent consent, the result was: "
......
...@@ -1054,6 +1054,12 @@ const char kUpdateRequiredWarningPeriod[] = "update_required_warning_period"; ...@@ -1054,6 +1054,12 @@ const char kUpdateRequiredWarningPeriod[] = "update_required_warning_period";
// when System-proxy and ARC++ are enabled by policy. // when System-proxy and ARC++ are enabled by policy.
const char kSystemProxyUserTrafficHostAndPort[] = const char kSystemProxyUserTrafficHostAndPort[] =
"system_proxy.user_traffic_host_and_port"; "system_proxy.user_traffic_host_and_port";
// Boolean pref indicating whether the supervised user has migrated EDU
// secondary account to ARC++.
const char kEduCoexistenceArcMigrationCompleted[] =
"account_manager.edu_coexistence_arc_migration_completed";
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
// A boolean pref set to true if a Home button to open the Home pages should be // A boolean pref set to true if a Home button to open the Home pages should be
......
...@@ -342,6 +342,7 @@ extern const char kDeviceLoginScreenWebUsbAllowDevicesForUrls[]; ...@@ -342,6 +342,7 @@ extern const char kDeviceLoginScreenWebUsbAllowDevicesForUrls[];
extern const char kUpdateRequiredTimerStartTime[]; extern const char kUpdateRequiredTimerStartTime[];
extern const char kUpdateRequiredWarningPeriod[]; extern const char kUpdateRequiredWarningPeriod[];
extern const char kSystemProxyUserTrafficHostAndPort[]; extern const char kSystemProxyUserTrafficHostAndPort[];
extern const char kEduCoexistenceArcMigrationCompleted[];
#endif // defined(OS_CHROMEOS) #endif // defined(OS_CHROMEOS)
extern const char kShowHomeButton[]; extern const char kShowHomeButton[];
extern const char kSpeechRecognitionFilterProfanities[]; extern const char kSpeechRecognitionFilterProfanities[];
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment