Chromium Code Reviews| Index: chrome/browser/ui/views/profiles/profile_chooser_view.cc |
| diff --git a/chrome/browser/ui/views/profiles/profile_chooser_view.cc b/chrome/browser/ui/views/profiles/profile_chooser_view.cc |
| index cbae94c49150976daea87beb1a9ca1efbfd16644..670d5d98ba37045b7c83c5b02a26cf153b344354 100644 |
| --- a/chrome/browser/ui/views/profiles/profile_chooser_view.cc |
| +++ b/chrome/browser/ui/views/profiles/profile_chooser_view.cc |
| @@ -21,6 +21,7 @@ |
| #include "chrome/browser/signin/signin_manager_factory.h" |
| #include "chrome/browser/signin/signin_promo.h" |
| #include "chrome/browser/signin/signin_ui_util.h" |
| +#include "chrome/browser/sync/profile_sync_service_factory.h" |
| #include "chrome/browser/ui/browser.h" |
| #include "chrome/browser/ui/browser_commands.h" |
| #include "chrome/browser/ui/browser_dialogs.h" |
| @@ -36,12 +37,14 @@ |
| #include "chrome/common/url_constants.h" |
| #include "chrome/grit/chromium_strings.h" |
| #include "chrome/grit/generated_resources.h" |
| +#include "components/browser_sync/browser/profile_sync_service.h" |
| #include "components/prefs/pref_service.h" |
| #include "components/signin/core/browser/profile_oauth2_token_service.h" |
| #include "components/signin/core/browser/signin_error_controller.h" |
| #include "components/signin/core/browser/signin_header_helper.h" |
| #include "components/signin/core/browser/signin_manager.h" |
| #include "components/signin/core/common/profile_management_switches.h" |
| +#include "components/sync_driver/sync_error_controller.h" |
| #include "content/public/browser/render_widget_host_view.h" |
| #include "content/public/browser/user_metrics.h" |
| #include "grit/theme_resources.h" |
| @@ -788,6 +791,11 @@ void ProfileChooserView::ResetView() { |
| tutorial_see_whats_new_button_ = nullptr; |
| tutorial_not_you_link_ = nullptr; |
| tutorial_learn_more_link_ = nullptr; |
| + sync_error_signin_button_ = nullptr; |
|
msw
2016/07/13 22:31:38
nit: order to match the decl of all these members.
Jane
2016/07/14 00:18:58
Done.
|
| + sync_error_passphrase_button_ = nullptr; |
| + sync_error_upgrade_button_ = nullptr; |
| + sync_error_signin_again_button_ = nullptr; |
| + sync_error_signout_button_ = nullptr; |
| } |
| void ProfileChooserView::Init() { |
| @@ -872,7 +880,11 @@ void ProfileChooserView::ShowView(profiles::BubbleViewMode view_to_display, |
| DCHECK(switches::IsEnableAccountConsistency()); |
| const AvatarMenu::Item& active_item = avatar_menu->GetItemAt( |
| avatar_menu->GetActiveProfileIndex()); |
| - DCHECK(active_item.signed_in); |
| + if (!active_item.signed_in) |
|
msw
2016/07/13 22:31:38
Add curlies here or move the comment above the if
Jane
2016/07/14 00:18:58
Done.
|
| + // This is the case when the user selects the sign out option in the user |
| + // menu upon encountering unrecoverable error. Then following the action, |
|
msw
2016/07/13 22:31:37
nit: "errors"
Jane
2016/07/14 00:18:57
Done.
|
| + // profile chooser view would be shown instead of account management view. |
|
msw
2016/07/13 22:31:38
nit: "Afterwards, the profile chooser view is show
Jane
2016/07/14 00:18:58
Done.
|
| + view_to_display = profiles::BUBBLE_VIEW_MODE_PROFILE_CHOOSER; |
| } |
| if (browser_->profile()->IsSupervised() && |
| @@ -1000,8 +1012,22 @@ void ProfileChooserView::ButtonPressed(views::Button* sender, |
| PostActionPerformed(ProfileMetrics::PROFILE_DESKTOP_MENU_LOCK); |
| } else if (sender == close_all_windows_button_) { |
| profiles::CloseProfileWindows(browser_->profile()); |
| - } else if (sender == auth_error_email_button_) { |
| + } else if (sender == auth_error_email_button_ || |
| + sender == sync_error_signin_button_) { |
| ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_REAUTH); |
| + } else if (sender == sync_error_passphrase_button_) { |
| + chrome::ShowSettingsSubPage(browser_, chrome::kSyncSetupSubPage); |
| + } else if (sender == sync_error_upgrade_button_) { |
| + chrome::OpenUpdateChromeDialog(browser_); |
| + } else if (sender == sync_error_signin_again_button_) { |
| + if (ProfileSyncServiceFactory::GetForProfile(browser_->profile())) |
| + ProfileSyncService::SyncEvent(ProfileSyncService::STOP_FROM_OPTIONS); |
| + SigninManagerFactory::GetForProfile(browser_->profile()) |
| + ->SignOut(signin_metrics::USER_CLICKED_SIGNOUT_SETTINGS, |
| + signin_metrics::SignoutDelete::IGNORE_METRIC); |
| + ShowViewFromMode(profiles::BUBBLE_VIEW_MODE_GAIA_SIGNIN); |
| + } else if (sender == sync_error_signout_button_) { |
| + chrome::ShowSettingsSubPage(browser_, chrome::kSignOutSubPage); |
| } else if (sender == tutorial_sync_settings_ok_button_) { |
| LoginUIServiceFactory::GetForProfile(browser_->profile())-> |
| SyncConfirmationUIClosed(LoginUIService::SYNC_WITH_DEFAULT_SETTINGS); |
| @@ -1175,6 +1201,7 @@ void ProfileChooserView::PopulateCompleteProfileChooserView( |
| // Separate items into active and alternatives. |
| Indexes other_profiles; |
| views::View* tutorial_view = NULL; |
| + views::View* sync_error_view = NULL; |
| views::View* current_profile_view = NULL; |
| views::View* current_profile_accounts = NULL; |
| views::View* option_buttons_view = NULL; |
| @@ -1189,10 +1216,14 @@ void ProfileChooserView::PopulateCompleteProfileChooserView( |
| ? CreateMaterialDesignCurrentProfileView(item, false) |
| : CreateCurrentProfileView(item, false); |
| if (IsProfileChooser(view_mode_)) { |
| - tutorial_view = CreateTutorialViewIfNeeded(item); |
| + if (!switches::IsMaterialDesignUserMenu()) |
|
msw
2016/07/13 22:31:38
Do we really not want tutorial_view in MD? Call th
Jane
2016/07/14 00:18:58
Yep, this is an explicit decision and is briefly m
msw
2016/07/14 02:23:33
Acknowledged.
|
| + tutorial_view = CreateTutorialViewIfNeeded(item); |
| } else { |
| current_profile_accounts = CreateCurrentProfileAccountsView(item); |
| } |
| + if (switches::IsMaterialDesignUserMenu()) { |
|
msw
2016/07/13 22:31:38
nit: curlies not needed
Jane
2016/07/14 00:18:57
Done.
|
| + sync_error_view = CreateSyncErrorViewIfNeeded(); |
| + } |
| } else { |
| other_profiles.push_back(i); |
| } |
| @@ -1206,6 +1237,13 @@ void ProfileChooserView::PopulateCompleteProfileChooserView( |
| tutorial_mode_ = profiles::TUTORIAL_MODE_NONE; |
| } |
| + if (sync_error_view) { |
| + layout->StartRow(1, 0); |
| + layout->AddView(sync_error_view); |
| + layout->StartRow(0, 0); |
| + layout->AddView(new views::Separator(views::Separator::HORIZONTAL)); |
| + } |
| + |
| if (!current_profile_view) { |
| // Guest windows don't have an active profile. |
| current_profile_view = CreateGuestProfileView(); |
| @@ -1434,6 +1472,137 @@ views::View* ProfileChooserView::CreateTutorialView( |
| return view; |
| } |
| +views::View* ProfileChooserView::CreateSyncErrorViewIfNeeded() { |
| + ProfileSyncService* service = |
| + ProfileSyncServiceFactory::GetForProfile(browser_->profile()); |
| + |
| + // The order or priority is going to be: 1. Unrecoverable errors. |
| + // 2. Auth errors. 3. Protocol errors. 4. Passphrase errors. |
| + if (service && service->HasUnrecoverableError()) { |
| + // Unrecoverable error is sometimes accompanied by actionable error. |
|
msw
2016/07/13 22:31:38
nit: "An unrecoverable" and "an actionable"
Jane
2016/07/14 00:18:58
Done.
|
| + // If actionable error is not set to be UPGRADE_CLIENT, then show generic |
|
msw
2016/07/13 22:31:38
nit: "an actionable" and "show a generic"
Jane
2016/07/14 00:18:58
Done.
|
| + // unrecoverable error message. |
| + ProfileSyncService::Status status; |
| + service->QueryDetailedSyncStatus(&status); |
| + if (status.sync_protocol_error.action != syncer::UPGRADE_CLIENT) { |
| + // Display different error messages and buttons depending on whether it |
|
msw
2016/07/13 22:31:38
nit: "Display different messages and buttons for m
Jane
2016/07/14 00:18:58
Done.
|
| + // is a managed account. |
| + if (SigninManagerFactory::GetForProfile(browser_->profile()) |
| + ->IsSignoutProhibited()) { |
| + return CreateSyncErrorView( |
| + l10n_util::GetStringUTF16( |
| + IDS_SYNC_ERROR_USER_MENU_SIGNOUT_MESSAGE), |
|
msw
2016/07/13 22:31:38
Did you flip the intended values here? You're usin
Jane
2016/07/14 00:18:58
The values are not flipped. AFAIU, IsSignoutProhib
msw
2016/07/14 02:23:33
This seems highly counter-intuitive, and deserves
Jane
2016/07/14 15:34:37
So Roger said this is the right function to use. I
|
| + l10n_util::GetStringUTF16( |
| + IDS_SYNC_ERROR_USER_MENU_SIGNOUT_BUTTON), |
| + &sync_error_signout_button_); |
| + } else { |
|
msw
2016/07/13 22:31:38
nit: no else after return.
Jane
2016/07/14 00:18:57
Done.
|
| + return CreateSyncErrorView( |
| + l10n_util::GetStringUTF16( |
| + IDS_SYNC_ERROR_USER_MENU_SIGNIN_AGAIN_MESSAGE), |
| + l10n_util::GetStringUTF16( |
| + IDS_SYNC_ERROR_USER_MENU_SIGNIN_AGAIN_BUTTON), |
| + &sync_error_signin_again_button_); |
| + } |
| + } |
| + } |
| + |
| + // Check for an auth error. |
| + if (HasAuthError(browser_->profile())) { |
| + return CreateSyncErrorView( |
| + l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_LOGIN_MESSAGE), |
| + l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_LOGIN_BUTTON), |
| + &sync_error_signin_button_); |
| + } |
| + |
| + // Check for sync errors if the sync service is enabled. |
| + if (service) { |
| + // Check for an actionable error UPGRADE_CLIENT. |
|
msw
2016/07/13 22:31:38
nit: "actionable UPGRADE_CLIENT error"?
Jane
2016/07/14 00:18:58
Done.
|
| + ProfileSyncService::Status status; |
| + service->QueryDetailedSyncStatus(&status); |
| + if (status.sync_protocol_error.action == syncer::UPGRADE_CLIENT) { |
| + return CreateSyncErrorView( |
| + l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_UPGRADE_MESSAGE), |
| + l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_UPGRADE_BUTTON), |
| + &sync_error_upgrade_button_); |
| + } |
| + |
| + // Check for a sync passphrase error. |
| + SyncErrorController* sync_error_controller = |
| + service->sync_error_controller(); |
| + if (sync_error_controller && sync_error_controller->HasError()) { |
| + return CreateSyncErrorView( |
| + l10n_util::GetStringUTF16( |
| + IDS_SYNC_ERROR_USER_MENU_PASSPHRASE_MESSAGE), |
| + l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_PASSPHRASE_BUTTON), |
| + &sync_error_passphrase_button_); |
| + } |
| + } |
| + |
| + // There is no error. |
| + return nullptr; |
| +} |
| + |
| +views::View* ProfileChooserView::CreateSyncErrorView( |
| + const base::string16& content_text, |
|
msw
2016/07/13 22:31:38
nit: take a resource ID here instead of the string
Jane
2016/07/14 00:18:58
Good suggestion! Changed it.
|
| + const base::string16& button_text, |
| + views::LabelButton** button) { |
|
msw
2016/07/13 22:31:38
nit: button_out... it'd be nice if we used |views:
Jane
2016/07/14 00:18:58
Done.
|
| + // Sets an overall horizontal layout. |
| + views::View* view = new views::View(); |
| + views::BoxLayout* layout = new views::BoxLayout( |
| + views::BoxLayout::kHorizontal, kMaterialMenuEdgeMargin, |
| + kMaterialMenuEdgeMargin, views::kUnrelatedControlHorizontalSpacing); |
| + layout->set_cross_axis_alignment( |
| + views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); |
| + view->SetLayoutManager(layout); |
| + |
| + // Adds the sync problem icon. |
| + views::ImageView* sync_problem_icon = new views::ImageView(); |
| + sync_problem_icon->SetImage(gfx::CreateVectorIcon( |
| + gfx::VectorIconId::SYNC_PROBLEM, 20, gfx::kGoogleRed700)); |
| + view->AddChildView(sync_problem_icon); |
| + |
| + // Adds a vertical view to organize the error title, message, and button. |
|
msw
2016/07/13 22:31:38
nit: GridLayout *might* be simpler than nesting Bo
Jane
2016/07/14 00:18:58
Oh, right, maybe, but I thought this was pretty st
|
| + views::View* vertical_view = new views::View(); |
| + views::BoxLayout* vertical_layout = |
| + new views::BoxLayout(views::BoxLayout::kVertical, 0, 0, |
| + views::kRelatedControlSmallVerticalSpacing); |
| + vertical_layout->set_cross_axis_alignment( |
| + views::BoxLayout::CROSS_AXIS_ALIGNMENT_START); |
| + vertical_view->SetLayoutManager(vertical_layout); |
| + |
| + // Adds the title. |
| + views::Label* title_label = new views::Label( |
| + l10n_util::GetStringUTF16(IDS_SYNC_ERROR_USER_MENU_TITLE)); |
| + title_label->SetFontList(gfx::FontList().DeriveWithSizeDelta(1)); |
|
msw
2016/07/13 22:31:38
I doubt that a 1px Font size difference matters he
Jane
2016/07/14 00:18:57
Done.
|
| + title_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| + title_label->SetEnabledColor(gfx::kGoogleRed700); |
| + vertical_view->AddChildView(title_label); |
| + |
| + // Adds body content. |
| + if (!content_text.empty()) { |
|
msw
2016/07/13 22:31:38
This text should never be empty; DCHECK instead or
Jane
2016/07/14 00:18:58
Done.
|
| + views::Label* content_label = new views::Label(content_text); |
| + content_label->SetMultiLine(true); |
| + content_label->SetHorizontalAlignment(gfx::ALIGN_LEFT); |
| + vertical_view->AddChildView(content_label); |
| + } |
| + |
| + // Adds a padding row between error title/content and the button. |
| + SizedContainer* padding = new SizedContainer( |
| + gfx::Size(GetFixedMenuWidth() - 2 * kMaterialMenuEdgeMargin, |
|
msw
2016/07/13 22:31:38
nit: I bet a 0 width would be okay here...
Jane
2016/07/14 00:18:58
Done.
|
| + views::kRelatedControlVerticalSpacing)); |
| + vertical_view->AddChildView(padding); |
| + |
| + // Adds action_button. |
|
msw
2016/07/13 22:31:38
nit: "an action button"; there is no |action_butto
Jane
2016/07/14 00:18:57
Done.
|
| + *button = views::MdTextButton::CreateSecondaryUiBlueButton(this, button_text); |
| + vertical_view->AddChildView(*button); |
| + |
| + view->AddChildView(vertical_view); |
| + view->SetBorder(views::Border::CreateEmptyBorder( |
| + 0, 0, views::kRelatedControlSmallVerticalSpacing, 0)); |
| + |
| + return view; |
| +} |
| + |
| views::View* ProfileChooserView::CreateCurrentProfileView( |
| const AvatarMenu::Item& avatar_item, |
| bool is_guest) { |