diff options
author | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-16 05:50:23 +0000 |
---|---|---|
committer | tbarzic@chromium.org <tbarzic@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-08-16 05:50:23 +0000 |
commit | 5975bc36fe10b3b9908ad2201b07b9a577c4f560 (patch) | |
tree | 7cdc7407e1d865b45c7eb4cb20ec90b7803f6b98 | |
parent | 2317849378238f140346278a6a5661beeac39645 (diff) | |
download | chromium_src-5975bc36fe10b3b9908ad2201b07b9a577c4f560.zip chromium_src-5975bc36fe10b3b9908ad2201b07b9a577c4f560.tar.gz chromium_src-5975bc36fe10b3b9908ad2201b07b9a577c4f560.tar.bz2 |
Easy Unlock: Add support for hard locking
When user clicks on the easy-unlock icon on "Click to enter" lock screen
(i.e. when lock screen auth type is USER_CLICK), the lock screen changes to
state in which password is required to unlock the screen.
This adds new auth state FORCE_OFFLINE_PASSWORD which, unlike OFFLINE_PASSWORD,
can't be changed to any other.
BUG=397363
TBR=asargent@chromium.org
Review URL: https://codereview.chromium.org/456943003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@290096 0039d316-1c4b-4281-b951-d872f2087c98
12 files changed, 246 insertions, 41 deletions
diff --git a/chrome/browser/chromeos/login/screens/user_selection_screen.cc b/chrome/browser/chromeos/login/screens/user_selection_screen.cc index 41c3024..e969589 100644 --- a/chrome/browser/chromeos/login/screens/user_selection_screen.cc +++ b/chrome/browser/chromeos/login/screens/user_selection_screen.cc @@ -362,6 +362,9 @@ void UserSelectionScreen::HandleGetUsers() { void UserSelectionScreen::SetAuthType( const std::string& username, ScreenlockBridge::LockHandler::AuthType auth_type) { + DCHECK(GetAuthType(username) != + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD || + auth_type == ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD); user_auth_type_map_[username] = auth_type; } diff --git a/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc b/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc index eb7b6e2..f5e44b2 100644 --- a/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc +++ b/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc @@ -57,6 +57,8 @@ screenlock::AuthType FromLockHandlerAuthType( // locking. NOTREACHED(); return screenlock::AUTH_TYPE_NONE; + case ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD: + return screenlock::AUTH_TYPE_OFFLINEPASSWORD; } NOTREACHED(); return screenlock::AUTH_TYPE_OFFLINEPASSWORD; diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc index 13816fc..5ddb98f 100644 --- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc +++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc @@ -49,6 +49,10 @@ bool HasAnimation(EasyUnlockScreenlockStateHandler::State state) { return state == EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING; } +bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state) { + return state == EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED; +} + size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state) { switch (state) { case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH: @@ -64,9 +68,7 @@ size_t GetTooltipResourceId(EasyUnlockScreenlockStateHandler::State state) { case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY: return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_PHONE_NOT_NEARBY; case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED: - // TODO(tbarzic): When hard lock is enabled change this to - // IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS. - return 0; + return IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK_INSTRUCTIONS; default: return 0; } @@ -99,10 +101,13 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) { state_ = new_state; - // If lock screen is not active, just cache the current state. - // The screenlock state will get refreshed in |ScreenDidLock|. - if (!screenlock_bridge_->IsLocked()) + // If lock screen is not active or it forces offline password, just cache the + // current state. The screenlock state will get refreshed in |ScreenDidLock|. + if (!screenlock_bridge_->IsLocked() || + screenlock_bridge_->lock_handler()->GetAuthType(user_email_) == + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD) { return; + } UpdateScreenlockAuthType(); @@ -115,7 +120,9 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) { } icon_options.SetIconAsResourceURL(icon_url); - UpdateTooltipOptions(&icon_options); + bool trial_run = IsTrialRun(); + + UpdateTooltipOptions(trial_run, &icon_options); if (UseOpaqueIcon(state_)) icon_options.SetOpacity(kOpaqueIconOpacity); @@ -125,6 +132,13 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) { if (HasAnimation(state_)) icon_options.SetAnimation(kSpinnerResourceWidth, kSpinnerIntervalMs); + // Hardlocking is disabled in trial run. + if (!trial_run && HardlockOnClick(state_)) + icon_options.SetHardlockOnClick(); + + if (trial_run && state_ == STATE_AUTHENTICATED) + MarkTrialRunComplete(); + screenlock_bridge_->lock_handler()->ShowUserPodCustomIcon(user_email_, icon_options); } @@ -140,12 +154,11 @@ void EasyUnlockScreenlockStateHandler::OnScreenDidUnlock() { } void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions( + bool trial_run, ScreenlockBridge::UserPodCustomIconOptions* icon_options) { - bool show_tutorial = ShouldShowTutorial(); - size_t resource_id = 0; base::string16 device_name; - if (show_tutorial) { + if (trial_run && state_ == STATE_AUTHENTICATED) { resource_id = IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_TUTORIAL; } else { resource_id = GetTooltipResourceId(state_); @@ -166,20 +179,17 @@ void EasyUnlockScreenlockStateHandler::UpdateTooltipOptions( if (tooltip.empty()) return; - if (show_tutorial) - MarkTutorialShown(); - - icon_options->SetTooltip(tooltip, show_tutorial /* autoshow tooltip */); + icon_options->SetTooltip( + tooltip, + state_ == STATE_AUTHENTICATED && trial_run /* autoshow tooltip */); } -bool EasyUnlockScreenlockStateHandler::ShouldShowTutorial() { - if (state_ != STATE_AUTHENTICATED) - return false; +bool EasyUnlockScreenlockStateHandler::IsTrialRun() { return pref_service_ && pref_service_->GetBoolean(prefs::kEasyUnlockShowTutorial); } -void EasyUnlockScreenlockStateHandler::MarkTutorialShown() { +void EasyUnlockScreenlockStateHandler::MarkTrialRunComplete() { if (!pref_service_) return; pref_service_->SetBoolean(prefs::kEasyUnlockShowTutorial, false); @@ -195,6 +205,10 @@ base::string16 EasyUnlockScreenlockStateHandler::GetDeviceName() { } void EasyUnlockScreenlockStateHandler::UpdateScreenlockAuthType() { + if (screenlock_bridge_->lock_handler()->GetAuthType(user_email_) == + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD) + return; + if (state_ == STATE_AUTHENTICATED) { screenlock_bridge_->lock_handler()->SetAuthType( user_email_, diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.h b/chrome/browser/signin/easy_unlock_screenlock_state_handler.h index dc5c2cc..e99c09b 100644 --- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.h +++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.h @@ -61,17 +61,20 @@ class EasyUnlockScreenlockStateHandler : public ScreenlockBridge::Observer { virtual void OnScreenDidLock() OVERRIDE; virtual void OnScreenDidUnlock() OVERRIDE; + // Updates icon's tooltip options. + // |trial_run|: Whether the trial Easy Unlock run is in progress. void UpdateTooltipOptions( + bool trial_run, ScreenlockBridge::UserPodCustomIconOptions* icon_options); - // Whether the tutorial message should be shown to the user. The message is - // shown only once, when the user encounters STATE_AUTHENTICATED for the first - // time (across sessions). After the tutorial message is shown, - // |MarkTutorialShown| should be called to prevent further tutorial message. - bool ShouldShowTutorial(); + // Whether this is the first, trial Easy Unlock run. If this is the case, a + // tutorial message should be shown and hard-locking be disabled in + // Authenticated state. The trial run will be active if Easy Unlock never + // entered Authenticated state (across sessions). + bool IsTrialRun(); - // Sets user preference that prevents showing of tutorial messages. - void MarkTutorialShown(); + // Sets user preference that marks trial run completed. + void MarkTrialRunComplete(); // Gets the name to be used for the device. The name depends on the device // type (example values: Chromebook and Chromebox). diff --git a/chrome/browser/signin/screenlock_bridge.cc b/chrome/browser/signin/screenlock_bridge.cc index 56c2910..4a95429 100644 --- a/chrome/browser/signin/screenlock_bridge.cc +++ b/chrome/browser/signin/screenlock_bridge.cc @@ -37,7 +37,8 @@ ScreenlockBridge::UserPodCustomIconOptions::UserPodCustomIconOptions() animation_resource_width_(0u), animation_frame_length_ms_(0u), opacity_(100u), - autoshow_tooltip_(false) { + autoshow_tooltip_(false), + hardlock_on_click_(false) { } ScreenlockBridge::UserPodCustomIconOptions::~UserPodCustomIconOptions() {} @@ -86,6 +87,10 @@ ScreenlockBridge::UserPodCustomIconOptions::ToDictionaryValue() const { animation_frame_length_ms_); result->Set("animation", animation); } + + if (hardlock_on_click_) + result->SetBoolean("hardlockOnClick", true); + return result.Pass(); } @@ -130,6 +135,10 @@ void ScreenlockBridge::UserPodCustomIconOptions::SetTooltip( autoshow_tooltip_ = autoshow; } +void ScreenlockBridge::UserPodCustomIconOptions::SetHardlockOnClick() { + hardlock_on_click_ = true; +} + // static std::string ScreenlockBridge::GetAuthenticatedUserEmail(Profile* profile) { // |profile| has to be a signed-in profile with SigninManager already diff --git a/chrome/browser/signin/screenlock_bridge.h b/chrome/browser/signin/screenlock_bridge.h index 72cec43..5391ca3 100644 --- a/chrome/browser/signin/screenlock_bridge.h +++ b/chrome/browser/signin/screenlock_bridge.h @@ -78,6 +78,10 @@ class ScreenlockBridge { // shown with the icon. void SetTooltip(const base::string16& tooltip, bool autoshow); + // If hardlock on click is set, clicking the icon in the screenlock will + // go to state where password is required for unlock. + void SetHardlockOnClick(); + private: std::string icon_resource_url_; scoped_ptr<gfx::Image> icon_image_; @@ -95,6 +99,8 @@ class ScreenlockBridge { base::string16 tooltip_; bool autoshow_tooltip_; + bool hardlock_on_click_; + DISALLOW_COPY_AND_ASSIGN(UserPodCustomIconOptions); }; @@ -108,6 +114,7 @@ class ScreenlockBridge { NUMERIC_PIN = 2, USER_CLICK = 3, EXPAND_THEN_USER_CLICK = 4, + FORCE_OFFLINE_PASSWORD = 5 }; // Displays |message| in a banner on the lock screen. diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc index 9ff3d1f..b6ff43c 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.cc @@ -764,6 +764,7 @@ void SigninScreenHandler::RegisterMessages() { AddCallback("updateOfflineLogin", &SigninScreenHandler::HandleUpdateOfflineLogin); AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod); + AddCallback("hardlockPod", &SigninScreenHandler::HandleHardlockPod); AddCallback("retrieveAuthenticatedUserEmail", &SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail); AddCallback("getPublicSessionKeyboardLayouts", @@ -948,6 +949,10 @@ void SigninScreenHandler::SetAuthType( const std::string& username, ScreenlockBridge::LockHandler::AuthType auth_type, const base::string16& initial_value) { + if (delegate_->GetAuthType(username) == + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD) + return; + delegate_->SetAuthType(username, auth_type); CallJS("login.AccountPickerScreen.setAuthType", @@ -1304,6 +1309,13 @@ void SigninScreenHandler::HandleFocusPod(const std::string& user_id) { WallpaperManager::Get()->SetUserWallpaperDelayed(user_id); } +void SigninScreenHandler::HandleHardlockPod(const std::string& user_id) { + SetAuthType(user_id, + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD, + base::string16()); + HideUserPodCustomIcon(user_id); +} + void SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail( double attempt_token) { // TODO(antrim) : move GaiaSigninScreen dependency to GaiaSigninScreen. diff --git a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h index 86d4dda..4656185 100644 --- a/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h @@ -370,6 +370,7 @@ class SigninScreenHandler void HandleUpdateOfflineLogin(bool offline_login_active); void HandleShowSupervisedUserCreationScreen(); void HandleFocusPod(const std::string& user_id); + void HandleHardlockPod(const std::string& user_id); void HandleLaunchKioskApp(const std::string& app_id, bool diagnostic_mode); void HandleRetrieveAuthenticatedUserEmail(double attempt_token); void HandleGetPublicSessionKeyboardLayouts(const std::string& user_id, diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc index c8104f7..4314bc0 100644 --- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc +++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.cc @@ -257,6 +257,10 @@ void UserManagerScreenHandler::SetAuthType( const std::string& user_email, ScreenlockBridge::LockHandler::AuthType auth_type, const base::string16& auth_value) { + if (GetAuthType(user_email) == + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD) + return; + user_auth_type_map_[user_email] = auth_type; web_ui()->CallJavascriptFunction( "login.AccountPickerScreen.setAuthType", @@ -430,6 +434,16 @@ void UserManagerScreenHandler::HandleAttemptUnlock( GetScreenlockRouter(email)->OnAuthAttempted(GetAuthType(email), ""); } +void UserManagerScreenHandler::HandleHardlockUserPod( + const base::ListValue* args) { + std::string email; + CHECK(args->GetString(0, &email)); + SetAuthType(email, + ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD, + base::string16()); + HideUserPodCustomIcon(email); +} + void UserManagerScreenHandler::OnClientLoginSuccess( const ClientLoginResult& result) { chrome::SetLocalAuthCredentials(authenticating_profile_index_, diff --git a/chrome/browser/ui/webui/signin/user_manager_screen_handler.h b/chrome/browser/ui/webui/signin/user_manager_screen_handler.h index 8339d61f..1e7d1b6 100644 --- a/chrome/browser/ui/webui/signin/user_manager_screen_handler.h +++ b/chrome/browser/ui/webui/signin/user_manager_screen_handler.h @@ -63,6 +63,7 @@ class UserManagerScreenHandler : public content::WebUIMessageHandler, void HandleLaunchUser(const base::ListValue* args); void HandleRemoveUser(const base::ListValue* args); void HandleAttemptUnlock(const base::ListValue* args); + void HandleHardlockUserPod(const base::ListValue* args); // Handle GAIA auth results. virtual void OnClientLoginSuccess(const ClientLoginResult& result) OVERRIDE; diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css index 01a3b7a..089dc5e 100644 --- a/ui/login/account_picker/user_pod_row.css +++ b/ui/login/account_picker/user_pod_row.css @@ -171,7 +171,8 @@ html[dir=rtl] .main-pane { display: none; } -.pod[auth-type='offlinePassword'].focused .password-entry-container { +.pod[auth-type='offlinePassword'].focused .password-entry-container, +.pod[auth-type='forceOfflinePassword'].focused .password-entry-container { display: flex; flex: auto; } @@ -226,6 +227,11 @@ html[dir=rtl] .main-pane { flex: none; } +.custom-icon.faded { + -webkit-transition: opacity 200ms ease-in-out, + visibility 200ms ease-in-out; +} + .custom-icon-container { display: flex; flex: none; diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js index 39b5c7d..e83344b 100644 --- a/ui/login/account_picker/user_pod_row.js +++ b/ui/login/account_picker/user_pod_row.js @@ -85,10 +85,11 @@ cr.define('login', function() { * @const */ var UserPodTabOrder = { - POD_INPUT: 1, // Password input fields (and whole pods themselves). - HEADER_BAR: 2, // Buttons on the header bar (Shutdown, Add User). - ACTION_BOX: 3, // Action box buttons. - PAD_MENU_ITEM: 4 // User pad menu items (Remove this user). + POD_INPUT: 1, // Password input fields (and whole pods themselves). + POD_CUSTOM_ICON: 2, // Pod custom icon next to passwrod input field. + HEADER_BAR: 3, // Buttons on the header bar (Shutdown, Add User). + ACTION_BOX: 4, // Action box buttons. + PAD_MENU_ITEM: 5 // User pad menu items (Remove this user). }; /** @@ -103,6 +104,7 @@ cr.define('login', function() { NUMERIC_PIN: 2, USER_CLICK: 3, EXPAND_THEN_USER_CLICK: 4, + FORCE_OFFLINE_PASSWORD: 5 }; /** @@ -114,6 +116,7 @@ cr.define('login', function() { 2: 'numericPin', 3: 'userClick', 4: 'expandThenUserClick', + 5: 'forceOfflinePassword' }; // Focus and tab order are organized as follows: @@ -121,9 +124,12 @@ cr.define('login', function() { // (1) all user pods have tab index 1 so they are traversed first; // (2) when a user pod is activated, its tab index is set to -1 and its // main input field gets focus and tab index 1; - // (3) buttons on the header bar have tab index 2 so they follow user pods; - // (4) Action box buttons have tab index 3 and follow header bar buttons; - // (5) lastly, focus jumps to the Status Area and back to user pods. + // (3) if user pod custom icon is interactive, it has tab index 2 so it + // follows the input. + // (4) buttons on the header bar have tab index 3 so they follow the custom + // icon, or user pod if custom icon is not interactive; + // (5) Action box buttons have tab index 4 and follow header bar buttons; + // (6) lastly, focus jumps to the Status Area and back to user pods. // // 'Focus' event is handled by a capture handler for the whole document // and in some cases 'mousedown' event handlers are used instead of 'click' @@ -252,6 +258,23 @@ cr.define('login', function() { */ animationResourceSize_: 0, + /** + * When {@code fadeOut} is called, the element gets hidden using fadeout + * animation. This is reference to the listener for transition end added to + * the icon element while it's fading out. + * @type {?function(Event)} + * @private + */ + hideTransitionListener_: null, + + /** + * Callback for click and 'Enter' key events that gets set if the icon is + * interactive. + * @type {?function()} + * @private + */ + actionHandler_: null, + /** @override */ decorate: function() { this.iconElement.addEventListener('mouseover', @@ -260,6 +283,16 @@ cr.define('login', function() { this.hideTooltip_.bind(this, false)); this.iconElement.addEventListener('mousedown', this.hideTooltip_.bind(this, false)); + this.iconElement.addEventListener('click', + this.handleClick_.bind(this)); + this.iconElement.addEventListener('keydown', + this.handleKeyDown_.bind(this)); + + // When the icon is focused using mouse, there should be no outline shown. + // Preventing default mousedown event accomplishes this. + this.iconElement.addEventListener('mousedown', function(e) { + e.preventDefault(); + }); }, /** @@ -298,16 +331,24 @@ cr.define('login', function() { * Shows the icon. */ show: function() { + this.resetHideTransitionState_(); this.hidden = false; }, /** - * Hides the icon. Makes sure the tooltip is hidden and animation reset. + * Hides the icon using a fade-out animation. */ - hide: function() { + fadeOut: function() { + // The icon is already being hidden. + if (this.iconElement.classList.contains('faded')) + return; + this.hideTooltip_(true); - this.setAnimation(null); - this.hidden = true; + this.iconElement.classList.add('faded'); + this.hideTransitionListener_ = this.hide_.bind(this); + this.iconElement.addEventListener('webkitTransitionEnd', + this.hideTransitionListener_); + ensureTransitionEndEvent(this.iconElement, 200); }, /** @@ -403,6 +444,80 @@ cr.define('login', function() { }, /** + * Sets up icon tabIndex attribute and handler for click and 'Enter' key + * down events. + * @param {?function()} callback If icon should be interactive, the + * function to get called on click and 'Enter' key down events. Should + * be null to make the icon non interactive. + */ + setInteractive: function(callback) { + // Update tabIndex property if needed. + if (!!this.actionHandler_ != !!callback) { + if (callback) { + this.iconElement.setAttribute('tabIndex', + UserPodTabOrder.POD_CUSTOM_ICON); + } else { + this.iconElement.removeAttribute('tabIndex'); + } + } + + // Set the new action handler. + this.actionHandler_ = callback; + }, + + /** + * Hides the icon. Makes sure the tooltip is hidden and animation reset. + * @private + */ + hide_: function() { + this.hideTooltip_(true); + this.hidden = true; + this.setAnimation(null); + this.setInteractive(null); + this.resetHideTransitionState_(); + }, + + /** + * Ensures the icon's transition state potentially set by a call to + * {@code fadeOut} is cleared. + * @private + */ + resetHideTransitionState_: function() { + if (this.hideTransitionListener_) { + this.iconElement.removeEventListener('webkitTransitionEnd', + this.hideTransitionListener_); + this.hideTransitionListener_ = null; + } + this.iconElement.classList.toggle('faded', false); + }, + + /** + * Handles click event on the icon element. No-op if + * {@code this.actionHandler_} is not set. + * @param {Event} e The click event. + * @private + */ + handleClick_: function(e) { + if (!this.actionHandler_) + return; + this.actionHandler_(); + stopEventPropagation(e); + }, + + /** + * Handles key down event on the icon element. Only 'Enter' key is handled. + * No-op if {@code this.actionHandler_} is not set. + * @param {Event} e The key down event. + * @private + */ + handleKeyDown_: function(e) { + if (!this.actionHandler_ || e.keyIdentifier != 'Enter') + return; + this.actionHandler_(e); + stopEventPropagation(e); + }, + + /** * Called when mouse enters the icon. It sets timeout for showing the * tooltip. * @private @@ -415,7 +530,7 @@ cr.define('login', function() { }, /** - * Shows the current tooltip, if one is set. + * Shows the current tooltip if one is set. * @private */ showTooltip_: function() { @@ -973,7 +1088,8 @@ cr.define('login', function() { * @type {bool} */ get isAuthTypePassword() { - return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD; + return this.authType_ == AUTH_TYPE.OFFLINE_PASSWORD || + this.authType_ == AUTH_TYPE.FORCE_OFFLINE_PASSWORD; }, /** @@ -2199,6 +2315,12 @@ cr.define('login', function() { pod.customIconElement.setSize(icon.size || {width: 0, height: 0}); pod.customIconElement.setAnimation(icon.animation || null); pod.customIconElement.setOpacity(icon.opacity || 100); + if (icon.hardlockOnClick) { + pod.customIconElement.setInteractive( + this.hardlockUserPod_.bind(this, username)); + } else { + pod.customIconElement.setInteractive(null); + } pod.customIconElement.show(); // This has to be called after |show| in case the tooltip should be shown // immediatelly. @@ -2207,6 +2329,17 @@ cr.define('login', function() { }, /** + * Hard-locks user pod for the user. If user pod is hard-locked, it can be + * only unlocked using password, and the authentication type cannot be + * changed. + * @param {!string} username The user's username. + * @private + */ + hardlockUserPod_: function(username) { + chrome.send('hardlockPod', [username]); + }, + + /** * Hides the custom icon in the user pod added by showUserPodCustomIcon(). * @param {string} username Username of pod to remove button */ @@ -2218,7 +2351,7 @@ cr.define('login', function() { return; } - pod.customIconElement.hide(); + pod.customIconElement.fadeOut(); }, /** |