Commit 57636f80 authored by Aga Wronska's avatar Aga Wronska Committed by Commit Bot

Toggle pin keyboard visibility according to virtual keyboard appearance.

Pin keyboard should be only visible when there is no virtul keyboard
displayed.
Observe virtual keyboard state in order to update pin keyboard visibility.

Bug: 799082
Change-Id: I9ef33faf699dfc78cdd09145f4c2aee43e52afab
Reviewed-on: https://chromium-review.googlesource.com/903414
Commit-Queue: Aga Wronska <agawronska@chromium.org>
Reviewed-by: default avatarJacob Dufault <jdufault@chromium.org>
Cr-Commit-Position: refs/heads/master@{#537333}
parent 3656c9a8
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "ash/focus_cycler.h" #include "ash/focus_cycler.h"
#include "ash/ime/ime_controller.h" #include "ash/ime/ime_controller.h"
#include "ash/keyboard/keyboard_observer_register.h"
#include "ash/login/login_screen_controller.h" #include "ash/login/login_screen_controller.h"
#include "ash/login/ui/layout_util.h" #include "ash/login/ui/layout_util.h"
#include "ash/login/ui/lock_screen.h" #include "ash/login/ui/lock_screen.h"
...@@ -156,6 +157,19 @@ views::Label* CreateInfoLabel() { ...@@ -156,6 +157,19 @@ views::Label* CreateInfoLabel() {
return label; return label;
} }
keyboard::KeyboardController* GetKeyboardControllerForWidget(
const views::Widget* widget) {
keyboard::KeyboardController* keyboard_controller =
keyboard::KeyboardController::GetInstance();
if (!keyboard_controller)
return nullptr;
aura::Window* keyboard_window =
keyboard_controller->GetContainerWindow()->GetRootWindow();
aura::Window* this_window = widget->GetNativeWindow()->GetRootWindow();
return keyboard_window == this_window ? keyboard_controller : nullptr;
}
} // namespace } // namespace
LockContentsView::TestApi::TestApi(LockContentsView* view) : view_(view) {} LockContentsView::TestApi::TestApi(LockContentsView* view) : view_(view) {}
...@@ -199,7 +213,8 @@ LockContentsView::LockContentsView( ...@@ -199,7 +213,8 @@ LockContentsView::LockContentsView(
: NonAccessibleView(kLockContentsViewName), : NonAccessibleView(kLockContentsViewName),
data_dispatcher_(data_dispatcher), data_dispatcher_(data_dispatcher),
display_observer_(this), display_observer_(this),
session_observer_(this) { session_observer_(this),
keyboard_observer_(this) {
data_dispatcher_->AddObserver(this); data_dispatcher_->AddObserver(this);
display_observer_.Add(display::Screen::GetScreen()); display_observer_.Add(display::Screen::GetScreen());
Shell::Get()->login_screen_controller()->AddLockScreenAppsFocusObserver(this); Shell::Get()->login_screen_controller()->AddLockScreenAppsFocusObserver(this);
...@@ -239,6 +254,7 @@ LockContentsView::LockContentsView( ...@@ -239,6 +254,7 @@ LockContentsView::LockContentsView(
top_header_->AddChildView(note_action_); top_header_->AddChildView(note_action_);
OnLockScreenNoteStateChanged(initial_note_action_state); OnLockScreenNoteStateChanged(initial_note_action_state);
Shell::Get()->AddShellObserver(this);
} }
LockContentsView::~LockContentsView() { LockContentsView::~LockContentsView() {
...@@ -254,6 +270,8 @@ LockContentsView::~LockContentsView() { ...@@ -254,6 +270,8 @@ LockContentsView::~LockContentsView() {
Shell::Get()->metrics()->login_metrics_recorder()->RecordNumLoginAttempts( Shell::Get()->metrics()->login_metrics_recorder()->RecordNumLoginAttempts(
unlock_attempt_, false /*success*/); unlock_attempt_, false /*success*/);
} }
Shell::Get()->RemoveShellObserver(this);
keyboard_observer_.RemoveAll();
} }
void LockContentsView::Layout() { void LockContentsView::Layout() {
...@@ -265,6 +283,14 @@ void LockContentsView::Layout() { ...@@ -265,6 +283,14 @@ void LockContentsView::Layout() {
} }
void LockContentsView::AddedToWidget() { void LockContentsView::AddedToWidget() {
// Register keyboard observer after view has been added to the widget. If
// virtual keyboard is activated before displaying lock screen we do not
// receive OnVirtualKeyboardStateChanged() callback and we need to register
// keyboard observer here.
keyboard::KeyboardController* keyboard_controller = GetKeyboardController();
if (keyboard_controller)
keyboard_observer_.Add(keyboard_controller);
DoLayout(); DoLayout();
// Focus the primary user when showing the UI. This will focus the password. // Focus the primary user when showing the UI. This will focus the password.
...@@ -490,6 +516,25 @@ void LockContentsView::OnLockStateChanged(bool locked) { ...@@ -490,6 +516,25 @@ void LockContentsView::OnLockStateChanged(bool locked) {
} }
} }
void LockContentsView::OnVirtualKeyboardStateChanged(
bool activated,
aura::Window* root_window) {
const views::Widget* widget = GetWidget();
if (widget) {
UpdateKeyboardObserverFromStateChanged(
activated, root_window, widget->GetNativeWindow()->GetRootWindow(),
&keyboard_observer_);
}
}
void LockContentsView::OnStateChanged(
const keyboard::KeyboardControllerState state) {
if (state == keyboard::KeyboardControllerState::SHOWN ||
state == keyboard::KeyboardControllerState::HIDDEN) {
LayoutAuth(primary_auth_, opt_secondary_auth_, false /*animate*/);
}
}
void LockContentsView::FocusNextWidget(bool reverse) { void LockContentsView::FocusNextWidget(bool reverse) {
Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow()); Shelf* shelf = Shelf::ForWindow(GetWidget()->GetNativeWindow());
// Tell the focus direction to the status area or the shelf so they can focus // Tell the focus direction to the status area or the shelf so they can focus
...@@ -661,7 +706,10 @@ void LockContentsView::LayoutAuth(LoginAuthUserView* to_update, ...@@ -661,7 +706,10 @@ void LockContentsView::LayoutAuth(LoginAuthUserView* to_update,
uint32_t to_update_auth = LoginAuthUserView::AUTH_PASSWORD; uint32_t to_update_auth = LoginAuthUserView::AUTH_PASSWORD;
UserState* state = UserState* state =
FindStateForUser(to_update->current_user()->basic_user_info->account_id); FindStateForUser(to_update->current_user()->basic_user_info->account_id);
if (state->show_pin) keyboard::KeyboardController* keyboard_controller = GetKeyboardController();
bool keyboard_visible =
keyboard_controller ? keyboard_controller->keyboard_visible() : false;
if (state->show_pin && !keyboard_visible)
to_update_auth |= LoginAuthUserView::AUTH_PIN; to_update_auth |= LoginAuthUserView::AUTH_PIN;
if (state->enable_tap_auth) if (state->enable_tap_auth)
to_update_auth |= LoginAuthUserView::AUTH_TAP; to_update_auth |= LoginAuthUserView::AUTH_TAP;
...@@ -813,6 +861,10 @@ void LockContentsView::OnEasyUnlockIconTapped() { ...@@ -813,6 +861,10 @@ void LockContentsView::OnEasyUnlockIconTapped() {
} }
} }
keyboard::KeyboardController* LockContentsView::GetKeyboardController() const {
return GetWidget() ? GetKeyboardControllerForWidget(GetWidget()) : nullptr;
}
LoginAuthUserView* LockContentsView::AllocateLoginAuthUserView( LoginAuthUserView* LockContentsView::AllocateLoginAuthUserView(
const mojom::LoginUserInfoPtr& user, const mojom::LoginUserInfoPtr& user,
bool is_primary) { bool is_primary) {
......
...@@ -15,15 +15,21 @@ ...@@ -15,15 +15,21 @@
#include "ash/login/ui/login_display_style.h" #include "ash/login/ui/login_display_style.h"
#include "ash/login/ui/non_accessible_view.h" #include "ash/login/ui/non_accessible_view.h"
#include "ash/session/session_observer.h" #include "ash/session/session_observer.h"
#include "ash/shell_observer.h"
#include "ash/system/system_tray_focus_observer.h" #include "ash/system/system_tray_focus_observer.h"
#include "base/macros.h" #include "base/macros.h"
#include "base/optional.h" #include "base/optional.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "ui/display/display_observer.h" #include "ui/display/display_observer.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
#include "ui/keyboard/keyboard_controller_observer.h"
#include "ui/views/controls/styled_label_listener.h" #include "ui/views/controls/styled_label_listener.h"
#include "ui/views/view.h" #include "ui/views/view.h"
namespace keyboard {
class KeyboardController;
} // namespace keyboard
namespace views { namespace views {
class BoxLayout; class BoxLayout;
class StyledLabel; class StyledLabel;
...@@ -50,7 +56,9 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView, ...@@ -50,7 +56,9 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView,
public SystemTrayFocusObserver, public SystemTrayFocusObserver,
public display::DisplayObserver, public display::DisplayObserver,
public views::StyledLabelListener, public views::StyledLabelListener,
public SessionObserver { public SessionObserver,
public keyboard::KeyboardControllerObserver,
public ShellObserver {
public: public:
// TestApi is used for tests to get internal implementation details. // TestApi is used for tests to get internal implementation details.
class ASH_EXPORT TestApi { class ASH_EXPORT TestApi {
...@@ -111,6 +119,13 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView, ...@@ -111,6 +119,13 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView,
// SessionObserver: // SessionObserver:
void OnLockStateChanged(bool locked) override; void OnLockStateChanged(bool locked) override;
// ash::ShellObserver:
void OnVirtualKeyboardStateChanged(bool activated,
aura::Window* root_window) override;
// keyboard::KeyboardControllerObserver:
void OnStateChanged(const keyboard::KeyboardControllerState state) override;
private: private:
class UserState { class UserState {
public: public:
...@@ -201,6 +216,11 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView, ...@@ -201,6 +216,11 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView,
// Called when the easy unlock icon is tapped. // Called when the easy unlock icon is tapped.
void OnEasyUnlockIconTapped(); void OnEasyUnlockIconTapped();
// Returns keyboard controller for the view. Returns nullptr if keyboard is
// not activated, view has not been added to the widget yet or keyboard is not
// displayed in this window.
keyboard::KeyboardController* GetKeyboardController() const;
// Helper method to allocate a LoginAuthUserView instance. // Helper method to allocate a LoginAuthUserView instance.
LoginAuthUserView* AllocateLoginAuthUserView( LoginAuthUserView* AllocateLoginAuthUserView(
const mojom::LoginUserInfoPtr& user, const mojom::LoginUserInfoPtr& user,
...@@ -248,6 +268,9 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView, ...@@ -248,6 +268,9 @@ class ASH_EXPORT LockContentsView : public NonAccessibleView,
ScopedObserver<display::Screen, display::DisplayObserver> display_observer_; ScopedObserver<display::Screen, display::DisplayObserver> display_observer_;
ScopedSessionObserver session_observer_; ScopedSessionObserver session_observer_;
ScopedObserver<keyboard::KeyboardController,
keyboard::KeyboardControllerObserver>
keyboard_observer_;
std::unique_ptr<LoginBubble> error_bubble_; std::unique_ptr<LoginBubble> error_bubble_;
std::unique_ptr<LoginBubble> tooltip_bubble_; std::unique_ptr<LoginBubble> tooltip_bubble_;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "ash/login/ui/login_bubble.h" #include "ash/login/ui/login_bubble.h"
#include "ash/login/ui/login_display_style.h" #include "ash/login/ui/login_display_style.h"
#include "ash/login/ui/login_keyboard_test_base.h" #include "ash/login/ui/login_keyboard_test_base.h"
#include "ash/login/ui/login_pin_view.h"
#include "ash/login/ui/login_test_base.h" #include "ash/login/ui/login_test_base.h"
#include "ash/login/ui/login_user_view.h" #include "ash/login/ui/login_user_view.h"
#include "ash/login/ui/scrollable_users_list_view.h" #include "ash/login/ui/scrollable_users_list_view.h"
...@@ -638,4 +639,30 @@ TEST_F(LockContentsViewUnitTest, EasyUnlockIconUpdatedDuringUserSwap) { ...@@ -638,4 +639,30 @@ TEST_F(LockContentsViewUnitTest, EasyUnlockIconUpdatedDuringUserSwap) {
EXPECT_FALSE(showing_easy_unlock_icon(secondary)); EXPECT_FALSE(showing_easy_unlock_icon(secondary));
} }
TEST_F(LockContentsViewKeyboardUnitTest, SwitchPinAndVirtualKeyboard) {
ASSERT_NO_FATAL_FAILURE(ShowLockScreen());
LockContentsView* contents =
LockScreen::TestApi(LockScreen::Get()).contents_view();
ASSERT_NE(nullptr, contents);
// Add user with enabled pin method of authentication.
const std::string email = "user@domain.com";
LoadUser(email);
contents->OnPinEnabledForUserChanged(AccountId::FromUserEmail(email), true);
LoginAuthUserView* auth_view =
LockContentsView::TestApi(contents).primary_auth();
ASSERT_NE(nullptr, auth_view);
// Pin keyboard should only be visible when there is no virtual keyboard
// shown.
LoginPinView* pin_view = LoginAuthUserView::TestApi(auth_view).pin_view();
EXPECT_TRUE(pin_view->visible());
ASSERT_NO_FATAL_FAILURE(ShowKeyboard());
EXPECT_FALSE(pin_view->visible());
ASSERT_NO_FATAL_FAILURE(HideKeyboard());
EXPECT_TRUE(pin_view->visible());
}
} // namespace ash } // namespace ash
...@@ -94,6 +94,10 @@ LoginPasswordView* LoginAuthUserView::TestApi::password_view() const { ...@@ -94,6 +94,10 @@ LoginPasswordView* LoginAuthUserView::TestApi::password_view() const {
return view_->password_view_; return view_->password_view_;
} }
LoginPinView* LoginAuthUserView::TestApi::pin_view() const {
return view_->pin_view_;
}
LoginAuthUserView::LoginAuthUserView( LoginAuthUserView::LoginAuthUserView(
const mojom::LoginUserInfoPtr& user, const mojom::LoginUserInfoPtr& user,
const OnAuthCallback& on_auth, const OnAuthCallback& on_auth,
......
...@@ -38,6 +38,7 @@ class ASH_EXPORT LoginAuthUserView : public NonAccessibleView { ...@@ -38,6 +38,7 @@ class ASH_EXPORT LoginAuthUserView : public NonAccessibleView {
LoginUserView* user_view() const; LoginUserView* user_view() const;
LoginPasswordView* password_view() const; LoginPasswordView* password_view() const;
LoginPinView* pin_view() const;
private: private:
LoginAuthUserView* const view_; LoginAuthUserView* const view_;
......
...@@ -22,7 +22,7 @@ class LoginAuthUserViewUnittest : public LoginTestBase { ...@@ -22,7 +22,7 @@ class LoginAuthUserViewUnittest : public LoginTestBase {
void SetUp() override { void SetUp() override {
LoginTestBase::SetUp(); LoginTestBase::SetUp();
user_ = CreateUser("user"); user_ = CreateUser("user@domain.com");
view_ = new LoginAuthUserView( view_ = new LoginAuthUserView(
user_, base::Bind([](bool auth_success) {}) /*on_auth*/, user_, base::Bind([](bool auth_success) {}) /*on_auth*/,
base::Bind([]() {}) /*on_easy_unlock_icon_hovered*/, base::Bind([]() {}) /*on_easy_unlock_icon_hovered*/,
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "ash/session/test_session_controller_client.h" #include "ash/session/test_session_controller_client.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/strings/strcat.h"
#include "ui/keyboard/keyboard_controller.h" #include "ui/keyboard/keyboard_controller.h"
#include "ui/keyboard/keyboard_switches.h" #include "ui/keyboard/keyboard_switches.h"
#include "ui/keyboard/keyboard_test_util.h" #include "ui/keyboard/keyboard_test_util.h"
...@@ -96,9 +97,17 @@ void LoginKeyboardTestBase::ShowLoginScreen() { ...@@ -96,9 +97,17 @@ void LoginKeyboardTestBase::ShowLoginScreen() {
void LoginKeyboardTestBase::LoadUsers(int count) { void LoginKeyboardTestBase::LoadUsers(int count) {
std::vector<mojom::LoginUserInfoPtr> users; std::vector<mojom::LoginUserInfoPtr> users;
for (int i = 0; i < count; ++i) { for (int i = 0; i < count; ++i) {
users.push_back(CreateUser("user")); std::string email =
base::StrCat({"user", std::to_string(i), "@domain.com "});
users.push_back(CreateUser(email));
} }
login_controller_->LoadUsers(std::move(users), false); login_controller_->LoadUsers(std::move(users), false);
} }
void LoginKeyboardTestBase::LoadUser(const std::string& email) {
std::vector<mojom::LoginUserInfoPtr> users;
users.push_back(CreateUser(email));
login_controller_->LoadUsers(std::move(users), false);
}
} // namespace ash } // namespace ash
...@@ -44,9 +44,12 @@ class LoginKeyboardTestBase : public AshTestBase { ...@@ -44,9 +44,12 @@ class LoginKeyboardTestBase : public AshTestBase {
// of the test on failed assertion use ASSERT_NO_FATAL_FAILURE macro. // of the test on failed assertion use ASSERT_NO_FATAL_FAILURE macro.
void ShowLoginScreen(); void ShowLoginScreen();
// Loads the number of test users specified by |count|; // Loads the number of test users specified by |count|.
void LoadUsers(int count); void LoadUsers(int count);
// Loads user with the specified |email|.
void LoadUser(const std::string& email);
// AshTestBase: // AshTestBase:
void SetUp() override; void SetUp() override;
void TearDown() override; void TearDown() override;
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "ash/public/cpp/shell_window_ids.h" #include "ash/public/cpp/shell_window_ids.h"
#include "ash/public/interfaces/tray_action.mojom.h" #include "ash/public/interfaces/tray_action.mojom.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/strings/strcat.h"
#include "services/ui/public/cpp/property_type_converters.h" #include "services/ui/public/cpp/property_type_converters.h"
#include "services/ui/public/interfaces/window_manager.mojom.h" #include "services/ui/public/interfaces/window_manager.mojom.h"
#include "ui/views/widget/widget.h" #include "ui/views/widget/widget.h"
...@@ -71,8 +72,11 @@ std::unique_ptr<views::Widget> LoginTestBase::CreateWidgetWithContent( ...@@ -71,8 +72,11 @@ std::unique_ptr<views::Widget> LoginTestBase::CreateWidgetWithContent(
void LoginTestBase::SetUserCount(size_t count) { void LoginTestBase::SetUserCount(size_t count) {
// Add missing users, then remove extra users. // Add missing users, then remove extra users.
while (users_.size() < count) while (users_.size() < count) {
users_.push_back(CreateUser(std::to_string(users_.size()))); std::string email =
base::StrCat({"user", std::to_string(users_.size()), "@domain.com"});
users_.push_back(CreateUser(email));
}
users_.erase(users_.begin() + count, users_.end()); users_.erase(users_.begin() + count, users_.end());
// Notify any listeners that the user count has changed. // Notify any listeners that the user count has changed.
......
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
// found in the LICENSE file. // found in the LICENSE file.
#include "ash/login/ui/login_test_utils.h" #include "ash/login/ui/login_test_utils.h"
#include "base/strings/string_split.h"
namespace ash { namespace ash {
...@@ -20,14 +21,13 @@ LoginPasswordView::TestApi MakeLoginPasswordTestApi(LockContentsView* view) { ...@@ -20,14 +21,13 @@ LoginPasswordView::TestApi MakeLoginPasswordTestApi(LockContentsView* view) {
MakeLoginPrimaryAuthTestApi(view).password_view()); MakeLoginPrimaryAuthTestApi(view).password_view());
} }
mojom::LoginUserInfoPtr CreateUser(const std::string& name) { mojom::LoginUserInfoPtr CreateUser(const std::string& email) {
auto user = mojom::LoginUserInfo::New(); auto user = mojom::LoginUserInfo::New();
user->basic_user_info = mojom::UserInfo::New(); user->basic_user_info = mojom::UserInfo::New();
user->basic_user_info->account_id = user->basic_user_info->account_id = AccountId::FromUserEmail(email);
AccountId::FromUserEmail(name + "@foo.com"); user->basic_user_info->display_name = base::SplitString(
user->basic_user_info->display_name = "User " + name; email, "@", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL)[0];
user->basic_user_info->display_email = user->basic_user_info->display_email = email;
user->basic_user_info->account_id.GetUserEmail();
return user; return user;
} }
......
...@@ -18,7 +18,7 @@ LoginAuthUserView::TestApi MakeLoginPrimaryAuthTestApi(LockContentsView* view); ...@@ -18,7 +18,7 @@ LoginAuthUserView::TestApi MakeLoginPrimaryAuthTestApi(LockContentsView* view);
LoginPasswordView::TestApi MakeLoginPasswordTestApi(LockContentsView* view); LoginPasswordView::TestApi MakeLoginPasswordTestApi(LockContentsView* view);
// Utility method to create a new |mojom::UserInfoPtr| instance. // Utility method to create a new |mojom::UserInfoPtr| instance.
mojom::LoginUserInfoPtr CreateUser(const std::string& name); mojom::LoginUserInfoPtr CreateUser(const std::string& email);
} // namespace ash } // namespace ash
......
...@@ -28,7 +28,7 @@ class LoginUserViewUnittest : public LoginTestBase { ...@@ -28,7 +28,7 @@ class LoginUserViewUnittest : public LoginTestBase {
new LoginUserView(display_style, show_dropdown, new LoginUserView(display_style, show_dropdown,
base::BindRepeating(&LoginUserViewUnittest::OnTapped, base::BindRepeating(&LoginUserViewUnittest::OnTapped,
base::Unretained(this))); base::Unretained(this)));
mojom::LoginUserInfoPtr user = CreateUser("foo"); mojom::LoginUserInfoPtr user = CreateUser("foo@foo.com");
view->UpdateForUser(user, false /*animate*/); view->UpdateForUser(user, false /*animate*/);
container_->AddChildView(view); container_->AddChildView(view);
widget()->GetContentsView()->Layout(); widget()->GetContentsView()->Layout();
...@@ -77,8 +77,7 @@ TEST_F(LoginUserViewUnittest, DifferentUsernamesHaveSameWidth) { ...@@ -77,8 +77,7 @@ TEST_F(LoginUserViewUnittest, DifferentUsernamesHaveSameWidth) {
EXPECT_GT(extra_small_width, 0); EXPECT_GT(extra_small_width, 0);
for (int i = 0; i < 25; ++i) { for (int i = 0; i < 25; ++i) {
std::string name(i, 'a'); mojom::LoginUserInfoPtr user = CreateUser("user@domain.com");
mojom::LoginUserInfoPtr user = CreateUser(name);
large->UpdateForUser(user, false /*animate*/); large->UpdateForUser(user, false /*animate*/);
small->UpdateForUser(user, false /*animate*/); small->UpdateForUser(user, false /*animate*/);
extra_small->UpdateForUser(user, false /*animate*/); extra_small->UpdateForUser(user, false /*animate*/);
......
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