Commit a4e2242b authored by calamity's avatar calamity Committed by Commit bot

Correctly handle tab navigation in the app list.

This CL causes the app list tab navigation to correctly cycle to and from
the custom launcher page. This has been fixed by adding a SearchBoxFocusHost
which directs the focus search to the search box.

BUG=462079

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

Cr-Commit-Position: refs/heads/master@{#318814}
parent 5f1263bb
......@@ -20,8 +20,11 @@
#include "ui/app_list/views/app_list_main_view.h"
#include "ui/app_list/views/app_list_view.h"
#include "ui/app_list/views/contents_view.h"
#include "ui/app_list/views/search_box_view.h"
#include "ui/events/test/event_generator.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/controls/webview/webview.h"
#include "ui/views/focus/focus_manager.h"
namespace {
......@@ -383,3 +386,43 @@ IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest, LauncherPageSetEnabled) {
EXPECT_TRUE(model->custom_launcher_page_enabled());
EXPECT_TRUE(custom_page_view->visible());
}
IN_PROC_BROWSER_TEST_F(CustomLauncherPageBrowserTest,
LauncherPageFocusTraversal) {
LoadAndLaunchPlatformApp(kCustomLauncherPagePath, "Launched");
app_list::AppListView* app_list_view = GetAppListView();
app_list::ContentsView* contents_view =
app_list_view->app_list_main_view()->contents_view();
app_list::SearchBoxView* search_box_view =
app_list_view->app_list_main_view()->search_box_view();
ASSERT_TRUE(
contents_view->IsStateActive(app_list::AppListModel::STATE_START));
EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(),
search_box_view->search_box());
{
ExtensionTestMessageListener listener("onPageProgressAt1", false);
contents_view->SetActivePage(contents_view->GetPageIndexForState(
app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE));
listener.WaitUntilSatisfied();
EXPECT_TRUE(contents_view->IsStateActive(
app_list::AppListModel::STATE_CUSTOM_LAUNCHER_PAGE));
EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(),
search_box_view->search_box());
}
{
ExtensionTestMessageListener listener("textfieldFocused", false);
app_list_view->GetFocusManager()->AdvanceFocus(false);
listener.WaitUntilSatisfied();
EXPECT_NE(app_list_view->GetFocusManager()->GetFocusedView(),
search_box_view->search_box());
}
{
ExtensionTestMessageListener listener("textfieldBlurred", false);
app_list_view->GetFocusManager()->AdvanceFocus(false);
listener.WaitUntilSatisfied();
EXPECT_EQ(app_list_view->GetFocusManager()->GetFocusedView(),
search_box_view->search_box());
}
}
......@@ -6,6 +6,7 @@
<html>
<body>
<input id="textfield" type="text">
<script src="main.js"></script>
</body>
</html>
......@@ -31,4 +31,15 @@ function enableCustomLauncherPage() {
});
}
chrome.test.sendMessage('Launched');
document.addEventListener('DOMContentLoaded', function() {
chrome.test.sendMessage('Launched');
});
var textfield = document.getElementById('textfield');
textfield.onfocus = function() {
chrome.test.sendMessage('textfieldFocused');
};
textfield.onblur = function() {
chrome.test.sendMessage('textfieldBlurred');
};
......@@ -83,6 +83,25 @@ bool SupportsShadow() {
return true;
}
// This view forwards the focus to the search box widget by providing it as a
// FocusTraversable when a focus search is provided.
class SearchBoxFocusHost : public views::View {
public:
explicit SearchBoxFocusHost(views::Widget* search_box_widget)
: search_box_widget_(search_box_widget) {}
~SearchBoxFocusHost() override {}
views::FocusTraversable* GetFocusTraversable() override {
return search_box_widget_;
}
private:
views::Widget* search_box_widget_;
DISALLOW_COPY_AND_ASSIGN(SearchBoxFocusHost);
};
// The view for the App List overlay, which appears as a white rounded
// rectangle with the given radius.
class AppListOverlayView : public views::View {
......@@ -182,6 +201,7 @@ AppListView::AppListView(AppListViewDelegate* delegate)
: delegate_(delegate),
app_list_main_view_(nullptr),
speech_view_(nullptr),
search_box_focus_host_(nullptr),
search_box_widget_(nullptr),
search_box_view_(nullptr),
overlay_view_(nullptr),
......@@ -463,6 +483,15 @@ void AppListView::InitChildWidgets() {
search_box_widget_->Init(search_box_widget_params);
search_box_widget_->SetContentsView(search_box_view_);
// The search box will not naturally receive focus by itself (because it is in
// a separate widget). Create this SearchBoxFocusHost in the main widget to
// forward the focus search into to the search box.
search_box_focus_host_ = new SearchBoxFocusHost(search_box_widget_);
AddChildView(search_box_focus_host_);
search_box_widget_->SetFocusTraversableParentView(search_box_focus_host_);
search_box_widget_->SetFocusTraversableParent(
GetWidget()->GetFocusTraversable());
#if defined(USE_AURA)
// Mouse events on the search box shadow should not be captured.
aura::Window* window = search_box_widget_->GetNativeWindow();
......
......@@ -173,6 +173,7 @@ class APP_LIST_EXPORT AppListView : public views::BubbleDelegateView,
AppListMainView* app_list_main_view_;
SpeechView* speech_view_;
views::View* search_box_focus_host_; // Owned by the views hierarchy.
views::Widget* search_box_widget_; // Owned by the app list's widget.
SearchBoxView* search_box_view_; // Owned by |search_box_widget_|.
......
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