blob: 96d244a914a4157147a9e984b1437ae0673979c7 [file] [log] [blame]
// Copyright 2021 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/apps/app_service/publishers/arc_apps.h"
#include "ash/components/arc/mojom/intent_helper.mojom.h"
#include "ash/components/arc/session/arc_bridge_service.h"
#include "ash/components/arc/session/arc_service_manager.h"
#include "ash/components/arc/test/fake_app_instance.h"
#include "base/test/scoped_feature_list.h"
#include "chrome/browser/apps/app_service/app_service_proxy.h"
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/apps/app_service/app_service_test.h"
#include "chrome/browser/apps/app_service/publishers/arc_apps_factory.h"
#include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
#include "chrome/browser/ui/app_list/arc/arc_app_test.h"
#include "chrome/browser/web_applications/test/fake_web_app_provider.h"
#include "chrome/browser/web_applications/test/web_app_install_test_utils.h"
#include "chrome/common/chrome_features.h"
#include "chrome/test/base/testing_profile.h"
#include "components/arc/intent_helper/arc_intent_helper_bridge.h"
#include "components/arc/intent_helper/intent_constants.h"
#include "components/arc/intent_helper/intent_filter.h"
#include "components/arc/test/fake_intent_helper_instance.h"
#include "components/services/app_service/public/cpp/preferred_apps_list_handle.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
std::vector<arc::IntentFilter> CreateFilterList(
const std::string& package_name,
const std::vector<std::string>& authorities) {
std::vector<arc::IntentFilter::AuthorityEntry> filter_authorities;
for (const std::string& authority : authorities) {
filter_authorities.emplace_back(authority, 0);
}
std::vector<arc::IntentFilter::PatternMatcher> patterns;
patterns.emplace_back("/", arc::mojom::PatternType::PATTERN_PREFIX);
auto filter = arc::IntentFilter(package_name, {arc::kIntentActionView},
std::move(filter_authorities),
std::move(patterns), {"https"}, {});
std::vector<arc::IntentFilter> filters;
filters.push_back(std::move(filter));
return filters;
}
} // namespace
class ArcAppsPublisherTest : public testing::Test {
public:
void SetUp() override {
testing::Test::SetUp();
scoped_feature_list_.InitAndDisableFeature(
features::kDefaultLinkCapturingInBrowser);
// Do not destroy the ArcServiceManager during TearDown, so that Arc
// KeyedServices can be correctly destroyed during profile shutdown.
arc_test_.set_persist_service_manager(true);
// We will manually start ArcApps after setting up IntentHelper, this allows
// ArcApps to observe the correct IntentHelper during initialization.
arc_test_.set_start_app_service_publisher(false);
arc_test_.SetUp(profile());
intent_helper_ =
arc::ArcIntentHelperBridge::GetForBrowserContextForTesting(profile());
intent_helper_instance_ = std::make_unique<arc::FakeIntentHelperInstance>();
auto* arc_bridge_service =
arc_test_.arc_service_manager()->arc_bridge_service();
arc_bridge_service->intent_helper()->SetInstance(
intent_helper_instance_.get());
auto* const provider = web_app::FakeWebAppProvider::Get(&profile_);
provider->SkipAwaitingExtensionSystem();
web_app::test::AwaitStartWebAppProviderAndSubsystems(profile());
app_service_test_.SetUp(&profile_);
apps::ArcAppsFactory::GetForProfile(profile());
app_service_test_.FlushMojoCalls();
}
void TearDown() override { arc_test_.TearDown(); }
void FlushMojoCalls() { app_service_test_.FlushMojoCalls(); }
TestingProfile* profile() { return &profile_; }
arc::ArcIntentHelperBridge* intent_helper() { return intent_helper_; }
arc::FakeIntentHelperInstance* intent_helper_instance() {
return intent_helper_instance_.get();
}
ArcAppTest* arc_test() { return &arc_test_; }
apps::PreferredAppsListHandle& preferred_apps() {
return apps::AppServiceProxyFactory::GetForProfile(profile())
->PreferredApps();
}
private:
content::BrowserTaskEnvironment task_environment_;
base::test::ScopedFeatureList scoped_feature_list_;
ArcAppTest arc_test_;
TestingProfile profile_;
apps::AppServiceTest app_service_test_;
arc::ArcIntentHelperBridge* intent_helper_;
std::unique_ptr<arc::FakeIntentHelperInstance> intent_helper_instance_;
};
// Verifies that a call to set the supported links preference from ARC persists
// the setting in app service.
TEST_F(ArcAppsPublisherTest, SetSupportedLinksFromArc) {
constexpr char kTestAuthority[] = "www.example.com";
const auto& fake_apps = arc_test()->fake_apps();
std::string package_name = fake_apps[0].package_name;
std::string app_id = ArcAppListPrefs::GetAppId(fake_apps[0].package_name,
fake_apps[0].activity);
arc_test()->app_instance()->SendRefreshAppList(fake_apps);
// Update intent filters and supported links for the app, as if it was just
// installed.
intent_helper()->OnIntentFiltersUpdatedForPackage(
package_name, CreateFilterList(package_name, {kTestAuthority}));
std::vector<arc::mojom::SupportedLinksPtr> added_links;
added_links.emplace_back(base::in_place, package_name,
CreateFilterList(package_name, {kTestAuthority}));
intent_helper()->OnSupportedLinksChanged(
std::move(added_links), {},
arc::mojom::SupportedLinkChangeSource::kArcSystem);
FlushMojoCalls();
ASSERT_EQ(app_id, preferred_apps().FindPreferredAppForUrl(
GURL("https://www.example.com/foo")));
}
// Verifies that a call to set the supported links preference from App Service
// syncs the setting to ARC.
TEST_F(ArcAppsPublisherTest, SetSupportedLinksFromAppService) {
constexpr char kTestAuthority[] = "www.example.com";
const auto& fake_apps = arc_test()->fake_apps();
std::string package_name = fake_apps[0].package_name;
std::string app_id = ArcAppListPrefs::GetAppId(fake_apps[0].package_name,
fake_apps[0].activity);
arc_test()->app_instance()->SendRefreshAppList(fake_apps);
intent_helper()->OnIntentFiltersUpdatedForPackage(
package_name, CreateFilterList(package_name, {kTestAuthority}));
FlushMojoCalls();
apps::AppServiceProxyFactory::GetForProfile(profile())
->SetSupportedLinksPreference(app_id);
FlushMojoCalls();
ASSERT_TRUE(
intent_helper_instance()->verified_links().find(package_name)->second);
}
// Verifies that when the behavior to open links in the browser by default is
// enabled, Android apps are not set to handle links during first install.
TEST_F(ArcAppsPublisherTest, SetSupportedLinksDefaultBrowserBehavior) {
base::test::ScopedFeatureList scoped_features(
features::kDefaultLinkCapturingInBrowser);
constexpr char kTestAuthority[] = "www.example.com";
const auto& fake_apps = arc_test()->fake_apps();
std::string package_name = fake_apps[0].package_name;
std::string app_id = ArcAppListPrefs::GetAppId(fake_apps[0].package_name,
fake_apps[0].activity);
arc_test()->app_instance()->SendRefreshAppList(fake_apps);
// Update intent filters and supported links for the app, as if it was just
// installed.
intent_helper()->OnIntentFiltersUpdatedForPackage(
package_name, CreateFilterList(package_name, {kTestAuthority}));
std::vector<arc::mojom::SupportedLinksPtr> added_links;
added_links.emplace_back(base::in_place, package_name,
CreateFilterList(package_name, {kTestAuthority}));
intent_helper()->OnSupportedLinksChanged(
std::move(added_links), {},
arc::mojom::SupportedLinkChangeSource::kArcSystem);
FlushMojoCalls();
ASSERT_EQ(absl::nullopt, preferred_apps().FindPreferredAppForUrl(
GURL("https://www.example.com/foo")));
}
// Verifies that when the behavior to open links in the browser by default is
// enabled, apps which are already preferred can still update their filters.
TEST_F(ArcAppsPublisherTest,
SetSupportedLinksDefaultBrowserBehaviorAllowsUpdates) {
constexpr char kTestAuthority[] = "www.example.com";
constexpr char kTestAuthority2[] = "www.newexample.com";
const auto& fake_apps = arc_test()->fake_apps();
std::string package_name = fake_apps[0].package_name;
std::string app_id = ArcAppListPrefs::GetAppId(fake_apps[0].package_name,
fake_apps[0].activity);
arc_test()->app_instance()->SendRefreshAppList(fake_apps);
// Update intent filters and supported links for the app, as if it was just
// installed.
intent_helper()->OnIntentFiltersUpdatedForPackage(
package_name, CreateFilterList(package_name, {kTestAuthority}));
std::vector<arc::mojom::SupportedLinksPtr> added_links;
added_links.emplace_back(base::in_place, package_name,
CreateFilterList(package_name, {kTestAuthority}));
intent_helper()->OnSupportedLinksChanged(
std::move(added_links), {},
arc::mojom::SupportedLinkChangeSource::kArcSystem);
FlushMojoCalls();
base::test::ScopedFeatureList scoped_features(
features::kDefaultLinkCapturingInBrowser);
// Update filters with a new authority added.
intent_helper()->OnIntentFiltersUpdatedForPackage(
package_name,
CreateFilterList(package_name, {kTestAuthority, kTestAuthority2}));
std::vector<arc::mojom::SupportedLinksPtr> added_links2;
added_links2.emplace_back(
base::in_place, package_name,
CreateFilterList(package_name, {kTestAuthority, kTestAuthority2}));
intent_helper()->OnSupportedLinksChanged(
std::move(added_links2), {},
arc::mojom::SupportedLinkChangeSource::kArcSystem);
FlushMojoCalls();
ASSERT_EQ(app_id, preferred_apps().FindPreferredAppForUrl(
GURL("https://www.newexample.com/foo")));
}
// Verifies that when the behavior to open links in the browser by default is
// enabled, the user can still set an app as preferred through ARC settings.
TEST_F(ArcAppsPublisherTest,
SetSupportedLinksDefaultBrowserBehaviorAllowsUserChanges) {
base::test::ScopedFeatureList scoped_features(
features::kDefaultLinkCapturingInBrowser);
constexpr char kTestAuthority[] = "www.example.com";
const auto& fake_apps = arc_test()->fake_apps();
std::string package_name = fake_apps[0].package_name;
std::string app_id = ArcAppListPrefs::GetAppId(fake_apps[0].package_name,
fake_apps[0].activity);
arc_test()->app_instance()->SendRefreshAppList(fake_apps);
// Update intent filters and supported links for the app, as if it was just
// installed.
intent_helper()->OnIntentFiltersUpdatedForPackage(
package_name, CreateFilterList(package_name, {kTestAuthority}));
std::vector<arc::mojom::SupportedLinksPtr> added_links;
added_links.emplace_back(base::in_place, package_name,
CreateFilterList(package_name, {kTestAuthority}));
intent_helper()->OnSupportedLinksChanged(
std::move(added_links), {},
arc::mojom::SupportedLinkChangeSource::kUserPreference);
FlushMojoCalls();
ASSERT_EQ(app_id, preferred_apps().FindPreferredAppForUrl(
GURL("https://www.example.com/foo")));
}