Commit 261c0fed authored by Maggie Cai's avatar Maggie Cai Committed by Commit Bot

[IntentHandling] Get apps for URL from App Service.

This CL adds the apps query logic for URL intents to the App Service.

BUG=853604

Change-Id: Icb39f7be6dccb6c2ca58824d202c3a2650efedb0
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1826739
Commit-Queue: Maggie Cai <mxcai@chromium.org>
Reviewed-by: default avatarDominick Ng <dominickn@chromium.org>
Cr-Commit-Position: refs/heads/master@{#701399}
parent e29875ce
...@@ -3592,7 +3592,7 @@ jumbo_split_static_library("browser") { ...@@ -3592,7 +3592,7 @@ jumbo_split_static_library("browser") {
"//chrome/services/app_service:lib", "//chrome/services/app_service:lib",
"//chrome/services/app_service/public/cpp:app_update", "//chrome/services/app_service/public/cpp:app_update",
"//chrome/services/app_service/public/cpp:icon_loader", "//chrome/services/app_service/public/cpp:icon_loader",
"//chrome/services/app_service/public/cpp:intent_filter_util", "//chrome/services/app_service/public/cpp:intents",
"//components/feedback", "//components/feedback",
"//components/image_fetcher/core", "//components/image_fetcher/core",
"//components/keep_alive_registry", "//components/keep_alive_registry",
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "chrome/browser/apps/app_service/app_service_proxy_factory.h" #include "chrome/browser/apps/app_service/app_service_proxy_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/services/app_service/app_service_impl.h" #include "chrome/services/app_service/app_service_impl.h"
#include "chrome/services/app_service/public/cpp/intent_util.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h" #include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/url_data_source.h" #include "content/public/browser/url_data_source.h"
...@@ -224,6 +225,25 @@ void AppServiceProxy::ReInitializeCrostiniForTesting(Profile* profile) { ...@@ -224,6 +225,25 @@ void AppServiceProxy::ReInitializeCrostiniForTesting(Profile* profile) {
#endif #endif
} }
std::vector<std::string> AppServiceProxy::GetAppIdsForUrl(const GURL& url) {
return GetAppIdsForIntent(apps_util::CreateIntentFromUrl(url));
}
std::vector<std::string> AppServiceProxy::GetAppIdsForIntent(
apps::mojom::IntentPtr intent) {
std::vector<std::string> app_ids;
if (app_service_.is_bound()) {
cache_.ForEachApp([&app_ids, &intent](const apps::AppUpdate& update) {
for (const auto& filter : update.IntentFilters()) {
if (apps_util::IntentMatchesFilter(intent, filter)) {
app_ids.push_back(update.AppId());
}
}
});
}
return app_ids;
}
void AppServiceProxy::AddAppIconSource(Profile* profile) { void AppServiceProxy::AddAppIconSource(Profile* profile) {
// Make the chrome://app-icon/ resource available. // Make the chrome://app-icon/ resource available.
content::URLDataSource::Add(profile, content::URLDataSource::Add(profile,
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include "mojo/public/cpp/bindings/pending_receiver.h" #include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/receiver_set.h" #include "mojo/public/cpp/bindings/receiver_set.h"
#include "mojo/public/cpp/bindings/remote.h" #include "mojo/public/cpp/bindings/remote.h"
#include "url/gurl.h"
#if defined(OS_CHROMEOS) #if defined(OS_CHROMEOS)
#include "chrome/browser/apps/app_service/built_in_chromeos_apps.h" #include "chrome/browser/apps/app_service/built_in_chromeos_apps.h"
...@@ -72,6 +73,8 @@ class AppServiceProxy : public KeyedService, ...@@ -72,6 +73,8 @@ class AppServiceProxy : public KeyedService,
apps::IconLoader* OverrideInnerIconLoaderForTesting( apps::IconLoader* OverrideInnerIconLoaderForTesting(
apps::IconLoader* icon_loader); apps::IconLoader* icon_loader);
void ReInitializeCrostiniForTesting(Profile* profile); void ReInitializeCrostiniForTesting(Profile* profile);
std::vector<std::string> GetAppIdsForUrl(const GURL& url);
std::vector<std::string> GetAppIdsForIntent(apps::mojom::IntentPtr intent);
private: private:
// An adapter, presenting an IconLoader interface based on the underlying // An adapter, presenting an IconLoader interface based on the underlying
......
...@@ -695,32 +695,9 @@ apps::mojom::InstallSource GetInstallSource( ...@@ -695,32 +695,9 @@ apps::mojom::InstallSource GetInstallSource(
void ExtensionApps::PopulateIntentFilters( void ExtensionApps::PopulateIntentFilters(
const base::Optional<GURL>& app_scope, const base::Optional<GURL>& app_scope,
std::vector<mojom::IntentFilterPtr>* target) { std::vector<mojom::IntentFilterPtr>* target) {
if (app_scope) { if (app_scope != base::nullopt) {
auto intent_filter = apps::mojom::IntentFilter::New(); target->push_back(
apps_util::CreateIntentFilterForUrlScope(app_scope.value()));
std::vector<apps::mojom::ConditionValuePtr> scheme_condition_values;
scheme_condition_values.push_back(apps_util::MakeConditionValue(
app_scope->scheme(), apps::mojom::PatternMatchType::kNone));
auto scheme_condition =
apps_util::MakeCondition(apps::mojom::ConditionType::kScheme,
std::move(scheme_condition_values));
intent_filter->conditions.push_back(std::move(scheme_condition));
std::vector<apps::mojom::ConditionValuePtr> host_condition_values;
host_condition_values.push_back(apps_util::MakeConditionValue(
app_scope->host(), apps::mojom::PatternMatchType::kNone));
auto host_condition = apps_util::MakeCondition(
apps::mojom::ConditionType::kHost, std::move(host_condition_values));
intent_filter->conditions.push_back(std::move(host_condition));
std::vector<apps::mojom::ConditionValuePtr> path_condition_values;
path_condition_values.push_back(apps_util::MakeConditionValue(
app_scope->path(), apps::mojom::PatternMatchType::kPrefix));
auto path_condition = apps_util::MakeCondition(
apps::mojom::ConditionType::kPattern, std::move(path_condition_values));
intent_filter->conditions.push_back(std::move(path_condition));
target->push_back(std::move(intent_filter));
} }
} }
......
...@@ -41,10 +41,12 @@ source_set("icon_loader_test_support") { ...@@ -41,10 +41,12 @@ source_set("icon_loader_test_support") {
] ]
} }
source_set("intent_filter_util") { source_set("intents") {
sources = [ sources = [
"intent_filter_util.cc", "intent_filter_util.cc",
"intent_filter_util.h", "intent_filter_util.h",
"intent_util.cc",
"intent_util.h",
] ]
deps = [ deps = [
...@@ -61,6 +63,7 @@ source_set("unit_tests") { ...@@ -61,6 +63,7 @@ source_set("unit_tests") {
"app_update_unittest.cc", "app_update_unittest.cc",
"icon_cache_unittest.cc", "icon_cache_unittest.cc",
"icon_coalescer_unittest.cc", "icon_coalescer_unittest.cc",
"intent_util_unittest.cc",
] ]
deps = [ deps = [
......
...@@ -25,4 +25,31 @@ apps::mojom::ConditionPtr MakeCondition( ...@@ -25,4 +25,31 @@ apps::mojom::ConditionPtr MakeCondition(
return condition; return condition;
} }
apps::mojom::IntentFilterPtr CreateIntentFilterForUrlScope(const GURL& url) {
auto intent_filter = apps::mojom::IntentFilter::New();
std::vector<apps::mojom::ConditionValuePtr> scheme_condition_values;
scheme_condition_values.push_back(apps_util::MakeConditionValue(
url.scheme(), apps::mojom::PatternMatchType::kNone));
auto scheme_condition = apps_util::MakeCondition(
apps::mojom::ConditionType::kScheme, std::move(scheme_condition_values));
intent_filter->conditions.push_back(std::move(scheme_condition));
std::vector<apps::mojom::ConditionValuePtr> host_condition_values;
host_condition_values.push_back(apps_util::MakeConditionValue(
url.host(), apps::mojom::PatternMatchType::kNone));
auto host_condition = apps_util::MakeCondition(
apps::mojom::ConditionType::kHost, std::move(host_condition_values));
intent_filter->conditions.push_back(std::move(host_condition));
std::vector<apps::mojom::ConditionValuePtr> path_condition_values;
path_condition_values.push_back(apps_util::MakeConditionValue(
url.path(), apps::mojom::PatternMatchType::kPrefix));
auto path_condition = apps_util::MakeCondition(
apps::mojom::ConditionType::kPattern, std::move(path_condition_values));
intent_filter->conditions.push_back(std::move(path_condition));
return intent_filter;
}
} // namespace apps_util } // namespace apps_util
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h" #include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "url/gurl.h"
namespace apps_util { namespace apps_util {
...@@ -32,6 +33,10 @@ apps::mojom::ConditionPtr MakeCondition( ...@@ -32,6 +33,10 @@ apps::mojom::ConditionPtr MakeCondition(
apps::mojom::ConditionType condition_type, apps::mojom::ConditionType condition_type,
std::vector<apps::mojom::ConditionValuePtr> condition_values); std::vector<apps::mojom::ConditionValuePtr> condition_values);
// Create intent filter for URL scope, with prefix matching only for the path.
// e.g. filter created for https://www.google.com/ will match any URL that
// started with https://www.google.com/*.
apps::mojom::IntentFilterPtr CreateIntentFilterForUrlScope(const GURL& url);
} // namespace apps_util } // namespace apps_util
#endif // CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_FILTER_UTIL_H_ #endif // CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_FILTER_UTIL_H_
// Copyright (c) 2019 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/services/app_service/public/cpp/intent_util.h"
#include "base/optional.h"
#include "base/strings/string_util.h"
namespace {
// Get the intent condition value based on the condition type.
base::Optional<std::string> GetIntentConditionValueByType(
apps::mojom::ConditionType condition_type,
const apps::mojom::IntentPtr& intent) {
switch (condition_type) {
case apps::mojom::ConditionType::kScheme:
return intent->scheme;
case apps::mojom::ConditionType::kHost:
return intent->host;
case apps::mojom::ConditionType::kPattern:
return intent->path;
}
}
} // namespace
namespace apps_util {
apps::mojom::IntentPtr CreateIntentFromUrl(const GURL& url) {
auto intent = apps::mojom::Intent::New();
intent->scheme = url.scheme();
intent->host = url.host();
intent->path = url.path();
return intent;
}
bool ConditionValueMatches(
const std::string& value,
const apps::mojom::ConditionValuePtr& condition_value) {
switch (condition_value->match_type) {
// Fallthrough as kNone and kLiteral has same matching type.
case apps::mojom::PatternMatchType::kNone:
case apps::mojom::PatternMatchType::kLiteral:
return value == condition_value->value;
case apps::mojom::PatternMatchType::kPrefix:
return base::StartsWith(value, condition_value->value,
base::CompareCase::INSENSITIVE_ASCII);
case apps::mojom::PatternMatchType::kGlob:
// TODO(crbug.com/853604): Implement glob pattern match.
return false;
}
}
bool IntentMatchesCondition(const apps::mojom::IntentPtr& intent,
const apps::mojom::ConditionPtr& condition) {
base::Optional<std::string> value_to_match =
GetIntentConditionValueByType(condition->condition_type, intent);
if (!value_to_match.has_value()) {
return false;
}
for (const auto& condition_value : condition->condition_values) {
if (ConditionValueMatches(value_to_match.value(), condition_value)) {
return true;
}
}
return false;
}
bool IntentMatchesFilter(const apps::mojom::IntentPtr& intent,
const apps::mojom::IntentFilterPtr& filter) {
// Intent matches with this intent filter when all of the existing conditions
// match.
for (const auto& condition : filter->conditions) {
if (!IntentMatchesCondition(intent, condition)) {
return false;
}
}
return true;
}
} // namespace apps_util
// Copyright (c) 2019 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.
#ifndef CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
#define CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
// Utility functions for App Service intent.
#include <string>
#include "base/macros.h"
#include "chrome/services/app_service/public/mojom/types.mojom.h"
#include "url/gurl.h"
namespace apps_util {
// Create an intent struct from URL.
apps::mojom::IntentPtr CreateIntentFromUrl(const GURL& url);
// Return true if |value| matches with the |condition_value|, based on the
// pattern match type in the |condition_value|.
bool ConditionValueMatches(
const std::string& value,
const apps::mojom::ConditionValuePtr& condition_value);
// Return true if |intent| matches with any of the values in |condition|.
bool IntentMatchesCondition(const apps::mojom::IntentPtr& intent,
const apps::mojom::ConditionPtr& condition);
// Return true if a |filter| matches an |intent|. This is true when intent
// matches all existing conditions in the filter.
bool IntentMatchesFilter(const apps::mojom::IntentPtr& intent,
const apps::mojom::IntentFilterPtr& filter);
} // namespace apps_util
#endif // CHROME_SERVICES_APP_SERVICE_PUBLIC_CPP_INTENT_UTIL_H_
// Copyright (c) 2019 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/services/app_service/public/cpp/intent_util.h"
#include "chrome/services/app_service/public/cpp/intent_filter_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
const char kFilterUrl[] = "https://www.google.com/";
}
class IntentUtilTest : public testing::Test {
protected:
apps::mojom::ConditionPtr CreateMultiConditionValuesCondition() {
std::vector<apps::mojom::ConditionValuePtr> condition_values;
condition_values.push_back(apps_util::MakeConditionValue(
"https", apps::mojom::PatternMatchType::kNone));
condition_values.push_back(apps_util::MakeConditionValue(
"http", apps::mojom::PatternMatchType::kNone));
auto condition = apps_util::MakeCondition(
apps::mojom::ConditionType::kScheme, std::move(condition_values));
return condition;
}
};
TEST_F(IntentUtilTest, AllConditionMatches) {
GURL test_url = GURL("https://www.google.com/");
auto intent = apps_util::CreateIntentFromUrl(test_url);
auto intent_filter =
apps_util::CreateIntentFilterForUrlScope(GURL(kFilterUrl));
EXPECT_TRUE(apps_util::IntentMatchesFilter(intent, intent_filter));
}
TEST_F(IntentUtilTest, OneConditionDoesnotMatch) {
GURL test_url = GURL("https://www.abc.com/");
auto intent = apps_util::CreateIntentFromUrl(test_url);
auto intent_filter =
apps_util::CreateIntentFilterForUrlScope(GURL(kFilterUrl));
EXPECT_FALSE(apps_util::IntentMatchesFilter(intent, intent_filter));
}
TEST_F(IntentUtilTest, IntentDoesnotHaveValueToMatch) {
GURL test_url = GURL("www.abc.com/");
auto intent = apps_util::CreateIntentFromUrl(test_url);
auto intent_filter =
apps_util::CreateIntentFilterForUrlScope(GURL(kFilterUrl));
EXPECT_FALSE(apps_util::IntentMatchesFilter(intent, intent_filter));
}
// Test ConditionMatch with more then one condition values.
TEST_F(IntentUtilTest, OneConditionValueMatch) {
auto condition = CreateMultiConditionValuesCondition();
GURL test_url = GURL("https://www.google.com/");
auto intent = apps_util::CreateIntentFromUrl(test_url);
EXPECT_TRUE(apps_util::IntentMatchesCondition(intent, condition));
}
TEST_F(IntentUtilTest, NoneConditionValueMathc) {
auto condition = CreateMultiConditionValuesCondition();
GURL test_url = GURL("tel://www.google.com/");
auto intent = apps_util::CreateIntentFromUrl(test_url);
EXPECT_FALSE(apps_util::IntentMatchesCondition(intent, condition));
}
// Test Condition Value match with different pattern match type.
TEST_F(IntentUtilTest, NoneMatchType) {
auto condition_value = apps_util::MakeConditionValue(
"https", apps::mojom::PatternMatchType::kNone);
EXPECT_TRUE(apps_util::ConditionValueMatches("https", condition_value));
EXPECT_FALSE(apps_util::ConditionValueMatches("http", condition_value));
}
TEST_F(IntentUtilTest, LiteralMatchType) {
auto condition_value = apps_util::MakeConditionValue(
"https", apps::mojom::PatternMatchType::kLiteral);
EXPECT_TRUE(apps_util::ConditionValueMatches("https", condition_value));
EXPECT_FALSE(apps_util::ConditionValueMatches("http", condition_value));
}
TEST_F(IntentUtilTest, PrefixMatchType) {
auto condition_value = apps_util::MakeConditionValue(
"/ab", apps::mojom::PatternMatchType::kPrefix);
EXPECT_TRUE(apps_util::ConditionValueMatches("/abc", condition_value));
EXPECT_TRUE(apps_util::ConditionValueMatches("/ABC", condition_value));
EXPECT_FALSE(apps_util::ConditionValueMatches("/d", condition_value));
}
// TODO(crbug.com/853604): Test glob pattern match when implemented.
...@@ -213,3 +213,12 @@ struct Condition { ...@@ -213,3 +213,12 @@ struct Condition {
struct IntentFilter { struct IntentFilter {
array<Condition> conditions; array<Condition> conditions;
}; };
// Action and resource handling request. This includes the scheme and URL at
// the moment, and will be extended to handle MIME type and file extensions in
// the future.
struct Intent {
string? scheme; // URL scheme. e.g. https.
string? host; // URL host. e.g. www.google.com.
string? path; // URL path. e.g. /abc.
};
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