blob: b7a6b769dcc592291190d99b17b7f89288ff7ef9 [file] [log] [blame]
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/views/intent_picker_bubble_view.h"
#include <optional>
#include <string>
#include "base/feature_list.h"
#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ptr.h"
#include "base/test/scoped_feature_list.h"
#include "build/build_config.h"
#include "chrome/browser/apps/link_capturing/intent_picker_info.h"
#include "chrome/browser/apps/link_capturing/link_capturing_feature_test_support.h"
#include "chrome/browser/ui/views/frame/browser_view.h"
#include "chrome/browser/ui/views/frame/test_with_browser_view.h"
#include "chrome/browser/ui/views/toolbar/toolbar_view.h"
#include "chrome/browser/web_applications/link_capturing_features.h"
#include "chrome/common/chrome_features.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/test/views/chrome_views_test_base.h"
#include "components/services/app_service/public/cpp/intent_util.h"
#include "content/public/browser/web_contents.h"
#include "content/public/common/content_features.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/models/image_model.h"
#include "ui/base/mojom/dialog_button.mojom.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/events/base_event_utils.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/test/event_generator.h"
#include "ui/events/types/event_type.h"
#include "ui/gfx/image/image.h"
#include "ui/strings/grit/ui_strings.h"
#include "ui/views/animation/ink_drop.h"
#include "ui/views/animation/ink_drop_state.h"
#include "ui/views/bubble/bubble_frame_view.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/checkbox.h"
#include "ui/views/controls/scroll_view.h"
#include "ui/views/resources/grit/views_resources.h"
#include "ui/views/test/button_test_api.h"
#include "ui/views/test/views_test_base.h"
#include "ui/views/view_utils.h"
#include "ui/views/widget/widget_utils.h"
#include "url/gurl.h"
#include "url/origin.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "chromeos/ash/experiences/arc/intent_helper/arc_intent_helper_package.h"
#endif
using AppInfo = apps::IntentPickerAppInfo;
using BubbleType = apps::IntentPickerBubbleType;
using content::OpenURLParams;
using content::Referrer;
using content::WebContents;
class IntentPickerBubbleViewTest : public TestWithBrowserView {
public:
IntentPickerBubbleViewTest() = default;
IntentPickerBubbleViewTest(const IntentPickerBubbleViewTest&) = delete;
IntentPickerBubbleViewTest& operator=(const IntentPickerBubbleViewTest&) =
delete;
protected:
ChromeViewsTestBase::WidgetAutoclosePtr CreateBubbleView(
bool use_icons,
bool show_stay_in_chrome,
BubbleType bubble_type,
const std::optional<url::Origin>& initiating_origin) {
DCHECK(!app_info_.empty());
BrowserView* browser_view =
BrowserView::GetBrowserViewForBrowser(browser());
anchor_view_ =
browser_view->toolbar()->AddChildView(std::make_unique<views::View>());
if (use_icons) {
FillAppListWithDummyIcons();
}
// We create |web_contents| since the Bubble UI has an Observer that
// depends on this, otherwise it wouldn't work.
GURL url("http://www.google.com");
WebContents* web_contents = browser()->OpenURL(
OpenURLParams(url, Referrer(), WindowOpenDisposition::CURRENT_TAB,
ui::PAGE_TRANSITION_TYPED, false),
/*navigation_handle_callback=*/{});
CommitPendingLoad(&web_contents->GetController());
auto* widget = IntentPickerBubbleView::ShowBubble(
anchor_view_, /*highlighted_button=*/nullptr, bubble_type, web_contents,
app_info_, show_stay_in_chrome,
/*show_remember_selection=*/true, initiating_origin,
base::BindOnce(&IntentPickerBubbleViewTest::OnBubbleClosed,
base::Unretained(this)));
event_generator_.reset(); // Mac only allows one EventGenerator at a time.
event_generator_ = std::make_unique<ui::test::EventGenerator>(
views::GetRootWindow(widget));
return ChromeViewsTestBase::WidgetAutoclosePtr(widget);
}
// Add an app to the bubble opened by CreateBubbleView. Manually added apps
// will appear before automatic placeholder apps.
void AddApp(apps::PickerEntryType app_type,
const std::string& launch_name,
const std::string& title) {
app_info_.emplace_back(app_type, ui::ImageModel(), launch_name, title);
}
void AddDefaultApps() {
AddApp(apps::PickerEntryType::kArc, "package_1", "App 1");
AddApp(apps::PickerEntryType::kArc, "package_2", "App 2");
}
void FillAppListWithDummyIcons() {
ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
ui::ImageModel dummy_icon_model =
ui::ImageModel::FromImage(rb.GetImageNamed(IDR_CLOSE));
for (auto& app : app_info_) {
app.icon_model = dummy_icon_model;
}
}
views::Button* GetButtonAtIndex(size_t index) {
auto children =
bubble()
->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
->children();
CHECK_LT(index, children.size());
return views::AsViewClass<views::Button>(children[index]);
}
views::LabelButton* GetLabelButtonAtIndex(size_t index) {
CHECK(!apps::features::ShouldShowLinkCapturingUX());
return views::AsViewClass<views::LabelButton>(GetButtonAtIndex(index));
}
void ClickApp(size_t index) {
event_generator().MoveMouseTo(
GetButtonAtIndex(index)->GetBoundsInScreen().CenterPoint());
event_generator().ClickLeftButton();
}
views::InkDropState GetInkDropState(size_t index) {
return views::InkDrop::Get(GetButtonAtIndex(index))
->GetInkDrop()
->GetTargetInkDropState();
}
size_t GetScrollViewSize() {
return bubble()
->GetViewByID(IntentPickerBubbleView::ViewId::kItemContainer)
->children()
.size();
}
void OnBubbleClosed(const std::string& selected_app_launch_name,
apps::PickerEntryType entry_type,
apps::IntentPickerCloseReason close_reason,
bool should_persist) {
last_selected_launch_name_ = selected_app_launch_name;
last_close_reason_ = close_reason;
last_selection_should_persist_ = should_persist;
}
IntentPickerBubbleView* bubble() {
return IntentPickerBubbleView::intent_picker_bubble();
}
const std::vector<AppInfo>& app_info() { return app_info_; }
ui::test::EventGenerator& event_generator() {
return *event_generator_.get();
}
const std::string& last_selected_launch_name() {
return last_selected_launch_name_;
}
apps::IntentPickerCloseReason last_close_reason() {
return last_close_reason_;
}
bool last_selection_should_persist() {
return last_selection_should_persist_;
}
private:
raw_ptr<views::View, DanglingUntriaged> anchor_view_;
std::vector<AppInfo> app_info_;
std::unique_ptr<ui::test::EventGenerator> event_generator_;
std::string last_selected_launch_name_;
apps::IntentPickerCloseReason last_close_reason_;
bool last_selection_should_persist_;
};
#if !BUILDFLAG(IS_CHROMEOS)
// This test runs only on non ChromeOS platforms, since navigation capturing has
// not fully launched to 100% of the Stable population.
class IntentPickerBubbleViewListTest : public IntentPickerBubbleViewTest {
public:
IntentPickerBubbleViewListTest() {
feature_list_.InitAndDisableFeature(features::kPwaNavigationCapturing);
}
private:
base::test::ScopedFeatureList feature_list_;
};
// Verifies that we didn't set up an image for any LabelButton.
TEST_F(IntentPickerBubbleViewListTest, NullIcons) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
size_t size = GetScrollViewSize();
for (size_t i = 0; i < size; ++i) {
gfx::ImageSkia image =
GetLabelButtonAtIndex(i)->GetImage(views::Button::STATE_NORMAL);
EXPECT_TRUE(image.isNull()) << i;
}
}
// Verifies that all the icons contain a non-null icon.
TEST_F(IntentPickerBubbleViewListTest, NonNullIcons) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
size_t size = GetScrollViewSize();
for (size_t i = 0; i < size; ++i) {
gfx::ImageSkia image =
GetLabelButtonAtIndex(i)->GetImage(views::Button::STATE_NORMAL);
EXPECT_FALSE(image.isNull()) << i;
}
}
// Verifies that the bubble contains as many rows as |app_info_| with one
// exception, if the Chrome package is present on the input list it won't be
// shown to the user on the picker UI, so there could be a difference
// represented by |chrome_package_repetitions|.
TEST_F(IntentPickerBubbleViewListTest, LabelsPtrVectorSize) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
size_t size = app_info().size();
EXPECT_EQ(size, GetScrollViewSize());
}
// Verifies that the first item is activated by default when creating a new
// bubble.
TEST_F(IntentPickerBubbleViewListTest, VerifyStartingInkDrop) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
size_t size = GetScrollViewSize();
EXPECT_EQ(GetInkDropState(0), views::InkDropState::ACTIVATED);
for (size_t i = 1; i < size; ++i) {
EXPECT_EQ(GetInkDropState(i), views::InkDropState::HIDDEN);
}
}
// Press each button at a time and make sure it goes to ACTIVATED state,
// followed by HIDDEN state after selecting other button.
TEST_F(IntentPickerBubbleViewListTest, InkDropStateTransition) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
size_t size = GetScrollViewSize();
for (size_t i = 0; i < size; ++i) {
ClickApp((i + 1) % size);
EXPECT_EQ(GetInkDropState(i), views::InkDropState::HIDDEN);
EXPECT_EQ(GetInkDropState((i + 1) % size), views::InkDropState::ACTIVATED);
}
}
// Arbitrary press a button twice, check that the InkDropState remains the same.
TEST_F(IntentPickerBubbleViewListTest, PressButtonTwice) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/true, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
EXPECT_EQ(GetInkDropState(1), views::InkDropState::HIDDEN);
ClickApp(1);
EXPECT_EQ(GetInkDropState(1), views::InkDropState::ACTIVATED);
// Move mouse to prevent the mouse events being interpreted as a double-click.
event_generator().MoveMouseBy(10, 0);
event_generator().ClickLeftButton();
EXPECT_EQ(GetInkDropState(1), views::InkDropState::ACTIVATED);
}
// Check that a non nullptr WebContents() has been created and observed.
TEST_F(IntentPickerBubbleViewListTest, WebContentsTiedToBubble) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
EXPECT_TRUE(bubble()->web_contents());
bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
EXPECT_TRUE(bubble()->web_contents());
}
// Check that that the correct window title is shown.
TEST_F(IntentPickerBubbleViewListTest, WindowTitle) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_BUBBLE_VIEW_OPEN_WITH),
bubble()->GetWindowTitle());
bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kClickToCall,
/*initiating_origin=*/std::nullopt);
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_TITLE_LABEL),
bubble()->GetWindowTitle());
}
// Check that that the correct button labels are used.
TEST_F(IntentPickerBubbleViewListTest, ButtonLabels) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
EXPECT_EQ(l10n_util::GetStringUTF16(IDS_INTENT_PICKER_BUBBLE_VIEW_OPEN),
bubble()->GetDialogButtonLabel(ui::mojom::DialogButton::kOk));
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_INTENT_PICKER_BUBBLE_VIEW_STAY_IN_CHROME),
bubble()->GetDialogButtonLabel(ui::mojom::DialogButton::kCancel));
bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kClickToCall,
/*initiating_origin=*/std::nullopt);
EXPECT_EQ(l10n_util::GetStringUTF16(
IDS_BROWSER_SHARING_CLICK_TO_CALL_DIALOG_CALL_BUTTON_LABEL),
bubble()->GetDialogButtonLabel(ui::mojom::DialogButton::kOk));
EXPECT_EQ(
l10n_util::GetStringUTF16(IDS_INTENT_PICKER_BUBBLE_VIEW_STAY_IN_CHROME),
bubble()->GetDialogButtonLabel(ui::mojom::DialogButton::kCancel));
}
TEST_F(IntentPickerBubbleViewListTest, InitiatingOriginView) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
const int children_without_origin = bubble()->children().size();
bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
url::Origin::Create(GURL("https://example.com")));
const int children_with_origin = bubble()->children().size();
EXPECT_EQ(children_without_origin + 1, children_with_origin);
bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
url::Origin::Create(GURL("http://www.google.com")));
const int children_with_same_origin = bubble()->children().size();
EXPECT_EQ(children_without_origin, children_with_same_origin);
}
#endif // !BUILDFLAG(IS_CHROMEOS)
class IntentPickerBubbleViewLayoutTest
: public IntentPickerBubbleViewTest,
public ::testing::WithParamInterface<
apps::test::LinkCapturingFeatureVersion> {
public:
IntentPickerBubbleViewLayoutTest() {
feature_list_.InitWithFeaturesAndParameters(
apps::test::GetFeaturesToEnableLinkCapturingUX(GetParam()),
/*disabled_features=*/{});
}
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_P(IntentPickerBubbleViewLayoutTest, RememberCheckbox) {
AddApp(apps::PickerEntryType::kDevice, "device_id", "Android Phone");
AddApp(apps::PickerEntryType::kWeb, "web_app_id", "Web App");
AddApp(apps::PickerEntryType::kArc, "arc_app_id", "Arc App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
auto* checkbox = views::AsViewClass<views::Checkbox>(
bubble()->GetViewByID(IntentPickerBubbleView::ViewId::kRememberCheckbox));
// kDevice entries should not allow persistence.
ClickApp(0);
ASSERT_FALSE(checkbox->GetEnabled());
// kWeb entries should allow persistence on CrOS. The checkbox does not pop up
// on non-ChromeOS platforms, and persistence results in a no-op behavior.
ClickApp(1);
ASSERT_TRUE(checkbox->GetEnabled());
// Other app types can be persisted.
ClickApp(2);
ASSERT_TRUE(checkbox->GetEnabled());
}
TEST_P(IntentPickerBubbleViewLayoutTest, AcceptDialog) {
AddApp(apps::PickerEntryType::kWeb, "web_app_id_1", "Web App");
AddApp(apps::PickerEntryType::kWeb, "web_app_id_2", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
ClickApp(1);
bubble()->AcceptDialog();
EXPECT_EQ(last_selected_launch_name(), "web_app_id_2");
EXPECT_FALSE(last_selection_should_persist());
EXPECT_EQ(last_close_reason(), apps::IntentPickerCloseReason::OPEN_APP);
}
TEST_P(IntentPickerBubbleViewLayoutTest, AcceptDialogWithRememberSelection) {
AddApp(apps::PickerEntryType::kArc, "arc_app_id", "ARC App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
ClickApp(0);
auto* checkbox = views::AsViewClass<views::Checkbox>(
bubble()->GetViewByID(IntentPickerBubbleView::ViewId::kRememberCheckbox));
checkbox->SetChecked(true);
bubble()->AcceptDialog();
EXPECT_EQ(last_selected_launch_name(), "arc_app_id");
EXPECT_TRUE(last_selection_should_persist());
EXPECT_EQ(last_close_reason(), apps::IntentPickerCloseReason::OPEN_APP);
}
TEST_P(IntentPickerBubbleViewLayoutTest, CancelDialog) {
AddApp(apps::PickerEntryType::kWeb, "web_app_id_1", "Web App");
AddApp(apps::PickerEntryType::kWeb, "web_app_id_2", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/true,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
ClickApp(1);
bubble()->CancelDialog();
EXPECT_EQ(last_selected_launch_name(), apps_util::kUseBrowserForLink);
EXPECT_FALSE(last_selection_should_persist());
EXPECT_EQ(last_close_reason(), apps::IntentPickerCloseReason::STAY_IN_CHROME);
}
TEST_P(IntentPickerBubbleViewLayoutTest, CloseDialog) {
AddApp(apps::PickerEntryType::kWeb, "web_app_id_1", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
bubble()->GetWidget()->CloseWithReason(
views::Widget::ClosedReason::kLostFocus);
ASSERT_EQ(last_close_reason(),
apps::IntentPickerCloseReason::DIALOG_DEACTIVATED);
}
// TODO(crbug.com/40843230): Fix flakiness on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_KeyboardNavigation DISABLED_KeyboardNavigation
#else
#define MAYBE_KeyboardNavigation KeyboardNavigation
#endif
TEST_P(IntentPickerBubbleViewLayoutTest, MAYBE_KeyboardNavigation) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
ClickApp(0);
GetButtonAtIndex(0)->RequestFocus();
event_generator().PressAndReleaseKey(ui::VKEY_DOWN);
EXPECT_EQ(bubble()->GetSelectedIndex(), 1u);
event_generator().PressAndReleaseKey(ui::VKEY_LEFT);
EXPECT_EQ(bubble()->GetSelectedIndex(), 0u);
// Pressing up/left from the first item should wrap around to the last item.
event_generator().PressAndReleaseKey(ui::VKEY_UP);
EXPECT_EQ(bubble()->GetSelectedIndex(),
bubble()->app_info_for_testing().size() - 1);
// Pressing down/right from the last item should wrap around to the first
// item.
event_generator().PressAndReleaseKey(ui::VKEY_RIGHT);
EXPECT_EQ(bubble()->GetSelectedIndex(), 0u);
}
TEST_P(IntentPickerBubbleViewLayoutTest, DoubleClickToAccept) {
AddApp(apps::PickerEntryType::kWeb, "web_app_id", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
views::test::ButtonTestApi button(GetButtonAtIndex(0));
button.NotifyClick(ui::MouseEvent(ui::EventType::kMousePressed, gfx::PointF(),
gfx::PointF(), ui::EventTimeForNow(),
ui::EF_NONE, ui::EF_NONE));
button.NotifyClick(ui::MouseEvent(ui::EventType::kMousePressed, gfx::PointF(),
gfx::PointF(), ui::EventTimeForNow(),
ui::EF_IS_DOUBLE_CLICK, ui::EF_NONE));
EXPECT_EQ(last_selected_launch_name(), "web_app_id");
EXPECT_EQ(last_close_reason(), apps::IntentPickerCloseReason::OPEN_APP);
}
INSTANTIATE_TEST_SUITE_P(
All,
IntentPickerBubbleViewLayoutTest,
#if BUILDFLAG(IS_CHROMEOS)
testing::Values(apps::test::LinkCapturingFeatureVersion::kV1DefaultOff,
apps::test::LinkCapturingFeatureVersion::kV2DefaultOff)
#else
testing::Values(apps::test::LinkCapturingFeatureVersion::kV2DefaultOff,
apps::test::LinkCapturingFeatureVersion::kV2DefaultOn)
#endif // BUILDFLAG(IS_CHROMEOS)
,
apps::test::LinkCapturingVersionToString);
class IntentPickerBubbleViewGridLayoutTest
: public IntentPickerBubbleViewTest,
public testing::WithParamInterface<
apps::test::LinkCapturingFeatureVersion> {
public:
IntentPickerBubbleViewGridLayoutTest() {
feature_list_.InitWithFeaturesAndParameters(
apps::test::GetFeaturesToEnableLinkCapturingUX(GetParam()), {});
}
private:
base::test::ScopedFeatureList feature_list_;
};
TEST_P(IntentPickerBubbleViewGridLayoutTest, DefaultSelectionOneApp) {
AddApp(apps::PickerEntryType::kWeb, "web_app_id", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
ASSERT_EQ(bubble()->GetSelectedIndex(), 0u);
}
TEST_P(IntentPickerBubbleViewGridLayoutTest, AccessibilityCheckedStateChange) {
ui::AXNodeData data;
AddApp(apps::PickerEntryType::kWeb, "web_app_id", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
// In case of 1 app, 1st view will be selected
bubble()->SelectDefaultItem();
auto* view = GetButtonAtIndex(0);
view->GetViewAccessibility().GetAccessibleNodeData(&data);
EXPECT_EQ(data.GetCheckedState(), ax::mojom::CheckedState::kTrue);
AddApp(apps::PickerEntryType::kWeb, "web_app_id", "Web App");
bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
data = ui::AXNodeData();
view = GetButtonAtIndex(1);
view->GetViewAccessibility().GetAccessibleNodeData(&data);
EXPECT_EQ(data.GetCheckedState(), ax::mojom::CheckedState::kFalse);
}
TEST_P(IntentPickerBubbleViewGridLayoutTest, DefaultSelectionTwoApps) {
AddApp(apps::PickerEntryType::kWeb, "web_app_id_1", "Web App");
AddApp(apps::PickerEntryType::kWeb, "web_app_id_2", "Web App");
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
ASSERT_FALSE(bubble()->GetSelectedIndex().has_value());
}
// TODO(crbug.com/40843230): Fix flakiness on Windows.
#if BUILDFLAG(IS_WIN)
#define MAYBE_OpenWithReturnKey DISABLED_OpenWithReturnKey
#else
#define MAYBE_OpenWithReturnKey OpenWithReturnKey
#endif
TEST_P(IntentPickerBubbleViewGridLayoutTest, MAYBE_OpenWithReturnKey) {
AddDefaultApps();
auto bubble_widget =
CreateBubbleView(/*use_icons=*/false, /*show_stay_in_chrome=*/false,
BubbleType::kLinkCapturing,
/*initiating_origin=*/std::nullopt);
GetButtonAtIndex(0)->RequestFocus();
EXPECT_TRUE(GetButtonAtIndex(0)->HasFocus());
event_generator().PressKey(ui::VKEY_RETURN, ui::EF_NONE);
EXPECT_EQ(last_close_reason(), apps::IntentPickerCloseReason::OPEN_APP);
}
INSTANTIATE_TEST_SUITE_P(
,
IntentPickerBubbleViewGridLayoutTest,
#if BUILDFLAG(IS_CHROMEOS)
// BUG(370548596): Enable test coverage for kV2DefaultOff once we figure
// out the test failures (listed in the bug).
testing::Values(apps::test::LinkCapturingFeatureVersion::kV1DefaultOff)
#else
testing::Values(apps::test::LinkCapturingFeatureVersion::kV2DefaultOff,
apps::test::LinkCapturingFeatureVersion::kV2DefaultOn)
#endif // BUILDFLAG(IS_CHROMEOS)
,
apps::test::LinkCapturingVersionToString);