Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Unified Diff: ui/login/account_picker/user_pod_row.js

Issue 2733953008: Add fingerprint UI in user pod (Closed)
Patch Set: Incorporate comments Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « ui/login/account_picker/user_pod_row.css ('k') | ui/login/account_picker/user_pod_template.html » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: ui/login/account_picker/user_pod_row.js
diff --git a/ui/login/account_picker/user_pod_row.js b/ui/login/account_picker/user_pod_row.js
index c52ccfa36948317df4a453d3197ba3dc7e0dd191..13a1c64d1ef3afee5b957db7f01ca5408c119855 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -125,6 +125,32 @@ cr.define('login', function() {
5: 'forceOfflinePassword'
};
+ /**
+ * Supported fingerprint unlock states.
+ * @enum {number}
+ * @const
+ */
+ var FINGERPRINT_STATES = {
+ HIDDEN: 0,
+ DEFAULT: 1,
+ SIGNIN: 2,
+ FAILED: 3,
+ };
+
+ /**
+ * The fingerprint states to classes mapping.
+ * {@code state} properties indicate current fingerprint unlock state.
+ * {@code class} properties are CSS classes used to set the icons' background
+ * and password placeholder color.
+ * @const {Array<{type: !number, class: !string}>}
+ */
+ var FINGERPRINT_STATES_MAPPING = [
+ {state: FINGERPRINT_STATES.HIDDEN, class: 'hidden'},
+ {state: FINGERPRINT_STATES.DEFAULT, class: 'default'},
+ {state: FINGERPRINT_STATES.SIGNIN, class: 'signin'},
+ {state: FINGERPRINT_STATES.FAILED, class: 'failed'}
+ ];
+
// Focus and tab order are organized as follows:
//
// (1) all user pods have tab index 1 so they are traversed first;
@@ -711,6 +737,13 @@ cr.define('login', function() {
*/
userClickAuthAllowed_: false,
+ /**
+ * Whether the user has recently authenticated with fingerprint.
+ * @type {boolean}
+ * @private
+ */
+ fingerprintAuthenticated_: false,
+
/** @override */
decorate: function() {
this.tabIndex = UserPodTabOrder.POD_INPUT;
@@ -750,6 +783,15 @@ cr.define('login', function() {
this.actionBoxRemoveUserWarningButtonElement.addEventListener('keydown',
this.handleRemoveUserConfirmationKeyDown_.bind(this));
+ if (this.fingerprintIconElement) {
+ this.fingerprintIconElement.addEventListener(
+ 'mouseover', this.handleFingerprintIconMouseOver_.bind(this));
+ this.fingerprintIconElement.addEventListener(
+ 'mouseout', this.handleFingerprintIconMouseOut_.bind(this));
+ this.fingerprintIconElement.addEventListener(
+ 'mousedown', stopEventPropagation);
+ }
+
var customIcon = this.customIconElement;
customIcon.parentNode.replaceChild(new UserPodCustomIcon(), customIcon);
},
@@ -1096,6 +1138,14 @@ cr.define('login', function() {
},
/**
+ * Gets the fingerprint icon area.
+ * @type {!HTMLDivElement}
+ */
+ get fingerprintIconElement() {
+ return this.querySelector('.fingerprint-icon-container');
+ },
+
+ /**
* Updates the user pod element.
*/
update: function() {
@@ -1216,6 +1266,10 @@ cr.define('login', function() {
this.userTypeIconAreaElement.hidden = false;
},
+ isFingerprintIconShown: function() {
+ return this.fingerprintIconElement && !this.fingerprintIconElement.hidden;
+ },
+
/**
* The user that this pod represents.
* @type {!Object}
@@ -1412,6 +1466,10 @@ cr.define('login', function() {
this.classList.toggle('signing-in', true);
chrome.send('attemptUnlock', [this.user.username]);
} else if (this.isAuthTypePassword) {
+ if (this.fingerprintAuthenticated_) {
+ this.fingerprintAuthenticated_ = false;
+ return true;
+ }
var pinValue = this.pinKeyboard ? this.pinKeyboard.value : '';
var password = this.passwordElement.value || pinValue;
if (!password)
@@ -1822,6 +1880,50 @@ cr.define('login', function() {
},
/**
+ * Handles mouseover event on fingerprint icon.
+ * @param {Event} e MouseOver event.
+ */
+ handleFingerprintIconMouseOver_: function(e) {
+ var bubbleContent = document.createElement('div');
+ bubbleContent.textContent =
+ loadTimeData.getString('fingerprintIconMessage');
+ this.passwordElement.placeholder =
+ loadTimeData.getString('fingerprintHint');
+
+ /** @const */ var BUBBLE_OFFSET = 25;
+ /** @const */ var BUBBLE_PADDING = -8;
+ var attachment = this.isPinShown() ? cr.ui.Bubble.Attachment.RIGHT :
+ cr.ui.Bubble.Attachment.BOTTOM;
+ var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
+ $('bubble').showContentForElement(
+ bubbleAnchor, attachment, bubbleContent, BUBBLE_OFFSET,
+ BUBBLE_PADDING, true);
+ },
+
+ /**
+ * Handles mouseout event on fingerprint icon.
+ * @param {Event} e MouseOut event.
+ */
+ handleFingerprintIconMouseOut_: function(e) {
+ var bubbleAnchor = this.getBubbleAnchorForFingerprintIcon_();
+ $('bubble').hideForElement(bubbleAnchor);
+ this.passwordElement.placeholder = loadTimeData.getString(
+ this.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
+ 'passwordHint');
+ },
+
+ /**
+ * Returns bubble anchor of the fingerprint icon.
+ * @return {!HTMLElement} Anchor element of the bubble.
+ */
+ getBubbleAnchorForFingerprintIcon_: function() {
+ var bubbleAnchor = this;
+ if (this.isPinShown())
+ bubbleAnchor = (this.getElementsByClassName('auth-container'))[0];
+ return bubbleAnchor;
+ },
+
+ /**
* Handles a keydown event on remove user confirmation button.
* @param {Event} e KeyDown event.
*/
@@ -1899,8 +2001,14 @@ cr.define('login', function() {
* button color and state and hides the error popup bubble.
*/
updateInput_: function() {
- if (this.submitButton)
- this.submitButton.disabled = this.passwordElement.value.length <= 0;
+ if (this.submitButton) {
+ this.submitButton.disabled = this.passwordElement.value.length == 0;
+ if (this.isFingerprintIconShown()) {
+ this.submitButton.hidden = this.passwordElement.value.length == 0;
+ } else {
+ this.submitButton.hidden = false;
+ }
+ }
this.showError = false;
$('bubble').hide();
},
@@ -3001,6 +3109,9 @@ cr.define('login', function() {
// immediatelly.
pod.customIconElement.setTooltip(
icon.tooltip || {text: '', autoshow: false});
+
+ // Hide fingerprint icon when custom icon is shown.
+ this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.HIDDEN);
},
/**
@@ -3037,6 +3148,100 @@ cr.define('login', function() {
// TODO(tengs): Allow option for a fading transition.
pod.customIconElement.hide();
+
+ // Show fingerprint icon if applicable.
+ this.setUserPodFingerprintIcon(username, FINGERPRINT_STATES.DEFAULT);
+ },
+
+ /**
+ * Set a fingerprint icon in the user pod of |username|.
+ * @param {string} username Username of the selected user
+ * @param {number} state Fingerprint unlock state
+ */
+ setUserPodFingerprintIcon: function(username, state) {
+ var pod = this.getPodWithUsername_(username);
+ if (pod == null) {
+ console.error(
+ 'Unable to set user pod fingerprint icon: user pod not found.');
+ return;
+ }
+ pod.fingerprintAuthenticated_ = false;
+ if (!pod.fingerprintIconElement)
+ return;
+ if (!pod.user.allowFingerprint || state == FINGERPRINT_STATES.HIDDEN ||
+ !pod.customIconElement.hidden) {
+ pod.fingerprintIconElement.hidden = true;
+ pod.submitButton.hidden = false;
+ return;
+ }
+
+ FINGERPRINT_STATES_MAPPING.forEach(function(icon) {
+ pod.fingerprintIconElement.classList.toggle(
+ icon.class, state == icon.state);
+ });
+ pod.fingerprintIconElement.hidden = false;
+ pod.submitButton.hidden = pod.passwordElement.value.length == 0;
+ this.updatePasswordField_(pod, state);
+ if (state == FINGERPRINT_STATES.DEFAULT)
+ return;
+
+ pod.fingerprintAuthenticated_ = true;
+ this.setActivatedPod(pod);
+ if (state == FINGERPRINT_STATES.FAILED) {
+ /** @const */ var RESET_ICON_TIMEOUT_MS = 500;
+ setTimeout(
+ this.resetIconAndPasswordField_.bind(this, pod),
+ RESET_ICON_TIMEOUT_MS);
+ }
+ },
+
+ /**
+ * Reset the fingerprint icon and password field.
+ * @param {UserPod} pod Pod to reset.
+ */
+ resetIconAndPasswordField_: function(pod) {
+ if (!pod.fingerprintIconElement)
+ return;
+ this.setUserPodFingerprintIcon(
+ pod.user.username, FINGERPRINT_STATES.DEFAULT);
+ },
+
+ /**
+ * Remove the fingerprint icon in the user pod.
+ * @param {string} username Username of the selected user
+ */
+ removeUserPodFingerprintIcon: function(username) {
+ var pod = this.getPodWithUsername_(username);
+ if (pod == null) {
+ console.error('No user pod found (when removing fingerprint icon).');
+ return;
+ }
+ this.resetIconAndPasswordField_(pod);
+ if (pod.fingerprintIconElement) {
+ pod.fingerprintIconElement.parentNode.removeChild(
+ pod.fingerprintIconElement);
+ }
+ pod.submitButton.hidden = false;
+ },
+
+ /**
+ * Updates the password field in the user pod.
+ * @param {UserPod} pod Pod to update.
+ * @param {number} state Fingerprint unlock state
+ */
+ updatePasswordField_: function(pod, state) {
+ FINGERPRINT_STATES_MAPPING.forEach(function(item) {
+ pod.passwordElement.classList.toggle(item.class, state == item.state);
+ });
+ var placeholderStr = loadTimeData.getString(
+ pod.isPinShown() ? 'pinKeyboardPlaceholderPinPassword' :
+ 'passwordHint');
+ if (state == FINGERPRINT_STATES.SIGNIN) {
+ placeholderStr = loadTimeData.getString('fingerprintSigningin');
+ } else if (state == FINGERPRINT_STATES.FAILED) {
+ placeholderStr = loadTimeData.getString('fingerprintSigninFailed');
+ }
+ pod.passwordElement.placeholder = placeholderStr;
},
/**
@@ -3308,6 +3513,8 @@ cr.define('login', function() {
pod.isActionBoxMenuHovered = false;
pod.classList.remove('focused');
pod.setPinVisibility(false);
+ this.setUserPodFingerprintIcon(
+ pod.user.username, FINGERPRINT_STATES.HIDDEN);
// On Desktop, the faded style is not set correctly, so we should
// manually fade out non-focused pods if there is a focused pod.
if (pod.user.isDesktopUser && podToFocus)
@@ -3347,6 +3554,8 @@ cr.define('login', function() {
this.firstShown_ = false;
this.lastFocusedPod_ = podToFocus;
this.scrollFocusedPodIntoView();
+ this.setUserPodFingerprintIcon(
+ podToFocus.user.username, FINGERPRINT_STATES.DEFAULT);
} else {
chrome.send('noPodFocused');
}
« no previous file with comments | « ui/login/account_picker/user_pod_row.css ('k') | ui/login/account_picker/user_pod_template.html » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698