Commit 33508853 authored by noms@chromium.org's avatar noms@chromium.org

[Mac] Show a warning in the new avatar button/menu if there's an auth error.

This error is shown both in the avatar button, and in the avatar menu. When the 
account for which we're displaying the auth error is clicked in the avatar menu,
we show the Gaia reauth view.

Screenshot: 
https://drive.google.com/file/d/0B1B1Up4p2NRMQW90VmcwcGZQVEU/edit?usp=sharing

I've also fixed a bug where the available text for the account name was 
incorrectly calculated, and eliding overlapped the delete button. Screenshot:
https://drive.google.com/file/d/0B1B1Up4p2NRMaU9DcWdqTVZNMVk/edit?usp=sharing
BUG=311235
TEST= Sign into Chrome with the --new-profile-management flag on. Go to 
accounts.google.com and revoke Chrome's access to that account, from the 
Security tab. Try to bookmark the current page. The avatar button should be
badged like in the attached screenshot.

Review URL: https://codereview.chromium.org/303463010

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@277908 0039d316-1c4b-4281-b951-d872f2087c98
parent 7a46143e
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_metrics.h" #include "chrome/browser/profiles/profile_metrics.h"
#include "chrome/browser/signin/signin_header_helper.h" #include "chrome/browser/signin/signin_header_helper.h"
#include "chrome/browser/profiles/profiles_state.h"
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_commands.h" #include "chrome/browser/ui/browser_commands.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
...@@ -18,6 +19,7 @@ ...@@ -18,6 +19,7 @@
#import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h"
#import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h" #import "chrome/browser/ui/cocoa/profiles/avatar_menu_bubble_controller.h"
#import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h" #import "chrome/browser/ui/cocoa/profiles/profile_chooser_controller.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "components/signin/core/common/profile_management_switches.h" #include "components/signin/core/common/profile_management_switches.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
...@@ -27,50 +29,79 @@ const CGFloat kMenuYOffsetAdjust = 1.0; ...@@ -27,50 +29,79 @@ const CGFloat kMenuYOffsetAdjust = 1.0;
@interface AvatarBaseController (Private) @interface AvatarBaseController (Private)
// Shows the avatar bubble. // Shows the avatar bubble.
- (IBAction)buttonClicked:(id)sender; - (IBAction)buttonClicked:(id)sender;
- (void)bubbleWillClose:(NSNotification*)notif; - (void)bubbleWillClose:(NSNotification*)notif;
// Updates the profile name displayed by the avatar button. If |layoutParent| is // Updates the profile name displayed by the avatar button. If |layoutParent| is
// yes, then the BrowserWindowController is notified to relayout the subviews, // yes, then the BrowserWindowController is notified to relayout the subviews,
// as the button needs to be repositioned. // as the button needs to be repositioned.
- (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
// Displays an error icon if any accounts associated with this profile have an
// auth error.
- (void)updateErrorStatus:(BOOL)hasError;
@end @end
class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver { class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver,
public SigninErrorController::Observer {
public: public:
ProfileInfoUpdateObserver(AvatarBaseController* avatarButton) ProfileInfoUpdateObserver(Profile* profile,
: avatarButton_(avatarButton) { AvatarBaseController* avatarController)
: profile_(profile),
avatarController_(avatarController) {
g_browser_process->profile_manager()-> g_browser_process->profile_manager()->
GetProfileInfoCache().AddObserver(this); GetProfileInfoCache().AddObserver(this);
// Subscribe to authentication error changes so that the avatar button
// can update itself.
SigninErrorController* errorController =
profiles::GetSigninErrorController(profile_);
if (errorController)
errorController->AddObserver(this);
} }
virtual ~ProfileInfoUpdateObserver() { virtual ~ProfileInfoUpdateObserver() {
g_browser_process->profile_manager()-> g_browser_process->profile_manager()->
GetProfileInfoCache().RemoveObserver(this); GetProfileInfoCache().RemoveObserver(this);
SigninErrorController* errorController =
profiles::GetSigninErrorController(profile_);
if (errorController)
errorController->RemoveObserver(this);
} }
// ProfileInfoCacheObserver: // ProfileInfoCacheObserver:
virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE { virtual void OnProfileAdded(const base::FilePath& profile_path) OVERRIDE {
[avatarButton_ updateAvatarButtonAndLayoutParent:YES]; [avatarController_ updateAvatarButtonAndLayoutParent:YES];
} }
virtual void OnProfileWasRemoved( virtual void OnProfileWasRemoved(
const base::FilePath& profile_path, const base::FilePath& profile_path,
const base::string16& profile_name) OVERRIDE { const base::string16& profile_name) OVERRIDE {
[avatarButton_ updateAvatarButtonAndLayoutParent:YES]; [avatarController_ updateAvatarButtonAndLayoutParent:YES];
} }
virtual void OnProfileNameChanged( virtual void OnProfileNameChanged(
const base::FilePath& profile_path, const base::FilePath& profile_path,
const base::string16& old_profile_name) OVERRIDE { const base::string16& old_profile_name) OVERRIDE {
[avatarButton_ updateAvatarButtonAndLayoutParent:YES]; [avatarController_ updateAvatarButtonAndLayoutParent:YES];
} }
virtual void OnProfileAvatarChanged( virtual void OnProfileAvatarChanged(
const base::FilePath& profile_path) OVERRIDE { const base::FilePath& profile_path) OVERRIDE {
[avatarButton_ updateAvatarButtonAndLayoutParent:YES]; [avatarController_ updateAvatarButtonAndLayoutParent:YES];
}
// SigninErrorController::Observer:
virtual void OnErrorChanged() OVERRIDE {
SigninErrorController* errorController =
profiles::GetSigninErrorController(profile_);
if (errorController)
[avatarController_ updateErrorStatus:errorController->HasError()];
} }
private: private:
AvatarBaseController* avatarButton_; // Weak; owns this. Profile* profile_;
AvatarBaseController* avatarController_; // Weak; owns this.
DISALLOW_COPY_AND_ASSIGN(ProfileInfoUpdateObserver); DISALLOW_COPY_AND_ASSIGN(ProfileInfoUpdateObserver);
}; };
...@@ -80,7 +111,8 @@ class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver { ...@@ -80,7 +111,8 @@ class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver {
- (id)initWithBrowser:(Browser*)browser { - (id)initWithBrowser:(Browser*)browser {
if ((self = [super init])) { if ((self = [super init])) {
browser_ = browser; browser_ = browser;
profileInfoObserver_.reset(new ProfileInfoUpdateObserver(self)); profileInfoObserver_.reset(
new ProfileInfoUpdateObserver(browser_->profile(), self));
} }
return self; return self;
} }
...@@ -170,6 +202,9 @@ class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver { ...@@ -170,6 +202,9 @@ class ProfileInfoUpdateObserver : public ProfileInfoCacheObserver {
NOTREACHED(); NOTREACHED();
} }
- (void)updateErrorStatus:(BOOL)hasError {
}
- (BaseBubbleController*)menuController { - (BaseBubbleController*)menuController {
return menuController_; return menuController_;
} }
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/browser_window.h"
#import "chrome/browser/ui/cocoa/browser_window_controller.h" #import "chrome/browser/ui/cocoa/browser_window_controller.h"
#include "components/signin/core/browser/signin_error_controller.h"
#include "grit/generated_resources.h" #include "grit/generated_resources.h"
#include "grit/theme_resources.h" #include "grit/theme_resources.h"
#import "ui/base/cocoa/appkit_utils.h" #import "ui/base/cocoa/appkit_utils.h"
...@@ -19,6 +20,8 @@ ...@@ -19,6 +20,8 @@
#include "ui/base/l10n/l10n_util_mac.h" #include "ui/base/l10n/l10n_util_mac.h"
#include "ui/base/nine_image_painter_factory.h" #include "ui/base/nine_image_painter_factory.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_util_mac.h"
#include "ui/gfx/text_elider.h" #include "ui/gfx/text_elider.h"
namespace { namespace {
...@@ -49,21 +52,26 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -49,21 +52,26 @@ NSImage* GetImageFromResourceID(int resourceId) {
@interface CustomThemeButtonCell : NSButtonCell { @interface CustomThemeButtonCell : NSButtonCell {
@private @private
BOOL isThemedWindow_; BOOL isThemedWindow_;
base::scoped_nsobject<NSImage> authenticationErrorImage_;
} }
- (void)setIsThemedWindow:(BOOL)isThemedWindow; - (void)setIsThemedWindow:(BOOL)isThemedWindow;
- (void)setHasError:(BOOL)hasError;
@end @end
@implementation CustomThemeButtonCell @implementation CustomThemeButtonCell
- (id)initWithThemedWindow:(BOOL)isThemedWindow { - (id)initWithThemedWindow:(BOOL)isThemedWindow {
if ((self = [super init])) { if ((self = [super init])) {
isThemedWindow_ = isThemedWindow; isThemedWindow_ = isThemedWindow;
authenticationErrorImage_.reset();
} }
return self; return self;
} }
- (NSSize)cellSize { - (NSSize)cellSize {
NSSize buttonSize = [super cellSize]; NSSize buttonSize = [super cellSize];
buttonSize.width += 2 * kButtonPadding - 2 * kButtonDefaultPadding; CGFloat errorWidth = [authenticationErrorImage_ size].width;
buttonSize.width += 2 * (kButtonPadding - kButtonDefaultPadding) + errorWidth;
buttonSize.height = kButtonHeight; buttonSize.height = kButtonHeight;
return buttonSize; return buttonSize;
} }
...@@ -72,7 +80,27 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -72,7 +80,27 @@ NSImage* GetImageFromResourceID(int resourceId) {
withFrame:(NSRect)frame withFrame:(NSRect)frame
inView:(NSView*)controlView { inView:(NSView*)controlView {
frame.origin.x = kButtonPadding; frame.origin.x = kButtonPadding;
// Ensure there's always a padding between the text and the image.
// If there's an auth error, draw a warning icon before the cell image.
if (authenticationErrorImage_) {
NSSize imageSize = [authenticationErrorImage_ size];
NSRect rect = NSMakeRect(
frame.size.width - imageSize.width,
(kButtonHeight - imageSize.height) / 2,
imageSize.width,
imageSize.height);
[authenticationErrorImage_ drawInRect:rect
fromRect:NSZeroRect
operation:NSCompositeSourceOver
fraction:1.0
respectFlipped:YES
hints:nil];
// Padding between the title and the error image.
frame.size.width -= kButtonTitleImageSpacing;
}
// Padding between the title (or error image, if it exists) and the
// button's drop down image.
frame.size.width -= kButtonTitleImageSpacing; frame.size.width -= kButtonTitleImageSpacing;
return [super drawTitle:title withFrame:frame inView:controlView]; return [super drawTitle:title withFrame:frame inView:controlView];
} }
...@@ -106,11 +134,23 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -106,11 +134,23 @@ NSImage* GetImageFromResourceID(int resourceId) {
- (void)setIsThemedWindow:(BOOL)isThemedWindow { - (void)setIsThemedWindow:(BOOL)isThemedWindow {
isThemedWindow_ = isThemedWindow; isThemedWindow_ = isThemedWindow;
} }
- (void)setHasError:(BOOL)hasError {
if (hasError) {
authenticationErrorImage_.reset(
[ui::ResourceBundle::GetSharedInstance().GetImageNamed(
IDR_ICON_PROFILES_AVATAR_BUTTON_ERROR).ToNSImage() retain]);
} else {
authenticationErrorImage_.reset();
}
}
@end @end
@interface AvatarButtonController (Private) @interface AvatarButtonController (Private)
- (base::string16)getElidedAvatarName; - (base::string16)getElidedAvatarName;
- (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent; - (void)updateAvatarButtonAndLayoutParent:(BOOL)layoutParent;
- (void)updateErrorStatus:(BOOL)hasError;
- (void)dealloc; - (void)dealloc;
- (void)themeDidChangeNotification:(NSNotification*)aNotification; - (void)themeDidChangeNotification:(NSNotification*)aNotification;
@end @end
...@@ -135,6 +175,10 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -135,6 +175,10 @@ NSImage* GetImageFromResourceID(int resourceId) {
button_.reset(hoverButton); button_.reset(hoverButton);
base::scoped_nsobject<CustomThemeButtonCell> cell( base::scoped_nsobject<CustomThemeButtonCell> cell(
[[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]); [[CustomThemeButtonCell alloc] initWithThemedWindow:isThemedWindow_]);
SigninErrorController* errorController =
profiles::GetSigninErrorController(browser->profile());
if (errorController)
[cell setHasError:errorController->HasError()];
[button_ setCell:cell.get()]; [button_ setCell:cell.get()];
[self setView:button_]; [self setView:button_];
...@@ -156,7 +200,6 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -156,7 +200,6 @@ NSImage* GetImageFromResourceID(int resourceId) {
selector:@selector(themeDidChangeNotification:) selector:@selector(themeDidChangeNotification:)
name:kBrowserThemeDidChangeNotification name:kBrowserThemeDidChangeNotification
object:nil]; object:nil];
} }
return self; return self;
} }
...@@ -189,7 +232,6 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -189,7 +232,6 @@ NSImage* GetImageFromResourceID(int resourceId) {
// The button text has a black foreground and a white drop shadow for regular // The button text has a black foreground and a white drop shadow for regular
// windows, and a light text with a dark drop shadow for guest windows // windows, and a light text with a dark drop shadow for guest windows
// which are themed with a dark background. // which are themed with a dark background.
// TODO(noms): Figure out something similar for themed windows, if possible.
base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]); base::scoped_nsobject<NSShadow> shadow([[NSShadow alloc] init]);
[shadow setShadowOffset:NSMakeSize(0, -1)]; [shadow setShadowOffset:NSMakeSize(0, -1)];
[shadow setShadowBlurRadius:0]; [shadow setShadowBlurRadius:0];
...@@ -239,4 +281,9 @@ NSImage* GetImageFromResourceID(int resourceId) { ...@@ -239,4 +281,9 @@ NSImage* GetImageFromResourceID(int resourceId) {
} }
} }
- (void)updateErrorStatus:(BOOL)hasError {
[[button_ cell] setHasError:hasError];
[self updateAvatarButtonAndLayoutParent:YES];
}
@end @end
...@@ -106,6 +106,10 @@ class WebContents; ...@@ -106,6 +106,10 @@ class WebContents;
// account from the active profile if possible. // account from the active profile if possible.
- (IBAction)showAccountRemovalView:(id)sender; - (IBAction)showAccountRemovalView:(id)sender;
// Shows the account reauthentication view to re-sign in the currently selected
// account from the active profile if possible.
- (IBAction)showAccountReauthenticationView:(id)sender;
// Removes the current account |accountIdToRemove_|. // Removes the current account |accountIdToRemove_|.
- (IBAction)removeAccount:(id)sender; - (IBAction)removeAccount:(id)sender;
......
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