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 @@
#include "build/build_config.h"
#include "chrome/app/chrome_command_ids.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/profiles/avatar_menu.h"
#include "chrome/browser/profiles/profile.h"
......@@ -46,6 +47,9 @@ namespace {
constexpr base::TimeDelta kEmailExpansionDuration =
base::TimeDelta::FromSeconds(3);
constexpr base::TimeDelta kHighlightAnimationDuration =
base::TimeDelta::FromSeconds(2);
ProfileAttributesEntry* GetProfileAttributesEntry(Profile* profile) {
ProfileAttributesEntry* entry;
if (!g_browser_process->profile_manager()
......@@ -127,9 +131,15 @@ AvatarToolbarButton::AvatarToolbarButton(Browser* browser)
UpdateText();
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() {
// If widget isn't set, the button doesn't have access to the theme provider
......@@ -178,6 +188,14 @@ void AvatarToolbarButton::UpdateText() {
}
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:
color = AdjustHighlightColorForContrast(
GetThemeProvider(), gfx::kGoogleRed300, gfx::kGoogleRed600,
......@@ -203,10 +221,9 @@ void AvatarToolbarButton::UpdateText() {
SetTooltipText(GetAvatarTooltipText());
}
void AvatarToolbarButton::SetSuppressAvatarButtonState(
bool suppress_avatar_button_state) {
void AvatarToolbarButton::SetAutofillIconVisible(bool autofill_icon_visible) {
DCHECK_NE(GetState(), State::kIncognitoProfile);
suppress_avatar_button_state_ = suppress_avatar_button_state;
autofill_icon_visible_ = autofill_icon_visible;
UpdateText();
}
......@@ -302,6 +319,19 @@ void AvatarToolbarButton::OnTouchUiChanged() {
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() {
DCHECK(user_email_.has_value());
DCHECK(!waiting_for_image_to_show_user_email_);
......@@ -342,6 +372,7 @@ base::string16 AvatarToolbarButton::GetAvatarTooltipText() const {
return l10n_util::GetStringFUTF16(IDS_AVATAR_BUTTON_SYNC_PAUSED_TOOLTIP,
GetProfileName());
case State::kNormal:
case State::kHighlightAnimation:
return GetProfileName();
}
NOTREACHED();
......@@ -372,6 +403,7 @@ gfx::ImageSkia AvatarToolbarButton::GetAvatarIcon(
return gfx::CreateVectorIcon(kUserAccountAvatarIcon, icon_size,
icon_color);
case State::kAnimatedSignIn:
case State::kHighlightAnimation:
case State::kSyncError:
case State::kSyncPaused:
case State::kNormal:
......@@ -448,9 +480,12 @@ AvatarToolbarButton::State AvatarToolbarButton::GetState() const {
if (user_email_.has_value() && !waiting_for_image_to_show_user_email_)
return State::kAnimatedSignIn;
if (highlight_animation_visible_)
return State::kHighlightAnimation;
#if !defined(OS_CHROMEOS)
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
// icon is shown.
int unused;
......@@ -484,3 +519,13 @@ void AvatarToolbarButton::SetUserEmail(const std::string& user_email) {
waiting_for_image_to_show_user_email_ = true;
UpdateIcon();
}
void AvatarToolbarButton::ShowHighlightAnimation() {
highlight_animation_visible_ = true;
UpdateText();
}
void AvatarToolbarButton::HideHighlightAnimation() {
highlight_animation_visible_ = false;
UpdateText();
}
......@@ -14,6 +14,8 @@
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/browser_list_observer.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 "ui/base/material_design/material_design_controller_observer.h"
#include "ui/events/event.h"
......@@ -25,14 +27,15 @@ class AvatarToolbarButton : public ToolbarButton,
public BrowserListObserver,
public ProfileAttributesStorage::Observer,
public signin::IdentityManager::Observer,
public ui::MaterialDesignControllerObserver {
public ui::MaterialDesignControllerObserver,
public autofill::PersonalDataManagerObserver {
public:
explicit AvatarToolbarButton(Browser* browser);
~AvatarToolbarButton() override;
void UpdateIcon();
void UpdateText();
void SetSuppressAvatarButtonState(bool suppress_avatar_button_state);
void SetAutofillIconVisible(bool autofill_icon_visible);
private:
FRIEND_TEST_ALL_PREFIXES(AvatarToolbarButtonTest,
......@@ -43,6 +46,7 @@ class AvatarToolbarButton : public ToolbarButton,
kIncognitoProfile,
kGuestSession,
kGenericProfile,
kHighlightAnimation,
kAnimatedSignIn,
kSyncPaused,
kSyncError,
......@@ -84,6 +88,9 @@ class AvatarToolbarButton : public ToolbarButton,
// ui::MaterialDesignControllerObserver:
void OnTouchUiChanged() override;
// autofill::PersonalDataManagerObserver:
void OnCreditCardSaved() override;
void ExpandToShowEmail();
void ResetUserEmail();
......@@ -98,12 +105,22 @@ class AvatarToolbarButton : public ToolbarButton,
// Sets |user_email_| and initiates showing the email (if non-empty).
void SetUserEmail(const std::string& user_email);
void ShowHighlightAnimation();
void HideHighlightAnimation();
Browser* const browser_;
Profile* const profile_;
// Indicates if the avatar icon should show text and update highlight color
// when sync state is not normal.
bool suppress_avatar_button_state_ = false;
autofill::PersonalDataManager* personal_data_manager_;
// 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
// animation is in progress.
......
......@@ -158,12 +158,12 @@ void ToolbarPageActionIconContainerView::UpdateAvatarIconStateUi() {
if (browser_->profile()->IsIncognitoProfile())
return;
bool suppress_avatar_button_state = false;
bool autofill_icon_visible = false;
for (PageActionIconView* icon_view : page_action_icons_) {
if (icon_view->GetVisible()) {
suppress_avatar_button_state = true;
autofill_icon_visible = true;
break;
}
}
avatar_->SetSuppressAvatarButtonState(suppress_avatar_button_state);
avatar_->SetAutofillIconVisible(autofill_icon_visible);
}
......@@ -311,6 +311,11 @@ void CreditCardSaveManager::OnDidUploadCard(
// removed.
GetCreditCardSaveStrikeDatabase()->ClearStrikes(
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()) {
// 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.
......
......@@ -330,6 +330,12 @@ void LocalCardMigrationManager::OnDidMigrateLocalCards(
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.
personal_data_manager_->DeleteLocalCreditCards(migrated_cards);
}
......
......@@ -47,6 +47,7 @@
#include "components/autofill/core/common/autofill_clock.h"
#include "components/autofill/core/common/autofill_constants.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_switches.h"
#include "components/autofill/core/common/autofill_util.h"
......@@ -1799,6 +1800,10 @@ std::string PersonalDataManager::SaveImportedCreditCard(
credit_cards.push_back(imported_card);
SetCreditCards(&credit_cards);
// After a card is saved locally, notifies the observers.
OnCreditCardSaved();
return guid;
}
......@@ -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(
const AutofillType& type,
const base::string16& field_contents,
......
......@@ -387,6 +387,9 @@ class PersonalDataManager : public KeyedService,
// Notifies observers that the waiting should be stopped.
void NotifyPersonalDataObserver();
// Called when at least one (can be multiple) card was saved.
void OnCreditCardSaved();
void set_client_profile_validator_for_test(
AutofillProfileValidator* validator) {
client_profile_validator_ = validator;
......
......@@ -13,7 +13,7 @@ namespace autofill {
class PersonalDataManagerObserver {
public:
// 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.
virtual void OnInsufficientFormData() {}
......@@ -22,6 +22,13 @@ class PersonalDataManagerObserver {
// handle.
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:
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