| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "chrome/browser/chromeos/arc/intent_helper/arc_external_protocol_dialog.h" |
| |
| #include "base/macros.h" |
| #include "base/time/time.h" |
| #include "chrome/browser/chromeos/arc/arc_web_contents_data.h" |
| #include "chrome/browser/sharing/sharing_device_registration.h" |
| #include "chrome/browser/sharing/sharing_fcm_handler.h" |
| #include "chrome/browser/sharing/sharing_fcm_sender.h" |
| #include "chrome/browser/sharing/sharing_service.h" |
| #include "chrome/browser/sharing/sharing_service_factory.h" |
| #include "chrome/browser/sharing/sharing_sync_preference.h" |
| #include "chrome/browser/sharing/vapid_key_manager.h" |
| #include "chrome/test/base/browser_with_test_window_test.h" |
| #include "components/arc/intent_helper/arc_intent_helper_bridge.h" |
| #include "content/public/browser/render_process_host.h" |
| #include "content/public/browser/render_view_host.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "url/gurl.h" |
| |
| namespace arc { |
| |
| namespace { |
| |
| // Helper class to run tests that need a dummy WebContents. |
| class ArcExternalProtocolDialogTestUtils : public BrowserWithTestWindowTest { |
| public: |
| ArcExternalProtocolDialogTestUtils() = default; |
| |
| protected: |
| void CreateTab(bool started_from_arc) { |
| AddTab(browser(), GURL("http://www.tests.com")); |
| |
| web_contents_ = browser()->tab_strip_model()->GetWebContentsAt(0); |
| if (started_from_arc) { |
| web_contents_->SetUserData(&arc::ArcWebContentsData::kArcTransitionFlag, |
| std::make_unique<arc::ArcWebContentsData>()); |
| } |
| } |
| |
| bool WasTabStartedFromArc() { |
| return GetAndResetSafeToRedirectToArcWithoutUserConfirmationFlagForTesting( |
| web_contents_); |
| } |
| |
| content::WebContents* web_contents() { return web_contents_; } |
| |
| private: |
| // Keep only one |WebContents| at a time. |
| content::WebContents* web_contents_; |
| |
| DISALLOW_COPY_AND_ASSIGN(ArcExternalProtocolDialogTestUtils); |
| }; |
| |
| const char* kChromePackageName = |
| ArcIntentHelperBridge::kArcIntentHelperPackageName; |
| |
| // Creates a dummy GurlAndActivityInfo object. |
| GurlAndActivityInfo CreateEmptyGurlAndActivityInfo() { |
| return std::make_pair(GURL(), ArcIntentHelperBridge::ActivityName( |
| /*package_name=*/std::string(), |
| /*activity_name=*/std::string())); |
| } |
| |
| // Creates and returns a new IntentHandlerInfo object. |
| mojom::IntentHandlerInfoPtr Create(const std::string& name, |
| const std::string& package_name, |
| const std::string& activity_name, |
| bool is_preferred, |
| const GURL& fallback_url) { |
| mojom::IntentHandlerInfoPtr ptr = mojom::IntentHandlerInfo::New(); |
| ptr->name = name; |
| ptr->package_name = package_name; |
| ptr->activity_name = activity_name; |
| ptr->is_preferred = is_preferred; |
| if (!fallback_url.is_empty()) |
| ptr->fallback_url = fallback_url.spec(); |
| return ptr; |
| } |
| |
| // TODO(crbug.com/1011364): Extract this into a common mock file. |
| class MockSharingService : public SharingService { |
| public: |
| explicit MockSharingService() |
| : SharingService( |
| /*sync_prefs=*/nullptr, |
| /*vapid_key_manager=*/nullptr, |
| std::make_unique<SharingDeviceRegistration>( |
| /*pref_service=*/nullptr, |
| /*sync_preference=*/nullptr, |
| /*instance_id_driver=*/nullptr, |
| /*vapid_key_manager=*/nullptr), |
| /*fcm_sender=*/nullptr, |
| std::make_unique<SharingFCMHandler>( |
| /*gcm_driver=*/nullptr, |
| /*sharing_fcm_sender=*/nullptr, |
| /*sync_preference=*/nullptr), |
| /*gcm_driver=*/nullptr, |
| /*device_info_tracker=*/nullptr, |
| /*local_device_info_provider=*/nullptr, |
| /*sync_service=*/nullptr, |
| /*notification_display_service=*/nullptr) {} |
| |
| ~MockSharingService() override = default; |
| |
| MOCK_METHOD4(SendMessageToDevice, |
| void(const std::string&, |
| base::TimeDelta, |
| chrome_browser_sharing::SharingMessage, |
| SendMessageCallback)); |
| }; |
| |
| } // namespace |
| |
| // Tests that when no apps are returned from ARC, GetAction returns |
| // SHOW_CHROME_OS_DIALOG. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithNoApp) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| |
| // Marking this as safe to bypass or not makes no difference since there are |
| // no handlers. |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ(GetActionResult::SHOW_CHROME_OS_DIALOG, |
| GetActionForTesting(GURL("external-protocol:foo"), handlers, |
| handlers.size(), &url_and_activity_name, |
| &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ(GetActionResult::SHOW_CHROME_OS_DIALOG, |
| GetActionForTesting(GURL("external-protocol:foo"), handlers, |
| handlers.size(), &url_and_activity_name, |
| &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that when one app is passed to GetAction but the user hasn't selected |
| // it and |in_out_safe_to_bypass_ui| is true, the function returns |
| // HANDLE_URL_IN_ARC. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithOneAppBypassesIntentPicker) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("package", "com.google.package.name", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(GURL("external-protocol:foo"), handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that when one app is passed to GetAction but the user hasn't selected |
| // it and |in_out_safe_to_bypass_ui| is false, the function returns |
| // ASK_USER. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithOneAppDoesntBypassIntentPicker) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("package", "com.google.package.name", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::ASK_USER, |
| GetActionForTesting(GURL("external-protocol:foo"), handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that when 2+ apps are passed to GetAction but the user hasn't selected |
| // any the function returns ASK_USER, independently of whether or not is marked |
| // as safe to bypass the ui. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoAppWontBypassIntentPicker) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("package", "com.google.package.name", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, /*fallback_url=*/GURL())); |
| handlers.push_back(Create("package2", "com.google.package.name2", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::ASK_USER, |
| GetActionForTesting(GURL("external-protocol:foo"), handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::ASK_USER, |
| GetActionForTesting(GURL("external-protocol:foo"), handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that when one preferred app is passed to GetAction, the function |
| // returns HANDLE_URL_IN_ARC even if the user hasn't selected the app, safe to |
| // bypass the UI is not relevant for this context. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithOnePreferredApp) { |
| const GURL external_url("external-protocol:foo"); |
| const std::string package_name("com.google.package.name"); |
| const std::string activity_name("com.google.activity"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("package", package_name, activity_name, |
| /*is_preferred=*/true, |
| /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(external_url, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(external_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(external_url, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| // The flag was flipped since we have a preferred app. |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| EXPECT_EQ(external_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| } |
| |
| // Tests that when one app is passed to GetAction, the user has already selected |
| // it, the function returns HANDLE_URL_IN_ARC. Since the user already selected |
| // safe to bypass ui it's always false. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithOneAppSelected) { |
| const GURL external_url("external-protocol:foo"); |
| const std::string package_name("com.google.package.name"); |
| const std::string activity_name("fake_activity_name"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("package", package_name, activity_name, |
| /*is_preferred=*/false, |
| /*fallback_url=*/GURL())); |
| |
| constexpr size_t kSelection = 0; |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(external_url, handlers, kSelection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(external_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(external_url, handlers, kSelection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(external_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same as TestGetActionWithOnePreferredApp but with two apps. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithOnePreferredAppAndOneOther) { |
| const GURL external_url("external-protocol:foo"); |
| const std::string package_name("com.google.package2.name"); |
| const std::string activity_name("fake_activity_name2"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("package", "com.google.package.name", |
| "fake_activity_name", |
| /*is_preferred=*/false, /*fallback_url=*/GURL())); |
| handlers.push_back(Create("package2", package_name, activity_name, |
| /*is_preferred=*/true, |
| /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| // For cases with 2+ apps it doesn't matter whether it was marked as safe to |
| // bypass or not, it will only check for user's preferrences. |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(external_url, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(external_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| // It is expected to correct the flag to true, regardless of the initial |
| // value, since there is a preferred app. |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(external_url, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(external_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that HANDLE_URL_IN_ARC is returned for geo: URL. The URL is special in |
| // that intent_helper (i.e. the Chrome proxy) can handle it but Chrome cannot. |
| // We have to send such a URL to intent_helper to let the helper rewrite the |
| // URL to https://maps.google.com/?latlon=xxx which Chrome can handle. Since the |
| // url needs to be fixed in ARC first, safe to bypass doesn't modify this |
| // behavior. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithGeoUrl) { |
| const GURL geo_url("geo:37.7749,-122.4194"); |
| |
| const std::string activity_name("chrome_activity_name"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Chrome", kChromePackageName, activity_name, |
| /*is_preferred=*/true, |
| /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(geo_url, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(geo_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| // Value will be corrected as in previous scenarios. |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that OPEN_URL_IN_CHROME is returned when a handler with a fallback http |
| // URL and kChromePackageName is passed to GetAction, even if the handler is not |
| // a preferred one. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithOneFallbackUrl) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=http://zxing.org;end"); |
| const GURL fallback_url("http://zxing.org"); |
| const std::string activity_name("fake_activity_name"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Chrome", kChromePackageName, activity_name, |
| /*is_preferred=*/false, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| |
| // Since the navigation is intended to stay in Chrome the UI is bypassed. |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::OPEN_URL_IN_CHROME, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::OPEN_URL_IN_CHROME, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same with https and is_preferred == true. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithOnePreferredFallbackUrl) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=https://zxing.org;end"); |
| const GURL fallback_url("https://zxing.org"); |
| const std::string activity_name("fake_activity_name"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Chrome", kChromePackageName, activity_name, |
| /*is_preferred=*/true, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| |
| // Safe to bypass should be marked as true in the end, since the |
| // OPEN_URL_IN_CHROME actually bypasses the UI, regardless of the flag. |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::OPEN_URL_IN_CHROME, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| |
| // Changing the flag will not modify the outcome. |
| in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::OPEN_URL_IN_CHROME, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that ASK_USER is returned when two handlers with fallback URLs are |
| // passed to GetAction. This may happen when the user has installed a 3rd party |
| // browser app, and then clicks a intent: URI with a http fallback. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithTwoFallbackUrls) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=http://zxing.org;end"); |
| const GURL fallback_url("http://zxing.org"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other browser", "com.other.browser", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Chrome", kChromePackageName, |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::ASK_USER, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same but set Chrome as a preferred app. In this case, ASK_USER |
| // shouldn't be returned. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoFallbackUrlsChromePreferred) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=http://zxing.org;end"); |
| const GURL fallback_url("http://zxing.org"); |
| const std::string chrome_activity("chrome_activity"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other browser", "com.other.browser", |
| "fake_activity", |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Chrome", kChromePackageName, chrome_activity, |
| /*is_preferred=*/true, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::OPEN_URL_IN_CHROME, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(chrome_activity, url_and_activity_name.second.activity_name); |
| // Remember that this flag gets fixed under the presence of a preferred app. |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same but set "other browser" as a preferred app. In this case, |
| // ASK_USER shouldn't be returned either. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoFallbackUrlsOtherBrowserPreferred) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=http://zxing.org;end"); |
| const GURL fallback_url("http://zxing.org"); |
| const std::string package_name = "com.other.browser"; |
| const std::string chrome_activity_name("chrome_activity_name"); |
| const std::string other_activity_name("other_activity_name"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other browser", package_name, other_activity_name, |
| /*is_preferred=*/true, fallback_url)); |
| handlers.push_back(Create("Chrome", kChromePackageName, chrome_activity_name, |
| /*is_preferred=*/false, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(other_activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same but set Chrome as a user-selected app. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoFallbackUrlsChromeSelected) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=http://zxing.org;end"); |
| const GURL fallback_url("http://zxing.org"); |
| const std::string chrome_activity_name("chrome_activity"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other browser", "com.other.browser", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Chrome", kChromePackageName, chrome_activity_name, |
| /*is_preferred=*/false, fallback_url)); |
| |
| constexpr size_t kSelection = 1; // Chrome |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::OPEN_URL_IN_CHROME, |
| GetActionForTesting(intent_url_with_fallback, handlers, kSelection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(chrome_activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same but set "other browser" as a preferred app. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoFallbackUrlsOtherBrowserSelected) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=http://zxing.org;end"); |
| const GURL fallback_url("http://zxing.org"); |
| const std::string package_name = "com.other.browser"; |
| const std::string other_activity_name("other_activity_name"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other browser", package_name, other_activity_name, |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Chrome", kChromePackageName, "chrome_activity", |
| /*is_preferred=*/false, fallback_url)); |
| |
| constexpr size_t kSelection = 0; // the other browser |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| // Already selected app index, output should be corrected to false. |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, kSelection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(other_activity_name, url_and_activity_name.second.activity_name); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that HANDLE_URL_IN_ARC is returned when a handler with a fallback |
| // market: URL is passed to GetAction iff the flag to bypass the UI is set, |
| // otherwise UI will prompt to ASK_USER. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithOneMarketFallbackUrl) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Play Store", "com.google.play.store", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::ASK_USER, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same but with is_preferred == true. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithOnePreferredMarketFallbackUrl) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| const std::string play_store_package_name = "com.google.play.store"; |
| const std::string play_store_activity("play_store_activity"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Play Store", play_store_package_name, |
| play_store_activity, |
| /*is_preferred=*/true, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(play_store_package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(play_store_activity, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| |
| in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(play_store_package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(play_store_activity, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same but with an app_seleteced_index. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithOneSelectedMarketFallbackUrl) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| const std::string play_store_package_name = "com.google.play.store"; |
| const std::string play_store_activity("play_store_activity"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Play Store", play_store_package_name, |
| play_store_activity, |
| /*is_preferred=*/false, fallback_url)); |
| |
| constexpr size_t kSelection = 0; |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| // App already selected, it doesn't really makes sense to call GetAction with |
| // |in_out_safe_to_bypass_ui| set to true here. |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, kSelection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(play_store_package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(play_store_activity, url_and_activity_name.second.activity_name); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that HANDLE_URL_IN_ARC is returned when a handler with a fallback |
| // market: URL is passed to GetAction. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithOneMarketFallbackUrlBypassIntentPicker) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Play Store", "com.google.play.store", |
| "play_store_activity", /*is_preferred=*/false, |
| fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = true; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that ASK_USER is returned when two handlers with fallback market: URLs |
| // are passed to GetAction. Unlike the two browsers case, this rarely happens on |
| // the user's device, though. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithTwoMarketFallbackUrls) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Play Store", "com.google.play.store", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Other Store app", "com.other.play.store", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::ASK_USER, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_FALSE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same, but make the second handler a preferred one. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoMarketFallbackUrlsOnePreferred) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| const std::string play_store_package_name = "com.google.play.store"; |
| const std::string play_store_activity("play.store.act1"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other Store app", "com.other.play.store", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Play Store", play_store_package_name, |
| play_store_activity, |
| /*is_preferred=*/true, fallback_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(play_store_package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(play_store_activity, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests the same, but make the second handler a selected one. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithTwoMarketFallbackUrlsOneSelected) { |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;end"); |
| const GURL fallback_url("market://details?id=com.google.abc"); |
| const std::string play_store_package_name = "com.google.play.store"; |
| const std::string play_store_activity("play.store.act1"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Other Store app", "com.other.play.store", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, fallback_url)); |
| handlers.push_back(Create("Play Store", play_store_package_name, |
| play_store_activity, |
| /*is_preferred=*/false, fallback_url)); |
| |
| const size_t kSelection = 1; // Play Store |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| // After selection doesn't really makes sense to check this value. |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, kSelection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(fallback_url, url_and_activity_name.first); |
| EXPECT_EQ(play_store_package_name, url_and_activity_name.second.package_name); |
| EXPECT_EQ(play_store_activity, url_and_activity_name.second.activity_name); |
| } |
| |
| // Tests the case where geo: URL is returned as a fallback. This should never |
| // happen because intent_helper ignores such a fallback, but just in case. |
| // GetAction shouldn't crash at least. |
| TEST(ArcExternalProtocolDialogTest, TestGetActionWithGeoUrlAsFallback) { |
| // Note: geo: as a browser fallback is banned in the production code. |
| const GURL intent_url_with_fallback( |
| "intent://scan/#Intent;scheme=abc;package=com.google.abc;" |
| "S.browser_fallback_url=geo:37.7749,-122.4194;end"); |
| const GURL geo_url("geo:37.7749,-122.4194"); |
| const std::string chrome_activity("chrome.activity"); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("Chrome", kChromePackageName, chrome_activity, |
| /*is_preferred=*/true, geo_url)); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| // GetAction shouldn't return OPEN_URL_IN_CHROME because Chrome doesn't |
| // directly support geo:. |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(intent_url_with_fallback, handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_EQ(geo_url, url_and_activity_name.first); |
| EXPECT_EQ(kChromePackageName, url_and_activity_name.second.package_name); |
| EXPECT_EQ(chrome_activity, url_and_activity_name.second.activity_name); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Test that GetUrlToNavigateOnDeactivate returns an empty GURL when |handlers| |
| // is empty. |
| TEST(ArcExternalProtocolDialogTest, TestGetUrlToNavigateOnDeactivateEmpty) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| EXPECT_EQ(GURL(), GetUrlToNavigateOnDeactivateForTesting(handlers)); |
| } |
| |
| // Test that GetUrlToNavigateOnDeactivate returns an empty GURL when |handlers| |
| // only contains a (non-Chrome) app. |
| TEST(ArcExternalProtocolDialogTest, TestGetUrlToNavigateOnDeactivateAppOnly) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| // On production, when |handlers| only contains app(s), the fallback field is |
| // empty, but to make the test more reliable, use non-empty fallback URL. |
| handlers.push_back(Create("App", "app.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("http://www"))); |
| EXPECT_EQ(GURL(), GetUrlToNavigateOnDeactivateForTesting(handlers)); |
| } |
| |
| // Test that GetUrlToNavigateOnDeactivate returns an empty GURL when |handlers| |
| // only contains (non-Chrome) apps. |
| TEST(ArcExternalProtocolDialogTest, TestGetUrlToNavigateOnDeactivateAppsOnly) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| // On production, when |handlers| only contains app(s), the fallback field is |
| // empty, but to make the test more reliable, use non-empty fallback URL. |
| handlers.push_back(Create("App1", "app1.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("http://www"))); |
| handlers.push_back(Create("App2", "app2.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("http://www"))); |
| EXPECT_EQ(GURL(), GetUrlToNavigateOnDeactivateForTesting(handlers)); |
| } |
| |
| // Test that GetUrlToNavigateOnDeactivate returns an empty GURL when |handlers| |
| // contains Chrome, but it's not for http(s). |
| TEST(ArcExternalProtocolDialogTest, TestGetUrlToNavigateOnDeactivateGeoUrl) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back( |
| Create("Chrome", kChromePackageName, /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("geo:37.4220,-122.0840"))); |
| EXPECT_EQ(GURL(), GetUrlToNavigateOnDeactivateForTesting(handlers)); |
| } |
| |
| // Test that GetUrlToNavigateOnDeactivate returns non-empty GURL when |handlers| |
| // contains Chrome and an app. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetUrlToNavigateOnDeactivateChromeAndApp) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| // On production, all handlers have the same fallback URL, but to make sure |
| // that "Chrome" is actually selected by the function, use different URLs. |
| handlers.push_back(Create("A browser app", "browser.app.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("http://www1/"))); |
| handlers.push_back(Create("Chrome", kChromePackageName, |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("http://www2/"))); |
| handlers.push_back(Create("Yet another browser app", |
| "yet.another.browser.app.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("http://www3/"))); |
| |
| EXPECT_EQ(GURL("http://www2/"), |
| GetUrlToNavigateOnDeactivateForTesting(handlers)); |
| } |
| |
| // Does the same with https, just in case. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetUrlToNavigateOnDeactivateChromeAndAppHttps) { |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("A browser app", "browser.app.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www1/"))); |
| handlers.push_back(Create("Chrome", kChromePackageName, |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www2/"))); |
| handlers.push_back(Create("Yet another browser app", |
| "yet.another.browser.app.package", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www3/"))); |
| |
| EXPECT_EQ(GURL("https://www2/"), |
| GetUrlToNavigateOnDeactivateForTesting(handlers)); |
| } |
| |
| // Checks that the flag is correctly attached to the current tab. |
| TEST_F(ArcExternalProtocolDialogTestUtils, TestTabIsStartedFromArc) { |
| CreateTab(/*started_from_arc=*/true); |
| |
| EXPECT_TRUE(WasTabStartedFromArc()); |
| } |
| |
| // Tests the same as the previous, just for when the data is not attached to the |
| // tab. |
| TEST_F(ArcExternalProtocolDialogTestUtils, TestTabIsNotStartedFromArc) { |
| CreateTab(/*started_from_arc=*/false); |
| |
| EXPECT_FALSE(WasTabStartedFromArc()); |
| } |
| |
| // Tests that IsChromeAnAppCandidate works as intended. |
| TEST(ArcExternalProtocolDialogTest, TestIsChromeAnAppCandidate) { |
| // First 3 cases are valid, just switching the position of Chrome. |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back( |
| Create("fake app 1", "fake.app.package", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.fo.com"))); |
| handlers.push_back( |
| Create("fake app 2", "fake.app.package2", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.bar.com"))); |
| handlers.push_back(Create("Chrome", kChromePackageName, |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www/"))); |
| EXPECT_TRUE(IsChromeAnAppCandidateForTesting(handlers)); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers2; |
| handlers2.push_back( |
| Create("fake app 1", "fake.app.package", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.fo.com"))); |
| handlers2.push_back(Create("Chrome", kChromePackageName, |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www/"))); |
| handlers2.push_back( |
| Create("fake app 2", "fake.app.package2", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.bar.com"))); |
| EXPECT_TRUE(IsChromeAnAppCandidateForTesting(handlers2)); |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers3; |
| handlers3.push_back(Create("Chrome", kChromePackageName, |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www/"))); |
| handlers3.push_back( |
| Create("fake app 1", "fake.app.package", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.fo.com"))); |
| handlers3.push_back( |
| Create("fake app 2", "fake.app.package2", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.bar.com"))); |
| EXPECT_TRUE(IsChromeAnAppCandidateForTesting(handlers3)); |
| |
| // Only non-Chrome apps. |
| std::vector<mojom::IntentHandlerInfoPtr> handlers4; |
| handlers4.push_back( |
| Create("fake app 1", "fake.app.package", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.fo.com"))); |
| handlers4.push_back( |
| Create("fake app 2", "fake.app.package2", /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www.bar.com"))); |
| handlers4.push_back(Create("fake app 3", "fake.app.package3", |
| /*activity_name=*/std::string(), |
| /*is_preferred=*/false, GURL("https://www/"))); |
| EXPECT_FALSE(IsChromeAnAppCandidateForTesting(handlers4)); |
| |
| // Empty vector case. |
| EXPECT_FALSE(IsChromeAnAppCandidateForTesting( |
| std::vector<mojom::IntentHandlerInfoPtr>())); |
| } |
| |
| // Tests that when one app is passed to GetAction and it's for ARC IME, the |
| // picker won't be triggered. |
| TEST(ArcExternalProtocolDialogTest, |
| TestGetActionWithArcImeSettingsActivityBypassesIntentPicker) { |
| constexpr char kPackageForOpeningArcImeSettingsPage[] = |
| "org.chromium.arc.applauncher"; |
| constexpr char kActivityForOpeningArcImeSettingsPage[] = |
| "org.chromium.arc.applauncher.InputMethodSettingsActivity"; |
| |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| handlers.push_back(Create("ARC IME settings", |
| kPackageForOpeningArcImeSettingsPage, |
| kActivityForOpeningArcImeSettingsPage, |
| /*is_preferred=*/false, /*fallback_url=*/GURL())); |
| |
| const size_t no_selection = handlers.size(); |
| GurlAndActivityInfo url_and_activity_name = CreateEmptyGurlAndActivityInfo(); |
| bool in_out_safe_to_bypass_ui = false; |
| EXPECT_EQ( |
| GetActionResult::HANDLE_URL_IN_ARC, |
| GetActionForTesting(GURL("intent:foo"), handlers, no_selection, |
| &url_and_activity_name, &in_out_safe_to_bypass_ui)); |
| EXPECT_TRUE(in_out_safe_to_bypass_ui); |
| } |
| |
| // Tests that clicking on a device calls through to SharingService. |
| TEST_F(ArcExternalProtocolDialogTestUtils, TestSelectDeviceForTelLink) { |
| std::string device_guid = "device_guid"; |
| |
| MockSharingService* sharing_service = static_cast<MockSharingService*>( |
| SharingServiceFactory::GetInstance()->SetTestingFactoryAndUse( |
| profile(), base::BindRepeating([](content::BrowserContext* context) { |
| return static_cast<std::unique_ptr<KeyedService>>( |
| std::make_unique<MockSharingService>()); |
| }))); |
| |
| EXPECT_CALL(*sharing_service, |
| SendMessageToDevice(testing::Eq(device_guid), testing::_, |
| testing::_, testing::_)); |
| |
| CreateTab(/*started_from_arc=*/false); |
| |
| content::RenderViewHost* rvh = web_contents()->GetRenderViewHost(); |
| std::vector<mojom::IntentHandlerInfoPtr> handlers; |
| std::vector<std::unique_ptr<syncer::DeviceInfo>> devices; |
| |
| devices.emplace_back(std::make_unique<syncer::DeviceInfo>( |
| device_guid, "device_name", "chrome_version", "user_agent", |
| sync_pb::SyncEnums_DeviceType_TYPE_PHONE, "device_id", |
| /*last_updated_timestamp=*/base::Time::Now(), |
| /*send_tab_to_self_receiving_enabled=*/false, |
| /*sharing_info=*/base::nullopt)); |
| |
| OnIntentPickerClosedForTesting( |
| rvh->GetProcess()->GetID(), rvh->GetRoutingID(), GURL("tel:0123456789"), |
| /*safe_to_bypass_ui=*/true, std::move(handlers), std::move(devices), |
| /*selected_app_package=*/device_guid, apps::PickerEntryType::kDevice, |
| apps::IntentPickerCloseReason::OPEN_APP, /*should_persist=*/false); |
| } |
| |
| } // namespace arc |