Commit 294d8c72 authored by siyua's avatar siyua Committed by Commit Bot

[Upstream Feedback] Add avatar highlight animation

This CL adds the blue round circle highlight animation around the avatar
button. It reuses the ink drop hover animation but with a different color.

Whenever the animation is visible, hide the avatar sync paused/error
state, even if there is no autofill icon visible in the status chip.

Controlled by experiment flag kAutofillCreditCardUploadFeedback: No
event will be sent to avatar icon if flag is disabled.

The animation will be shown when any credit card is saved. Animation
for password save will be added later.

Bug: 964127
Change-Id: Icc386241e244a6bf9f3db271928ca19029348f81
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1784138
Commit-Queue: Siyu An <siyua@chromium.org>
Reviewed-by: default avatarJan Krcal <jkrcal@chromium.org>
Reviewed-by: default avatarPeter Boström <pbos@chromium.org>
Reviewed-by: default avatarChristos Froussios <cfroussios@chromium.org>
Reviewed-by: default avatarJared Saul <jsaul@google.com>
Cr-Commit-Position: refs/heads/master@{#695046}
parent 954e1ea4
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/app/chrome_command_ids.h" #include "chrome/app/chrome_command_ids.h"
#include "chrome/app/vector_icons/vector_icons.h" #include "chrome/app/vector_icons/vector_icons.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/browser_process.h" #include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/avatar_menu.h" #include "chrome/browser/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -46,6 +47,9 @@ namespace { ...@@ -46,6 +47,9 @@ namespace {
constexpr base::TimeDelta kEmailExpansionDuration = constexpr base::TimeDelta kEmailExpansionDuration =
base::TimeDelta::FromSeconds(3); base::TimeDelta::FromSeconds(3);
constexpr base::TimeDelta kHighlightAnimationDuration =
base::TimeDelta::FromSeconds(2);
ProfileAttributesEntry* GetProfileAttributesEntry(Profile* profile) { ProfileAttributesEntry* GetProfileAttributesEntry(Profile* profile) {
ProfileAttributesEntry* entry; ProfileAttributesEntry* entry;
if (!g_browser_process->profile_manager() if (!g_browser_process->profile_manager()
...@@ -127,9 +131,15 @@ AvatarToolbarButton::AvatarToolbarButton(Browser* browser) ...@@ -127,9 +131,15 @@ AvatarToolbarButton::AvatarToolbarButton(Browser* browser)
UpdateText(); UpdateText();
md_observer_.Add(ui::MaterialDesignController::GetInstance()); md_observer_.Add(ui::MaterialDesignController::GetInstance());
personal_data_manager_ = autofill::PersonalDataManagerFactory::GetForProfile(
profile_->GetOriginalProfile());
personal_data_manager_->AddObserver(this);
} }
AvatarToolbarButton::~AvatarToolbarButton() {} AvatarToolbarButton::~AvatarToolbarButton() {
personal_data_manager_->RemoveObserver(this);
}
void AvatarToolbarButton::UpdateIcon() { void AvatarToolbarButton::UpdateIcon() {
// If widget isn't set, the button doesn't have access to the theme provider // If widget isn't set, the button doesn't have access to the theme provider
...@@ -178,6 +188,14 @@ void AvatarToolbarButton::UpdateText() { ...@@ -178,6 +188,14 @@ void AvatarToolbarButton::UpdateText() {
} }
break; break;
} }
case State::kHighlightAnimation:
// If the highlight animation is visible, hide the avatar sync
// paused/error state even if there is no autofill icon visible in the
// parent container.
color = AdjustHighlightColorForContrast(
GetThemeProvider(), gfx::kGoogleBlue300, gfx::kGoogleBlue600,
gfx::kGoogleBlue050, gfx::kGoogleBlue900);
break;
case State::kSyncError: case State::kSyncError:
color = AdjustHighlightColorForContrast( color = AdjustHighlightColorForContrast(
GetThemeProvider(), gfx::kGoogleRed300, gfx::kGoogleRed600, GetThemeProvider(), gfx::kGoogleRed300, gfx::kGoogleRed600,
...@@ -203,10 +221,9 @@ void AvatarToolbarButton::UpdateText() { ...@@ -203,10 +221,9 @@ void AvatarToolbarButton::UpdateText() {
SetTooltipText(GetAvatarTooltipText()); SetTooltipText(GetAvatarTooltipText());
} }
void AvatarToolbarButton::SetSuppressAvatarButtonState( void AvatarToolbarButton::SetAutofillIconVisible(bool autofill_icon_visible) {
bool suppress_avatar_button_state) {
DCHECK_NE(GetState(), State::kIncognitoProfile); DCHECK_NE(GetState(), State::kIncognitoProfile);
suppress_avatar_button_state_ = suppress_avatar_button_state; autofill_icon_visible_ = autofill_icon_visible;
UpdateText(); UpdateText();
} }
...@@ -302,6 +319,19 @@ void AvatarToolbarButton::OnTouchUiChanged() { ...@@ -302,6 +319,19 @@ void AvatarToolbarButton::OnTouchUiChanged() {
PreferredSizeChanged(); PreferredSizeChanged();
} }
void AvatarToolbarButton::OnCreditCardSaved() {
DCHECK_NE(GetState(), State::kIncognitoProfile);
DCHECK_NE(GetState(), State::kGuestSession);
DCHECK(!profile_->IsOffTheRecord());
ShowHighlightAnimation();
base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
FROM_HERE,
base::BindOnce(&AvatarToolbarButton::HideHighlightAnimation,
weak_ptr_factory_.GetWeakPtr()),
kHighlightAnimationDuration);
}
void AvatarToolbarButton::ExpandToShowEmail() { void AvatarToolbarButton::ExpandToShowEmail() {
DCHECK(user_email_.has_value()); DCHECK(user_email_.has_value());
DCHECK(!waiting_for_image_to_show_user_email_); DCHECK(!waiting_for_image_to_show_user_email_);
...@@ -342,6 +372,7 @@ base::string16 AvatarToolbarButton::GetAvatarTooltipText() const { ...@@ -342,6 +372,7 @@ base::string16 AvatarToolbarButton::GetAvatarTooltipText() const {
return l10n_util::GetStringFUTF16(IDS_AVATAR_BUTTON_SYNC_PAUSED_TOOLTIP, return l10n_util::GetStringFUTF16(IDS_AVATAR_BUTTON_SYNC_PAUSED_TOOLTIP,
GetProfileName()); GetProfileName());
case State::kNormal: case State::kNormal:
case State::kHighlightAnimation:
return GetProfileName(); return GetProfileName();
} }
NOTREACHED(); NOTREACHED();
...@@ -372,6 +403,7 @@ gfx::ImageSkia AvatarToolbarButton::GetAvatarIcon( ...@@ -372,6 +403,7 @@ gfx::ImageSkia AvatarToolbarButton::GetAvatarIcon(
return gfx::CreateVectorIcon(kUserAccountAvatarIcon, icon_size, return gfx::CreateVectorIcon(kUserAccountAvatarIcon, icon_size,
icon_color); icon_color);
case State::kAnimatedSignIn: case State::kAnimatedSignIn:
case State::kHighlightAnimation:
case State::kSyncError: case State::kSyncError:
case State::kSyncPaused: case State::kSyncPaused:
case State::kNormal: case State::kNormal:
...@@ -448,9 +480,12 @@ AvatarToolbarButton::State AvatarToolbarButton::GetState() const { ...@@ -448,9 +480,12 @@ AvatarToolbarButton::State AvatarToolbarButton::GetState() const {
if (user_email_.has_value() && !waiting_for_image_to_show_user_email_) if (user_email_.has_value() && !waiting_for_image_to_show_user_email_)
return State::kAnimatedSignIn; return State::kAnimatedSignIn;
if (highlight_animation_visible_)
return State::kHighlightAnimation;
#if !defined(OS_CHROMEOS) #if !defined(OS_CHROMEOS)
if (identity_manager->HasPrimaryAccount() && profile_->IsSyncAllowed() && if (identity_manager->HasPrimaryAccount() && profile_->IsSyncAllowed() &&
error_controller_.HasAvatarError() && !suppress_avatar_button_state_) { error_controller_.HasAvatarError() && !autofill_icon_visible_) {
// When DICE is enabled and the error is an auth error, the sync-paused // When DICE is enabled and the error is an auth error, the sync-paused
// icon is shown. // icon is shown.
int unused; int unused;
...@@ -484,3 +519,13 @@ void AvatarToolbarButton::SetUserEmail(const std::string& user_email) { ...@@ -484,3 +519,13 @@ void AvatarToolbarButton::SetUserEmail(const std::string& user_email) {
waiting_for_image_to_show_user_email_ = true; waiting_for_image_to_show_user_email_ = true;
UpdateIcon(); UpdateIcon();
} }
void AvatarToolbarButton::ShowHighlightAnimation() {
highlight_animation_visible_ = true;
UpdateText();
}
void AvatarToolbarButton::HideHighlightAnimation() {
highlight_animation_visible_ = false;
UpdateText();
}
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
#include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_list_observer.h" #include "chrome/browser/ui/browser_list_observer.h"
#include "chrome/browser/ui/views/toolbar/toolbar_button.h" #include "chrome/browser/ui/views/toolbar/toolbar_button.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/signin/public/identity_manager/identity_manager.h" #include "components/signin/public/identity_manager/identity_manager.h"
#include "ui/base/material_design/material_design_controller_observer.h" #include "ui/base/material_design/material_design_controller_observer.h"
#include "ui/events/event.h" #include "ui/events/event.h"
...@@ -25,14 +27,15 @@ class AvatarToolbarButton : public ToolbarButton, ...@@ -25,14 +27,15 @@ class AvatarToolbarButton : public ToolbarButton,
public BrowserListObserver, public BrowserListObserver,
public ProfileAttributesStorage::Observer, public ProfileAttributesStorage::Observer,
public signin::IdentityManager::Observer, public signin::IdentityManager::Observer,
public ui::MaterialDesignControllerObserver { public ui::MaterialDesignControllerObserver,
public autofill::PersonalDataManagerObserver {
public: public:
explicit AvatarToolbarButton(Browser* browser); explicit AvatarToolbarButton(Browser* browser);
~AvatarToolbarButton() override; ~AvatarToolbarButton() override;
void UpdateIcon(); void UpdateIcon();
void UpdateText(); void UpdateText();
void SetSuppressAvatarButtonState(bool suppress_avatar_button_state); void SetAutofillIconVisible(bool autofill_icon_visible);
private: private:
FRIEND_TEST_ALL_PREFIXES(AvatarToolbarButtonTest, FRIEND_TEST_ALL_PREFIXES(AvatarToolbarButtonTest,
...@@ -43,6 +46,7 @@ class AvatarToolbarButton : public ToolbarButton, ...@@ -43,6 +46,7 @@ class AvatarToolbarButton : public ToolbarButton,
kIncognitoProfile, kIncognitoProfile,
kGuestSession, kGuestSession,
kGenericProfile, kGenericProfile,
kHighlightAnimation,
kAnimatedSignIn, kAnimatedSignIn,
kSyncPaused, kSyncPaused,
kSyncError, kSyncError,
...@@ -84,6 +88,9 @@ class AvatarToolbarButton : public ToolbarButton, ...@@ -84,6 +88,9 @@ class AvatarToolbarButton : public ToolbarButton,
// ui::MaterialDesignControllerObserver: // ui::MaterialDesignControllerObserver:
void OnTouchUiChanged() override; void OnTouchUiChanged() override;
// autofill::PersonalDataManagerObserver:
void OnCreditCardSaved() override;
void ExpandToShowEmail(); void ExpandToShowEmail();
void ResetUserEmail(); void ResetUserEmail();
...@@ -98,12 +105,22 @@ class AvatarToolbarButton : public ToolbarButton, ...@@ -98,12 +105,22 @@ class AvatarToolbarButton : public ToolbarButton,
// Sets |user_email_| and initiates showing the email (if non-empty). // Sets |user_email_| and initiates showing the email (if non-empty).
void SetUserEmail(const std::string& user_email); void SetUserEmail(const std::string& user_email);
void ShowHighlightAnimation();
void HideHighlightAnimation();
Browser* const browser_; Browser* const browser_;
Profile* const profile_; Profile* const profile_;
// Indicates if the avatar icon should show text and update highlight color autofill::PersonalDataManager* personal_data_manager_;
// when sync state is not normal.
bool suppress_avatar_button_state_ = false; // Whether the avatar highlight animation is visible. If true, hide avatar
// button sync paused/error state and update highlight color.
bool highlight_animation_visible_ = false;
// Whether any autofill icon is visible in |this|'s parent container. Set by
// |ToolbarPageActionIconContainerView|. If true, hide avatar button sync
// paused/error state.
bool autofill_icon_visible_ = false;
// The user email that we're currently showing in an animation or empty if no // The user email that we're currently showing in an animation or empty if no
// animation is in progress. // animation is in progress.
......
...@@ -158,12 +158,12 @@ void ToolbarPageActionIconContainerView::UpdateAvatarIconStateUi() { ...@@ -158,12 +158,12 @@ void ToolbarPageActionIconContainerView::UpdateAvatarIconStateUi() {
if (browser_->profile()->IsIncognitoProfile()) if (browser_->profile()->IsIncognitoProfile())
return; return;
bool suppress_avatar_button_state = false; bool autofill_icon_visible = false;
for (PageActionIconView* icon_view : page_action_icons_) { for (PageActionIconView* icon_view : page_action_icons_) {
if (icon_view->GetVisible()) { if (icon_view->GetVisible()) {
suppress_avatar_button_state = true; autofill_icon_visible = true;
break; break;
} }
} }
avatar_->SetSuppressAvatarButtonState(suppress_avatar_button_state); avatar_->SetAutofillIconVisible(autofill_icon_visible);
} }
...@@ -311,6 +311,11 @@ void CreditCardSaveManager::OnDidUploadCard( ...@@ -311,6 +311,11 @@ void CreditCardSaveManager::OnDidUploadCard(
// removed. // removed.
GetCreditCardSaveStrikeDatabase()->ClearStrikes( GetCreditCardSaveStrikeDatabase()->ClearStrikes(
base::UTF16ToUTF8(upload_request_.card.LastFourDigits())); base::UTF16ToUTF8(upload_request_.card.LastFourDigits()));
// After a card is successfully saved to server, notifies the
// |personal_data_manager_|. PDM uses this information to update the avatar
// button UI.
personal_data_manager_->OnCreditCardSaved();
} else if (show_save_prompt_.has_value() && show_save_prompt_.value()) { } else if (show_save_prompt_.has_value() && show_save_prompt_.value()) {
// If the upload failed and the bubble was actually shown (NOT just the // If the upload failed and the bubble was actually shown (NOT just the
// icon), count that as a strike against offering upload in the future. // icon), count that as a strike against offering upload in the future.
......
...@@ -330,6 +330,12 @@ void LocalCardMigrationManager::OnDidMigrateLocalCards( ...@@ -330,6 +330,12 @@ void LocalCardMigrationManager::OnDidMigrateLocalCards(
NOTREACHED(); NOTREACHED();
} }
} }
// If at least one card was migrated, notifies the |personal_data_manager_|.
// PDM uses this information to update the avatar button UI.
if (!migrated_cards.empty())
personal_data_manager_->OnCreditCardSaved();
// Remove cards that were successfully migrated from local storage. // Remove cards that were successfully migrated from local storage.
personal_data_manager_->DeleteLocalCreditCards(migrated_cards); personal_data_manager_->DeleteLocalCreditCards(migrated_cards);
} }
......
...@@ -47,6 +47,7 @@ ...@@ -47,6 +47,7 @@
#include "components/autofill/core/common/autofill_clock.h" #include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.h" #include "components/autofill/core/common/autofill_constants.h"
#include "components/autofill/core/common/autofill_features.h" #include "components/autofill/core/common/autofill_features.h"
#include "components/autofill/core/common/autofill_payments_features.h"
#include "components/autofill/core/common/autofill_prefs.h" #include "components/autofill/core/common/autofill_prefs.h"
#include "components/autofill/core/common/autofill_switches.h" #include "components/autofill/core/common/autofill_switches.h"
#include "components/autofill/core/common/autofill_util.h" #include "components/autofill/core/common/autofill_util.h"
...@@ -1799,6 +1800,10 @@ std::string PersonalDataManager::SaveImportedCreditCard( ...@@ -1799,6 +1800,10 @@ std::string PersonalDataManager::SaveImportedCreditCard(
credit_cards.push_back(imported_card); credit_cards.push_back(imported_card);
SetCreditCards(&credit_cards); SetCreditCards(&credit_cards);
// After a card is saved locally, notifies the observers.
OnCreditCardSaved();
return guid; return guid;
} }
...@@ -2033,6 +2038,15 @@ void PersonalDataManager::NotifyPersonalDataObserver() { ...@@ -2033,6 +2038,15 @@ void PersonalDataManager::NotifyPersonalDataObserver() {
} }
} }
void PersonalDataManager::OnCreditCardSaved() {
if (!base::FeatureList::IsEnabled(
features::kAutofillCreditCardUploadFeedback)) {
return;
}
for (PersonalDataManagerObserver& observer : observers_)
observer.OnCreditCardSaved();
}
std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards( std::vector<Suggestion> PersonalDataManager::GetSuggestionsForCards(
const AutofillType& type, const AutofillType& type,
const base::string16& field_contents, const base::string16& field_contents,
......
...@@ -387,6 +387,9 @@ class PersonalDataManager : public KeyedService, ...@@ -387,6 +387,9 @@ class PersonalDataManager : public KeyedService,
// Notifies observers that the waiting should be stopped. // Notifies observers that the waiting should be stopped.
void NotifyPersonalDataObserver(); void NotifyPersonalDataObserver();
// Called when at least one (can be multiple) card was saved.
void OnCreditCardSaved();
void set_client_profile_validator_for_test( void set_client_profile_validator_for_test(
AutofillProfileValidator* validator) { AutofillProfileValidator* validator) {
client_profile_validator_ = validator; client_profile_validator_ = validator;
......
...@@ -13,7 +13,7 @@ namespace autofill { ...@@ -13,7 +13,7 @@ namespace autofill {
class PersonalDataManagerObserver { class PersonalDataManagerObserver {
public: public:
// Notifies the observer that the PersonalDataManager changed in some way. // Notifies the observer that the PersonalDataManager changed in some way.
virtual void OnPersonalDataChanged() = 0; virtual void OnPersonalDataChanged() {}
// Called when there is insufficient data to fill a form. Used for testing. // Called when there is insufficient data to fill a form. Used for testing.
virtual void OnInsufficientFormData() {} virtual void OnInsufficientFormData() {}
...@@ -22,6 +22,13 @@ class PersonalDataManagerObserver { ...@@ -22,6 +22,13 @@ class PersonalDataManagerObserver {
// handle. // handle.
virtual void OnPersonalDataFinishedProfileTasks() {} virtual void OnPersonalDataFinishedProfileTasks() {}
// Notifies the observer whenever at least one (can be multiple) credit card
// is suceesfully saved.
// TODO(crbug.com/964127): Need to add a bool to separate server card save and
// local card save to decide whether to show the Autofill sign-in after local
// save promo bubble.
virtual void OnCreditCardSaved() {}
protected: protected:
virtual ~PersonalDataManagerObserver() {} virtual ~PersonalDataManagerObserver() {}
}; };
......
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