summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortbarzic <tbarzic@chromium.org>2014-10-03 18:23:32 -0700
committerCommit bot <commit-bot@chromium.org>2014-10-04 01:23:54 +0000
commitd366f72f171dd176aa89f8e0baaca34ef70545c6 (patch)
tree3aa9e770b5a74252362dd98b5a044980c1efcf09
parent42d9711d127ddc3e192747ff0901c4c6c29b5eae (diff)
downloadchromium_src-d366f72f171dd176aa89f8e0baaca34ef70545c6.zip
chromium_src-d366f72f171dd176aa89f8e0baaca34ef70545c6.tar.gz
chromium_src-d366f72f171dd176aa89f8e0baaca34ef70545c6.tar.bz2
[Easy Unlock] Support for hover and active effects on user pod icons
To simplify things, define icon resource URLs in CSS instead of passing them from C++. To set an icon only id for the icon resource is passed to js. This also enables us to set up spinner using css animation. While here fix two issues that occur when unfocusing and focusing back easy unlockable user pod: 1. clicking on the unfocused pod (given that no other pod were focused) would immediately attempt unlock instead of bringing the focus to the pod first 2. if the pod was unfocused by ESC key, clicking on it would not bring it to foreground. The reason is the main input for the pod is pod itself, which doesn't get hidden on ESC key, and does not really loose focus. So when the pod is clicked there is no focus event, which is relied on for updating the UI. BUG=406234 Review URL: https://codereview.chromium.org/623443006 Cr-Commit-Position: refs/heads/master@{#298153}
-rw-r--r--chrome/browser/signin/easy_unlock_screenlock_state_handler.cc52
-rw-r--r--chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc92
-rw-r--r--chrome/browser/signin/screenlock_bridge.cc79
-rw-r--r--chrome/browser/signin/screenlock_bridge.h42
-rw-r--r--ui/login/account_picker/screen_account_picker.js8
-rw-r--r--ui/login/account_picker/user_pod_row.css72
-rw-r--r--ui/login/account_picker/user_pod_row.js199
-rw-r--r--ui/resources/default_100_percent/common/easy_unlock_hardlocked_hover.pngbin0 -> 464 bytes
-rw-r--r--ui/resources/default_100_percent/common/easy_unlock_hardlocked_pressed.pngbin0 -> 463 bytes
-rw-r--r--ui/resources/default_100_percent/common/easy_unlock_locked_hover.pngbin0 -> 446 bytes
-rw-r--r--ui/resources/default_100_percent/common/easy_unlock_locked_pressed.pngbin0 -> 454 bytes
-rw-r--r--ui/resources/default_100_percent/common/easy_unlock_unlocked_hover.pngbin0 -> 439 bytes
-rw-r--r--ui/resources/default_100_percent/common/easy_unlock_unlocked_pressed.pngbin0 -> 449 bytes
-rw-r--r--ui/resources/default_200_percent/common/easy_unlock_hardlocked_hover.pngbin0 -> 893 bytes
-rw-r--r--ui/resources/default_200_percent/common/easy_unlock_hardlocked_pressed.pngbin0 -> 901 bytes
-rw-r--r--ui/resources/default_200_percent/common/easy_unlock_locked_hover.pngbin0 -> 863 bytes
-rw-r--r--ui/resources/default_200_percent/common/easy_unlock_locked_pressed.pngbin0 -> 880 bytes
-rw-r--r--ui/resources/default_200_percent/common/easy_unlock_unlocked_hover.pngbin0 -> 855 bytes
-rw-r--r--ui/resources/default_200_percent/common/easy_unlock_unlocked_pressed.pngbin0 -> 861 bytes
-rw-r--r--ui/resources/ui_resources.grd6
20 files changed, 233 insertions, 317 deletions
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
index 8921a20..a819065 100644
--- a/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
+++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler.cc
@@ -15,23 +15,8 @@
namespace {
-size_t kIconSize = 27u;
-size_t kSpinnerResourceWidth = 1215u;
-size_t kSpinnerIntervalMs = 50u;
-
-const char kHardlockIconResourceURL[] =
- "chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED";
-
-const char kLockedIconResourceURL[] =
- "chrome://theme/IDR_EASY_UNLOCK_LOCKED";
-
-const char kSpinnerIconResourceURL[] =
- "chrome://theme/IDR_EASY_UNLOCK_SPINNER";
-
-const char kUnlockedIconResourceURL[] =
- "chrome://theme/IDR_EASY_UNLOCK_UNLOCKED";
-
-std::string GetIconURLForState(EasyUnlockScreenlockStateHandler::State state) {
+ScreenlockBridge::UserPodCustomIcon GetIconForState(
+ EasyUnlockScreenlockStateHandler::State state) {
switch (state) {
case EasyUnlockScreenlockStateHandler::STATE_NO_BLUETOOTH:
case EasyUnlockScreenlockStateHandler::STATE_NO_PHONE:
@@ -40,20 +25,16 @@ std::string GetIconURLForState(EasyUnlockScreenlockStateHandler::State state) {
case EasyUnlockScreenlockStateHandler::STATE_PHONE_NOT_NEARBY:
case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNLOCKABLE:
case EasyUnlockScreenlockStateHandler::STATE_PHONE_UNSUPPORTED:
- return kLockedIconResourceURL;
+ return ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED;
case EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING:
- return kSpinnerIconResourceURL;
+ return ScreenlockBridge::USER_POD_CUSTOM_ICON_SPINNER;
case EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED:
- return kUnlockedIconResourceURL;
+ return ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED;
default:
- return "";
+ return ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE;
}
}
-bool HasAnimation(EasyUnlockScreenlockStateHandler::State state) {
- return state == EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING;
-}
-
bool HardlockOnClick(EasyUnlockScreenlockStateHandler::State state) {
return state != EasyUnlockScreenlockStateHandler::STATE_INACTIVE;
}
@@ -130,28 +111,24 @@ void EasyUnlockScreenlockStateHandler::ChangeState(State new_state) {
UpdateScreenlockAuthType();
- ScreenlockBridge::UserPodCustomIconOptions icon_options;
+ ScreenlockBridge::UserPodCustomIcon icon = GetIconForState(state_);
- std::string icon_url = GetIconURLForState(state_);
- if (icon_url.empty()) {
+ if (icon == ScreenlockBridge::USER_POD_CUSTOM_ICON_NONE) {
screenlock_bridge_->lock_handler()->HideUserPodCustomIcon(user_email_);
return;
}
- icon_options.SetIconAsResourceURL(icon_url);
- bool trial_run = IsTrialRun();
-
- UpdateTooltipOptions(trial_run, &icon_options);
-
- icon_options.SetSize(kIconSize, kIconSize);
+ ScreenlockBridge::UserPodCustomIconOptions icon_options;
+ icon_options.SetIcon(icon);
- if (HasAnimation(state_))
- icon_options.SetAnimation(kSpinnerResourceWidth, kSpinnerIntervalMs);
+ bool trial_run = IsTrialRun();
// Don't hardlock on trial run.
if (!trial_run && HardlockOnClick(state_))
icon_options.SetHardlockOnClick();
+ UpdateTooltipOptions(trial_run, &icon_options);
+
if (trial_run && state_ == STATE_AUTHENTICATED)
MarkTrialRunComplete();
@@ -216,8 +193,7 @@ void EasyUnlockScreenlockStateHandler::ShowHardlockUI() {
return;
ScreenlockBridge::UserPodCustomIconOptions icon_options;
- icon_options.SetIconAsResourceURL(kHardlockIconResourceURL);
- icon_options.SetSize(kIconSize, kIconSize);
+ icon_options.SetIcon(ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED);
icon_options.SetTooltip(
l10n_util::GetStringFUTF16(IDS_EASY_UNLOCK_SCREENLOCK_TOOLTIP_HARDLOCK,
GetDeviceName()),
diff --git a/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc b/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc
index 1c4a5ec..63b70a2 100644
--- a/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc
+++ b/chrome/browser/signin/easy_unlock_screenlock_state_handler_unittest.cc
@@ -20,15 +20,12 @@
namespace {
-// Resource URLs for icons used by EasyUnlockScreenlockStateHandler.
-const char kLockedIconURL[] = "chrome://theme/IDR_EASY_UNLOCK_LOCKED";
-const char kUnlockedIconURL[] = "chrome://theme/IDR_EASY_UNLOCK_UNLOCKED";
-const char kSpinnerIconURL[] = "chrome://theme/IDR_EASY_UNLOCK_SPINNER";
-const char kHardlockedIconURL[] = "chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED";
-
-// The expected size of user pod custom icons set by
-// EasyUnlockScreenlockStateHandler.
-const int kExpectedIconSize = 27;
+// Icons used by EasyUnlockScreenlockStateHandler. The icon id values are the
+// same as the ones set by ScreenlockBridge.
+const char kLockedIconId[] = "locked";
+const char kUnlockedIconId[] = "unlocked";
+const char kSpinnerIconId[] = "spinner";
+const char kHardlockedIconId[] = "hardlocked";
// Checks if |input| string has any unreplaced placeholders.
bool StringHasPlaceholders(const base::string16& input) {
@@ -125,13 +122,13 @@ class TestLockHandler : public ScreenlockBridge::LockHandler {
return last_custom_icon_;
}
- // If custom icon is set, returns the icon's resource URL.
- // If there is no icon, or if it doesn't have a resource URL set, returns
- // an empty string.
- std::string GetCustomIconURL() const {
+ // If custom icon is set, returns the icon's id.
+ // If there is no icon, or if it doesn't have an id set, returns an empty
+ // string.
+ std::string GetCustomIconId() const {
std::string result;
if (last_custom_icon_)
- last_custom_icon_->GetString("resourceUrl", &result);
+ last_custom_icon_->GetString("id", &result);
return result;
}
@@ -157,15 +154,6 @@ class TestLockHandler : public ScreenlockBridge::LockHandler {
return result;
}
- // Returns the custom icon's opacity. If the icon is not set, a negative value
- // is returned.
- int GetCustomIconOpacity() const {
- int result = -1;
- if (last_custom_icon_)
- last_custom_icon_->GetInteger("opacity", &result);
- return result;
- }
-
// Whether the custom icon is set and if has hardlock capability enabed.
bool CustomIconHardlocksOnClick() const {
bool result = false;
@@ -174,36 +162,13 @@ class TestLockHandler : public ScreenlockBridge::LockHandler {
return result;
}
- // Whether the custom icon is set and has an animation set.
- bool IsCustomIconAnimated() const {
- return last_custom_icon_ && last_custom_icon_->HasKey("animation");
- }
-
private:
// Does some sanity checks on the last icon set by |ShowUserPodCustomIcon|.
// It will cause a test failure if the icon is not valid.
void ValidateCustomIcon() {
ASSERT_TRUE(last_custom_icon_.get());
- EXPECT_FALSE(last_custom_icon_->HasKey("data"));
-
- int height = 0;
- last_custom_icon_->GetInteger("size.height", &height);
- EXPECT_EQ(kExpectedIconSize, height);
-
- int width = 0;
- last_custom_icon_->GetInteger("size.width", &width);
- EXPECT_EQ(kExpectedIconSize, width);
-
- if (last_custom_icon_->HasKey("animation")) {
- int animation_resource_width = -1;
- EXPECT_TRUE(last_custom_icon_->GetInteger("animation.resourceWidth",
- &animation_resource_width));
- EXPECT_GT(animation_resource_width, kExpectedIconSize);
- EXPECT_EQ(0, animation_resource_width % kExpectedIconSize);
- EXPECT_TRUE(
- last_custom_icon_->GetInteger("animation.frameLengthMs", NULL));
- }
+ EXPECT_TRUE(last_custom_icon_->HasKey("id"));
if (last_custom_icon_->HasKey("tooltip")) {
base::string16 tooltip;
@@ -284,12 +249,10 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, AuthenticatedInitialRun) {
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_EQ(kUnlockedIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kUnlockedIconId, lock_handler_->GetCustomIconId());
EXPECT_TRUE(lock_handler_->CustomIconHasTooltip());
EXPECT_TRUE(lock_handler_->IsCustomIconTooltipAutoshown());
EXPECT_FALSE(lock_handler_->CustomIconHardlocksOnClick());
- EXPECT_FALSE(lock_handler_->IsCustomIconAnimated());
- EXPECT_EQ(100, lock_handler_->GetCustomIconOpacity());
state_handler_->ChangeState(
EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED);
@@ -309,12 +272,10 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, AuthenticatedNotInitialRun) {
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_EQ(kUnlockedIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kUnlockedIconId, lock_handler_->GetCustomIconId());
EXPECT_TRUE(lock_handler_->CustomIconHasTooltip());
EXPECT_FALSE(lock_handler_->IsCustomIconTooltipAutoshown());
EXPECT_TRUE(lock_handler_->CustomIconHardlocksOnClick());
- EXPECT_FALSE(lock_handler_->IsCustomIconAnimated());
- EXPECT_EQ(100, lock_handler_->GetCustomIconOpacity());
}
TEST_F(EasyUnlockScreenlockStateHandlerTest, BluetoothConnecting) {
@@ -327,11 +288,9 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, BluetoothConnecting) {
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_EQ(kSpinnerIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kSpinnerIconId, lock_handler_->GetCustomIconId());
EXPECT_FALSE(lock_handler_->CustomIconHasTooltip());
EXPECT_TRUE(lock_handler_->CustomIconHardlocksOnClick());
- EXPECT_TRUE(lock_handler_->IsCustomIconAnimated());
- EXPECT_EQ(100, lock_handler_->GetCustomIconOpacity());
state_handler_->ChangeState(
EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING);
@@ -355,11 +314,9 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, HardlockedState) {
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_EQ(kHardlockedIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId());
EXPECT_TRUE(lock_handler_->CustomIconHasTooltip());
EXPECT_FALSE(lock_handler_->CustomIconHardlocksOnClick());
- EXPECT_FALSE(lock_handler_->IsCustomIconAnimated());
- EXPECT_EQ(100, lock_handler_->GetCustomIconOpacity());
state_handler_->SetHardlocked(true);
@@ -390,7 +347,7 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, StatesWithLockedIcon) {
ASSERT_TRUE(lock_handler_->HasCustomIcon())
<< "State: " << states[i];
- EXPECT_EQ(kLockedIconURL, lock_handler_->GetCustomIconURL())
+ EXPECT_EQ(kLockedIconId, lock_handler_->GetCustomIconId())
<< "State: " << states[i];
EXPECT_TRUE(lock_handler_->CustomIconHasTooltip())
<< "State: " << states[i];
@@ -398,10 +355,6 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, StatesWithLockedIcon) {
<< "State: " << states[i];
EXPECT_TRUE(lock_handler_->CustomIconHardlocksOnClick())
<< "State: " << states[i];
- EXPECT_FALSE(lock_handler_->IsCustomIconAnimated())
- << "State: " << states[i];
- EXPECT_EQ(100, lock_handler_->GetCustomIconOpacity())
- << "State: " << states[i];
state_handler_->ChangeState(states[i]);
EXPECT_EQ(0u, lock_handler_->GetAndResetShowIconCount())
@@ -471,7 +424,7 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, StateChangeWhileScreenUnlocked) {
EXPECT_EQ(ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_TRUE(lock_handler_->IsCustomIconAnimated());
+ EXPECT_EQ(kSpinnerIconId, lock_handler_->GetCustomIconId());
}
TEST_F(EasyUnlockScreenlockStateHandlerTest,
@@ -555,7 +508,8 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest,
state_handler_->ChangeState(
EasyUnlockScreenlockStateHandler::STATE_BLUETOOTH_CONNECTING);
EXPECT_EQ(base::ASCIIToUTF16("xxx"), lock_handler_->GetAuthValue());
- EXPECT_TRUE(lock_handler_->IsCustomIconAnimated());
+ ASSERT_TRUE(lock_handler_->HasCustomIcon());
+ EXPECT_EQ(kSpinnerIconId, lock_handler_->GetCustomIconId());
}
TEST_F(EasyUnlockScreenlockStateHandlerTest, StateChangesIgnoredIfHardlocked) {
@@ -572,7 +526,7 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, StateChangesIgnoredIfHardlocked) {
EXPECT_EQ(ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_EQ(kHardlockedIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId());
state_handler_->ChangeState(
EasyUnlockScreenlockStateHandler::STATE_NO_PHONE);
@@ -617,7 +571,7 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest,
EXPECT_TRUE(lock_handler_->HasCustomIcon());
EXPECT_EQ(ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
lock_handler_->GetAuthType(user_email_));
- EXPECT_EQ(kLockedIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kLockedIconId, lock_handler_->GetCustomIconId());
state_handler_->ChangeState(
EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED);
@@ -643,7 +597,7 @@ TEST_F(EasyUnlockScreenlockStateHandlerTest, HardlockStatePersistsOverUnlocks) {
EXPECT_EQ(ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
lock_handler_->GetAuthType(user_email_));
ASSERT_TRUE(lock_handler_->HasCustomIcon());
- EXPECT_EQ(kHardlockedIconURL, lock_handler_->GetCustomIconURL());
+ EXPECT_EQ(kHardlockedIconId, lock_handler_->GetCustomIconId());
state_handler_->ChangeState(
EasyUnlockScreenlockStateHandler::STATE_AUTHENTICATED);
diff --git a/chrome/browser/signin/screenlock_bridge.cc b/chrome/browser/signin/screenlock_bridge.cc
index 17d676b..a78d261 100644
--- a/chrome/browser/signin/screenlock_bridge.cc
+++ b/chrome/browser/signin/screenlock_bridge.cc
@@ -20,6 +20,30 @@ namespace {
base::LazyInstance<ScreenlockBridge> g_screenlock_bridge_bridge_instance =
LAZY_INSTANCE_INITIALIZER;
+// Ids for the icons that are supported by lock screen and signin screen
+// account picker as user pod custom icons.
+// The id's should be kept in sync with values used by user_pod_row.js.
+const char kLockedUserPodCustomIconId[] = "locked";
+const char kUnlockedUserPodCustomIconId[] = "unlocked";
+const char kHardlockedUserPodCustomIconId[] = "hardlocked";
+const char kSpinnerUserPodCustomIconId[] = "spinner";
+
+// Given the user pod icon, returns its id as used by the user pod UI code.
+std::string GetIdForIcon(ScreenlockBridge::UserPodCustomIcon icon) {
+ switch (icon) {
+ case ScreenlockBridge::USER_POD_CUSTOM_ICON_LOCKED:
+ return kLockedUserPodCustomIconId;
+ case ScreenlockBridge::USER_POD_CUSTOM_ICON_UNLOCKED:
+ return kUnlockedUserPodCustomIconId;
+ case ScreenlockBridge::USER_POD_CUSTOM_ICON_HARDLOCKED:
+ return kHardlockedUserPodCustomIconId;
+ case ScreenlockBridge::USER_POD_CUSTOM_ICON_SPINNER:
+ return kSpinnerUserPodCustomIconId;
+ default:
+ return "";
+ }
+}
+
} // namespace
// static
@@ -28,13 +52,7 @@ ScreenlockBridge* ScreenlockBridge::Get() {
}
ScreenlockBridge::UserPodCustomIconOptions::UserPodCustomIconOptions()
- : width_(0u),
- height_(0u),
- animation_set_(false),
- animation_resource_width_(0u),
- animation_frame_length_ms_(0u),
- opacity_(100u),
- autoshow_tooltip_(false),
+ : autoshow_tooltip_(false),
hardlock_on_click_(false) {
}
@@ -43,10 +61,11 @@ ScreenlockBridge::UserPodCustomIconOptions::~UserPodCustomIconOptions() {}
scoped_ptr<base::DictionaryValue>
ScreenlockBridge::UserPodCustomIconOptions::ToDictionaryValue() const {
scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue());
- if (icon_resource_url_.empty())
+ std::string icon_id = GetIdForIcon(icon_);
+ if (icon_id.empty())
return result.Pass();
- result->SetString("resourceUrl", icon_resource_url_);
+ result->SetString("id", icon_id);
if (!tooltip_.empty()) {
base::DictionaryValue* tooltip_options = new base::DictionaryValue();
@@ -55,51 +74,15 @@ ScreenlockBridge::UserPodCustomIconOptions::ToDictionaryValue() const {
result->Set("tooltip", tooltip_options);
}
- base::DictionaryValue* size = new base::DictionaryValue();
- size->SetInteger("height", height_);
- size->SetInteger("width", width_);
- result->Set("size", size);
-
- result->SetInteger("opacity", opacity_);
-
- if (animation_set_) {
- base::DictionaryValue* animation = new base::DictionaryValue();
- animation->SetInteger("resourceWidth",
- animation_resource_width_);
- animation->SetInteger("frameLengthMs",
- animation_frame_length_ms_);
- result->Set("animation", animation);
- }
-
if (hardlock_on_click_)
result->SetBoolean("hardlockOnClick", true);
return result.Pass();
}
-void ScreenlockBridge::UserPodCustomIconOptions::SetIconAsResourceURL(
- const std::string& url) {
- icon_resource_url_ = url;
-}
-
-
-void ScreenlockBridge::UserPodCustomIconOptions::SetSize(size_t icon_width,
- size_t icon_height) {
- width_ = icon_width;
- height_ = icon_height;
-}
-
-void ScreenlockBridge::UserPodCustomIconOptions::SetAnimation(
- size_t resource_width,
- size_t frame_length_ms) {
- animation_set_ = true;
- animation_resource_width_ = resource_width;
- animation_frame_length_ms_ = frame_length_ms;
-}
-
-void ScreenlockBridge::UserPodCustomIconOptions::SetOpacity(size_t opacity) {
- DCHECK_LE(opacity, 100u);
- opacity_ = opacity;
+void ScreenlockBridge::UserPodCustomIconOptions::SetIcon(
+ ScreenlockBridge::UserPodCustomIcon icon) {
+ icon_ = icon;
}
void ScreenlockBridge::UserPodCustomIconOptions::SetTooltip(
diff --git a/chrome/browser/signin/screenlock_bridge.h b/chrome/browser/signin/screenlock_bridge.h
index 54167b4..7add894 100644
--- a/chrome/browser/signin/screenlock_bridge.h
+++ b/chrome/browser/signin/screenlock_bridge.h
@@ -37,6 +37,15 @@ class ScreenlockBridge {
virtual ~Observer() {}
};
+ // User pod icons supported by lock screen / signin screen UI.
+ enum UserPodCustomIcon {
+ USER_POD_CUSTOM_ICON_NONE,
+ USER_POD_CUSTOM_ICON_HARDLOCKED,
+ USER_POD_CUSTOM_ICON_LOCKED,
+ USER_POD_CUSTOM_ICON_UNLOCKED,
+ USER_POD_CUSTOM_ICON_SPINNER
+ };
+
// Class containing parameters describing the custom icon that should be
// shown on a user's screen lock pod next to the input field.
class UserPodCustomIconOptions {
@@ -48,25 +57,8 @@ class ScreenlockBridge {
// screenlock web UI.
scoped_ptr<base::DictionaryValue> ToDictionaryValue() const;
- // Sets the icon as chrome://theme resource URL.
- void SetIconAsResourceURL(const std::string& url);
-
- // Sets the icon size. If not called, the icon will not be visible.
- // For animated icon, this should be set to a single frame size, not the
- // animation resource size.
- void SetSize(size_t icon_width, size_t icon_height);
-
- // If the icon is supposed to be animated, sets the animation parameters.
- // If set, it expects that the resource set using |SetIconAsResourceURL|
- // method contains horizontally arranged ordered list of animation frames.
- // Note that the icon size set in |SetSize| should be a single frame size.
- // |resource_width|: Total animation resource width.
- // |frame_length_ms|: Time for which a single animation frame is shown.
- void SetAnimation(size_t resource_width, size_t frame_length_ms);
-
- // Sets the icon opacity. The values should be in <0, 100] interval, which
- // will get scaled into <0, 1] interval. The default value is 100.
- void SetOpacity(size_t opacity);
+ // Sets the icon that should be shown in the UI.
+ void SetIcon(UserPodCustomIcon icon);
// Sets the icon tooltip. If |autoshow| is set the tooltip is automatically
// shown with the icon.
@@ -77,17 +69,7 @@ class ScreenlockBridge {
void SetHardlockOnClick();
private:
- std::string icon_resource_url_;
-
- size_t width_;
- size_t height_;
-
- bool animation_set_;
- size_t animation_resource_width_;
- size_t animation_frame_length_ms_;
-
- // The opacity should be in <0, 100] range.
- size_t opacity_;
+ UserPodCustomIcon icon_;
base::string16 tooltip_;
bool autoshow_tooltip_;
diff --git a/ui/login/account_picker/screen_account_picker.js b/ui/login/account_picker/screen_account_picker.js
index fc87cc4..865d64d 100644
--- a/ui/login/account_picker/screen_account_picker.js
+++ b/ui/login/account_picker/screen_account_picker.js
@@ -271,12 +271,8 @@ login.createScreen('AccountPickerScreen', 'account-picker', function() {
* Shows a custom icon in the user pod of |username|. This function
* is used by the chrome.screenlockPrivate API.
* @param {string} username Username of pod to add button
- * @param {!{resourceUrl: (string | undefined),
- * data: ({scale1x: string, scale2x: string} | undefined),
- * size: ({width: number, height: number} | undefined),
- * animation: ({resourceWidth: number, frameLength: number} |
- * undefined),
- * opacity: (number | undefined),
+ * @param {!{id: !string,
+ * hardlockOnClick: boolean,
* tooltip: ({text: string, autoshow: boolean} | undefined)}} icon
* The icon parameters.
*/
diff --git a/ui/login/account_picker/user_pod_row.css b/ui/login/account_picker/user_pod_row.css
index 089dc5e..bb52a3e 100644
--- a/ui/login/account_picker/user_pod_row.css
+++ b/ui/login/account_picker/user_pod_row.css
@@ -214,6 +214,7 @@ html[dir=rtl] .main-pane {
display: block;
flex: auto;
margin-top: 11px;
+ outline: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@@ -225,6 +226,8 @@ html[dir=rtl] .main-pane {
background-position: center;
background-repeat: no-repeat;
flex: none;
+ height: 27px;
+ width: 27px;
}
.custom-icon.faded {
@@ -232,6 +235,75 @@ html[dir=rtl] .main-pane {
visibility 200ms ease-in-out;
}
+.custom-icon-hardlocked {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED');
+}
+
+.custom-icon-hardlocked.icon-with-tooltip:hover {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_HOVER');
+}
+
+.custom-icon-hardlocked.interactive-custom-icon:active {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_PRESSED');
+}
+
+.custom-icon-locked {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_LOCKED');
+}
+
+.custom-icon-locked.icon-with-tooltip:hover {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER');
+}
+
+.custom-icon-locked.interactive-custom-icon:active {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED');
+}
+
+.custom-icon-unlocked {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED');
+}
+
+.custom-icon-unlocked.icon-with-tooltip:hover {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER');
+}
+
+.custom-icon-unlocked.interactive-custom-icon:active {
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED');
+}
+
+/**
+ * Preloads resources for custom icon. Without this, the resources will be
+ * loaded when CSS properties using them are first applied, which has visible
+ * delay and may cause a short white flash when the icon background changes.
+ */
+.custom-icon::after {
+ content:
+ url('chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED')
+ url('chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_HOVER')
+ url('chrome://theme/IDR_EASY_UNLOCK_HARDLOCKED_PRESSED')
+ url('chrome://theme/IDR_EASY_UNLOCK_LOCKED')
+ url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_HOVER')
+ url('chrome://theme/IDR_EASY_UNLOCK_LOCKED_PRESSED')
+ url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED')
+ url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_HOVER')
+ url('chrome://theme/IDR_EASY_UNLOCK_UNLOCKED_PRESSED');
+ display: none;
+}
+
+.custom-icon-spinner {
+ -webkit-animation: easy-unlock-spinner-animation 2s steps(45) infinite;
+ background-image: url('chrome://theme/IDR_EASY_UNLOCK_SPINNER');
+}
+
+@-webkit-keyframes easy-unlock-spinner-animation {
+ from { background-position: 0 }
+ to { background-position: -1215px }
+}
+
+.interactive-custom-icon {
+ cursor: pointer;
+}
+
.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 1024dfa..c6af9a8 100644
--- a/ui/login/account_picker/user_pod_row.js
+++ b/ui/login/account_picker/user_pod_row.js
@@ -183,24 +183,23 @@ cr.define('login', function() {
return node;
});
+ /**
+ * The supported user pod custom icons.
+ * {@code id} properties should be in sync with values set by C++ side.
+ * {@code class} properties are CSS classes used to set the icons' background.
+ * @const {Array.<{id: !string, class: !string}>}
+ */
+ UserPodCustomIcon.ICONS = [
+ {id: 'locked', class: 'custom-icon-locked'},
+ {id: 'unlocked', class: 'custom-icon-unlocked'},
+ {id: 'hardlocked', class: 'custom-icon-hardlocked'},
+ {id: 'spinner', class: 'custom-icon-spinner'}
+ ];
+
UserPodCustomIcon.prototype = {
__proto__: HTMLDivElement.prototype,
/**
- * The icon height.
- * @type {number}
- * @private
- */
- height_: 0,
-
- /**
- * The icon width.
- * @type {number}
- * @private
- */
- width_: 0,
-
- /**
* Tooltip to be shown when the user hovers over the icon. The icon
* properties may be set so the tooltip is shown automatically when the icon
* is updated. The tooltip is shown in a bubble attached to the icon
@@ -236,29 +235,6 @@ cr.define('login', function() {
showTooltipTimeout_: null,
/**
- * If animation is set, the current horizontal background offset for the
- * icon resource.
- * @type {number}
- * @private
- */
- lastAnimationOffset_: 0,
-
- /**
- * The reference to interval for progressing the animation.
- * @type {?number}
- * @private
- */
- animationInterval_: null,
-
- /**
- * The width of the resource that contains representations for different
- * animation stages.
- * @type {number}
- * @private
- */
- 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.
@@ -280,9 +256,9 @@ cr.define('login', function() {
this.iconElement.addEventListener('mouseover',
this.showTooltipSoon_.bind(this));
this.iconElement.addEventListener('mouseout',
- this.hideTooltip_.bind(this, false));
+ this.hideTooltip_.bind(this, false));
this.iconElement.addEventListener('mousedown',
- this.hideTooltip_.bind(this, false));
+ this.handleMouseDown_.bind(this));
this.iconElement.addEventListener('click',
this.handleClick_.bind(this));
this.iconElement.addEventListener('keydown',
@@ -304,14 +280,15 @@ cr.define('login', function() {
},
/**
- * Sets the icon background image to a chrome://theme URL.
- * @param {!string} iconUrl The icon's background image URL.
+ * Updates the icon element class list to properly represent the provided
+ * icon.
+ * @param {!string} id The id of the icon that should be shown. Should be
+ * one of the ids listed in {@code UserPodCustomIcon.ICONS}.
*/
- setIconAsResourceUrl: function(iconUrl) {
- this.iconElement.style.backgroundImage =
- '-webkit-image-set(' +
- 'url(' + iconUrl + '@1x) 1x,' +
- 'url(' + iconUrl + '@2x) 2x)';
+ setIcon: function(id) {
+ UserPodCustomIcon.ICONS.forEach(function(icon) {
+ this.iconElement.classList.toggle(icon.class, id == icon.id);
+ }, this);
},
/**
@@ -339,35 +316,6 @@ cr.define('login', function() {
},
/**
- * Sets the icon size element size.
- * @param {!{width: number, height: number}} size The icon size.
- */
- setSize: function(size) {
- this.height_ = size.height < CUSTOM_ICON_CONTAINER_SIZE ?
- size.height : CUSTOM_ICON_COTAINER_SIZE;
- this.iconElement.style.height = this.height_ + 'px';
-
- this.width_ = size.width < CUSTOM_ICON_CONTAINER_SIZE ?
- size.width : CUSTOM_ICON_COTAINER_SIZE;
- this.iconElement.style.width = this.width_ + 'px';
- this.style.width = this.width_ + 'px';
- },
-
- /**
- * Sets the icon opacity.
- * @param {number} opacity The icon opacity in [0-100] scale.
- */
- setOpacity: function(opacity) {
- if (opacity > 100) {
- this.style.opacity = 1;
- } else if (opacity < 0) {
- this.style.opacity = 0;
- } else {
- this.style.opacity = opacity / 100;
- }
- },
-
- /**
* Updates the icon tooltip. If {@code autoshow} parameter is set the
* tooltip is immediatelly shown. If tooltip text is not set, the method
* ensures the tooltip gets hidden. If tooltip is shown prior to this call,
@@ -376,6 +324,8 @@ cr.define('login', function() {
* parameters.
*/
setTooltip: function(tooltip) {
+ this.iconElement.classList.toggle('icon-with-tooltip', !!tooltip);
+
if (this.tooltip_ == tooltip.text && !tooltip.autoshow)
return;
this.tooltip_ = tooltip.text;
@@ -408,29 +358,6 @@ cr.define('login', function() {
},
/**
- * Sets the icon animation parameter and starts the animation.
- * The animation is set using the resource containing all animation frames
- * concatenated horizontally. The animator offsets the background image in
- * regural intervals.
- * @param {?{resourceWidth: number, frameLengthMs: number}} animation
- * |resourceWidth|: Total width for the resource containing the
- * animation frames.
- * |frameLengthMs|: Time interval for which a single animation frame is
- * shown.
- */
- setAnimation: function(animation) {
- if (this.animationInterval_)
- clearInterval(this.animationInterval_);
- this.iconElement.style.backgroundPosition = 'center';
- if (!animation)
- return;
- this.lastAnimationOffset_ = 0;
- this.animationResourceSize_ = animation.resourceWidth;
- this.animationInterval_ = setInterval(this.progressAnimation_.bind(this),
- animation.frameLengthMs);
- },
-
- /**
* Sets up icon tabIndex attribute and handler for click and 'Enter' key
* down events.
* @param {?function()} callback If icon should be interactive, the
@@ -438,6 +365,8 @@ cr.define('login', function() {
* be null to make the icon non interactive.
*/
setInteractive: function(callback) {
+ this.iconElement.classList.toggle('interactive-custom-icon', !!callback);
+
// Update tabIndex property if needed.
if (!!this.actionHandler_ != !!callback) {
if (callback) {
@@ -453,12 +382,11 @@ cr.define('login', function() {
},
/**
- * Hides the icon. Makes sure the tooltip is hidden and animation reset.
+ * Hides the icon and cleans its state.
*/
hide: function() {
this.hideTooltip_(true);
this.hidden = true;
- this.setAnimation(null);
this.setInteractive(null);
this.resetHideTransitionState_();
},
@@ -478,6 +406,18 @@ cr.define('login', function() {
},
/**
+ * Handles mouse down event in the icon element.
+ * @param {Event} e The mouse down event.
+ * @private
+ */
+ handleMouseDown_: function(e) {
+ this.hideTooltip_(false);
+ // Stop the event propagation so in the case the click ends up on the
+ // user pod (outside the custom icon) auth is not attempted.
+ stopEventPropagation(e);
+ },
+
+ /**
* Handles click event on the icon element. No-op if
* {@code this.actionHandler_} is not set.
* @param {Event} e The click event.
@@ -569,19 +509,6 @@ cr.define('login', function() {
this.showTooltipTimeout_ = null;
}
},
-
- /**
- * Horizontally offsets the animated icon's background for a single icon
- * size width.
- * @private
- */
- progressAnimation_: function() {
- this.lastAnimationOffset_ += this.width_;
- if (this.lastAnimationOffset_ >= this.animationResourceSize_)
- this.lastAnimationOffset_ = 0;
- this.iconElement.style.backgroundPosition =
- '-' + this.lastAnimationOffset_ + 'px center';
- }
};
/**
@@ -594,6 +521,15 @@ cr.define('login', function() {
UserPod.prototype = {
__proto__: HTMLDivElement.prototype,
+ /**
+ * Whether click on the pod can issue a user click auth attempt. The
+ * attempt can be issued iff the pod was focused when the click
+ * started (i.e. on mouse down event).
+ * @type {boolean}
+ * @private
+ */
+ userClickAuthAllowed_: false,
+
/** @override */
decorate: function() {
this.tabIndex = UserPodTabOrder.POD_INPUT;
@@ -601,6 +537,7 @@ cr.define('login', function() {
this.addEventListener('keydown', this.handlePodKeyDown_.bind(this));
this.addEventListener('click', this.handleClickOnPod_.bind(this));
+ this.addEventListener('mousedown', this.handlePodMouseDown_.bind(this));
this.signinButtonElement.addEventListener('click',
this.activate.bind(this));
@@ -644,6 +581,8 @@ cr.define('login', function() {
var initialAuthType = this.user.initialAuthType ||
AUTH_TYPE.OFFLINE_PASSWORD;
this.setAuthType(initialAuthType, null);
+
+ this.userClickAuthAllowed_ = false;
},
/**
@@ -981,7 +920,7 @@ cr.define('login', function() {
} else if (this.isAuthTypeOnlineSignIn) {
return this.signinButtonElement;
} else if (this.isAuthTypeUserClick) {
- return this;
+ return this.passwordLabelElement;
}
},
@@ -1365,6 +1304,16 @@ cr.define('login', function() {
},
/**
+ * Handles mouse down event. It sets whether the user click auth will be
+ * allowed on the next mouse click event. The auth is allowed iff the pod
+ * was focused on the mouse down event starting the click.
+ * @param {Event} e The mouse down event.
+ */
+ handlePodMouseDown_: function(e) {
+ this.userClickAuthAllowed_ = this.parentNode.isFocused(this);
+ },
+
+ /**
* Handles click event on a user pod.
* @param {Event} e Click event.
*/
@@ -1375,7 +1324,9 @@ cr.define('login', function() {
if (!this.isActionBoxMenuActive) {
if (this.isAuthTypeOnlineSignIn) {
this.showSigninUI();
- } else if (this.isAuthTypeUserClick) {
+ } else if (this.isAuthTypeUserClick && this.userClickAuthAllowed_) {
+ // Note that this.userClickAuthAllowed_ is set in mouse down event
+ // handler.
this.parentNode.setActivatedPod(this);
}
@@ -2280,12 +2231,8 @@ cr.define('login', function() {
/**
* Shows a custom icon on a user pod besides the input field.
* @param {string} username Username of pod to add button
- * @param {!{resourceUrl: (string | undefined),
- * data: ({scale1x: string, scale2x: string} | undefined),
- * size: ({width: number, height: number} | undefined),
- * animation: ({resourceWidth: number, frameLength: number} |
- * undefined),
- * opacity: (number | undefined),
+ * @param {!{id: !string,
+ * hardlockOnClick: boolean,
* tooltip: ({text: string, autoshow: boolean} | undefined)}} icon
* The icon parameters.
*/
@@ -2297,20 +2244,20 @@ cr.define('login', function() {
return;
}
- if (!icon.resourceUrl)
+ if (!icon.id)
return;
- pod.customIconElement.setIconAsResourceUrl(icon.resourceUrl);
- pod.customIconElement.setSize(icon.size || {width: 0, height: 0});
- pod.customIconElement.setAnimation(icon.animation || null);
- pod.customIconElement.setOpacity(icon.opacity || 100);
+ pod.customIconElement.setIcon(icon.id);
+
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.
pod.customIconElement.setTooltip(
diff --git a/ui/resources/default_100_percent/common/easy_unlock_hardlocked_hover.png b/ui/resources/default_100_percent/common/easy_unlock_hardlocked_hover.png
new file mode 100644
index 0000000..7792ee6
--- /dev/null
+++ b/ui/resources/default_100_percent/common/easy_unlock_hardlocked_hover.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/easy_unlock_hardlocked_pressed.png b/ui/resources/default_100_percent/common/easy_unlock_hardlocked_pressed.png
new file mode 100644
index 0000000..371a40e
--- /dev/null
+++ b/ui/resources/default_100_percent/common/easy_unlock_hardlocked_pressed.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/easy_unlock_locked_hover.png b/ui/resources/default_100_percent/common/easy_unlock_locked_hover.png
new file mode 100644
index 0000000..33f2ec6
--- /dev/null
+++ b/ui/resources/default_100_percent/common/easy_unlock_locked_hover.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/easy_unlock_locked_pressed.png b/ui/resources/default_100_percent/common/easy_unlock_locked_pressed.png
new file mode 100644
index 0000000..49ccf28c
--- /dev/null
+++ b/ui/resources/default_100_percent/common/easy_unlock_locked_pressed.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/easy_unlock_unlocked_hover.png b/ui/resources/default_100_percent/common/easy_unlock_unlocked_hover.png
new file mode 100644
index 0000000..7b2ef72
--- /dev/null
+++ b/ui/resources/default_100_percent/common/easy_unlock_unlocked_hover.png
Binary files differ
diff --git a/ui/resources/default_100_percent/common/easy_unlock_unlocked_pressed.png b/ui/resources/default_100_percent/common/easy_unlock_unlocked_pressed.png
new file mode 100644
index 0000000..7f8e3e2
--- /dev/null
+++ b/ui/resources/default_100_percent/common/easy_unlock_unlocked_pressed.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/easy_unlock_hardlocked_hover.png b/ui/resources/default_200_percent/common/easy_unlock_hardlocked_hover.png
new file mode 100644
index 0000000..90fb3b2
--- /dev/null
+++ b/ui/resources/default_200_percent/common/easy_unlock_hardlocked_hover.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/easy_unlock_hardlocked_pressed.png b/ui/resources/default_200_percent/common/easy_unlock_hardlocked_pressed.png
new file mode 100644
index 0000000..e730f2a
--- /dev/null
+++ b/ui/resources/default_200_percent/common/easy_unlock_hardlocked_pressed.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/easy_unlock_locked_hover.png b/ui/resources/default_200_percent/common/easy_unlock_locked_hover.png
new file mode 100644
index 0000000..e7ee8e9
--- /dev/null
+++ b/ui/resources/default_200_percent/common/easy_unlock_locked_hover.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/easy_unlock_locked_pressed.png b/ui/resources/default_200_percent/common/easy_unlock_locked_pressed.png
new file mode 100644
index 0000000..2eebf9b
--- /dev/null
+++ b/ui/resources/default_200_percent/common/easy_unlock_locked_pressed.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/easy_unlock_unlocked_hover.png b/ui/resources/default_200_percent/common/easy_unlock_unlocked_hover.png
new file mode 100644
index 0000000..01d3f97
--- /dev/null
+++ b/ui/resources/default_200_percent/common/easy_unlock_unlocked_hover.png
Binary files differ
diff --git a/ui/resources/default_200_percent/common/easy_unlock_unlocked_pressed.png b/ui/resources/default_200_percent/common/easy_unlock_unlocked_pressed.png
new file mode 100644
index 0000000..b7e1b52
--- /dev/null
+++ b/ui/resources/default_200_percent/common/easy_unlock_unlocked_pressed.png
Binary files differ
diff --git a/ui/resources/ui_resources.grd b/ui/resources/ui_resources.grd
index 18394f4..1bae8be 100644
--- a/ui/resources/ui_resources.grd
+++ b/ui/resources/ui_resources.grd
@@ -260,9 +260,15 @@
<structure type="chrome_scaled_image" name="IDR_DEFAULT_FAVICON_32" file="common/default_favicon_32.png" />
<structure type="chrome_scaled_image" name="IDR_DEFAULT_FAVICON_64" file="common/default_favicon_64.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_HARDLOCKED" file="common/easy_unlock_hardlocked.png" />
+ <structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_HARDLOCKED_HOVER" file="common/easy_unlock_hardlocked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_HARDLOCKED_PRESSED" file="common/easy_unlock_hardlocked_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_LOCKED" file="common/easy_unlock_locked.png" />
+ <structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_LOCKED_HOVER" file="common/easy_unlock_locked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_LOCKED_PRESSED" file="common/easy_unlock_locked_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_SPINNER" file="common/easy_unlock_spinner.png" />
<structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED" file="common/easy_unlock_unlocked.png" />
+ <structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED_HOVER" file="common/easy_unlock_unlocked_hover.png" />
+ <structure type="chrome_scaled_image" name="IDR_EASY_UNLOCK_UNLOCKED_PRESSED" file="common/easy_unlock_unlocked_pressed.png" />
<structure type="chrome_scaled_image" name="IDR_FOLDER_CLOSED" file="common/folder_closed.png" />
<structure type="chrome_scaled_image" name="IDR_FOLDER_CLOSED_RTL" file="common/folder_closed_rtl.png" />
<if expr="toolkit_views">