Commit 4bcc8496 authored by David Black's avatar David Black Committed by Commit Bot

Adds onboarding/reminders to deep_link_util.

Reminders is classified a web deep link, so it automatically will
open in the AssistantWebView (though we are only providing
placeholder content for the time being).

Onboarding will be wired up in a follow up CL.

This CL:
- Adds IsAssistantOnboardingDeepLink API.
- Adds IsAssistantRemindersDeepLink API.
- Adds ParseDeepLinkParams API. Some deep links, like onboarding, will
  have parameters and so I've added a method to parse parameters from
  a provided deep link and to return them in a provided map.
- Adds unit tests.

Bug: b:110986528
Change-Id: Ic17c625bd4b6869a256e1df09b4740fd2b6f1ee0
Reviewed-on: https://chromium-review.googlesource.com/1121581Reviewed-by: default avatarXiaohui Chen <xiaohuic@chromium.org>
Commit-Queue: David Black <dmblack@google.com>
Cr-Commit-Position: refs/heads/master@{#573401}
parent c1488fc6
......@@ -1693,6 +1693,7 @@ test("ash_unittests") {
"app_menu/notification_menu_controller_unittest.cc",
"app_menu/notification_menu_view_unittest.cc",
"assistant/assistant_controller_unittest.cc",
"assistant/util/deep_link_util_unittest.cc",
"autoclick/autoclick_unittest.cc",
"cursor_unittest.cc",
"detachable_base/detachable_base_handler_unittest.cc",
......
......@@ -4,6 +4,8 @@
#include "ash/assistant/util/deep_link_util.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "url/gurl.h"
namespace ash {
......@@ -12,10 +14,22 @@ namespace util {
namespace {
constexpr char kAssistantSettingsSpec[] = "googleassistant://settings";
constexpr char kAssistantOnboardingPrefix[] = "googleassistant://onboarding";
constexpr char kAssistantRemindersPrefix[] = "googleassistant://reminders";
constexpr char kAssistantSettingsPrefix[] = "googleassistant://settings";
// TODO(dmblack): Wire up actual Assistant Reminders URL.
constexpr char kAssistantRemindersWebUrl[] = R"(data:text/html,
<html>
<body style="padding:32px;">
<h3>Assistant Reminders</h3>
<p>Coming Soon! :)</p>
</body>
</html>
)";
// TODO(dmblack): Wire up actual Assistant Settings URL.
constexpr char kAssistantSettingsWebUiUrl[] = R"(data:text/html,
constexpr char kAssistantSettingsWebUrl[] = R"(data:text/html,
<html>
<body style="padding:32px;">
<h3>Assistant Settings</h3>
......@@ -27,30 +41,74 @@ constexpr char kAssistantSettingsWebUiUrl[] = R"(data:text/html,
} // namespace
bool IsDeepLinkUrl(const GURL& url) {
return IsAssistantSettingsDeepLink(url);
return IsAssistantOnboardingDeepLink(url) ||
IsAssistantRemindersDeepLink(url) || IsAssistantSettingsDeepLink(url);
}
bool IsAssistantOnboardingDeepLink(const GURL& url) {
return base::StartsWith(url.spec(), kAssistantOnboardingPrefix,
base::CompareCase::SENSITIVE);
}
bool IsAssistantRemindersDeepLink(const GURL& url) {
return base::StartsWith(url.spec(), kAssistantRemindersPrefix,
base::CompareCase::SENSITIVE);
}
GURL CreateAssistantSettingsDeepLink() {
return GURL(kAssistantSettingsSpec);
return GURL(kAssistantSettingsPrefix);
}
bool IsAssistantSettingsDeepLink(const GURL& url) {
return url.spec() == kAssistantSettingsSpec;
return base::StartsWith(url.spec(), kAssistantSettingsPrefix,
base::CompareCase::SENSITIVE);
}
base::Optional<GURL> GetWebUrl(const GURL& deep_link) {
if (!IsWebDeepLink(deep_link))
return base::nullopt;
if (IsAssistantRemindersDeepLink(deep_link))
return GURL(kAssistantRemindersWebUrl);
if (IsAssistantSettingsDeepLink(deep_link))
return GURL(kAssistantSettingsWebUiUrl);
return GURL(kAssistantSettingsWebUrl);
NOTIMPLEMENTED();
return base::nullopt;
}
bool IsWebDeepLink(const GURL& url) {
return IsAssistantSettingsDeepLink(url);
return IsAssistantRemindersDeepLink(url) || IsAssistantSettingsDeepLink(url);
}
bool ParseDeepLinkParams(const GURL& deep_link,
std::map<std::string, std::string>& params) {
if (!IsDeepLinkUrl(deep_link))
return false;
// If the deep link does not have a query then there are no key-value pairs to
// be parsed. We still return true in this case because omission of parameters
// in a deep link does not cause a parse attempt to fail.
if (!deep_link.has_query())
return true;
// Key-value pairs are '&' delimited and the keys/values are '=' delimited.
// Example: "googleassistant://onboarding?k1=v1&k2=v2".
base::StringPairs pairs;
if (!base::SplitStringIntoKeyValuePairs(deep_link.query(), '=', '&',
&pairs)) {
return false;
}
// Insert the parsed values into the caller provided map of |params|.
for (std::pair<std::string, std::string>& pair : pairs) {
if (params.count(pair.first) > 0) {
params[pair.first] = pair.second;
}
}
return true;
}
} // namespace util
......
......@@ -5,6 +5,10 @@
#ifndef ASH_ASSISTANT_UTIL_DEEP_LINK_UTIL_H_
#define ASH_ASSISTANT_UTIL_DEEP_LINK_UTIL_H_
#include <map>
#include <string>
#include "ash/ash_export.h"
#include "base/optional.h"
class GURL;
......@@ -14,22 +18,39 @@ namespace assistant {
namespace util {
// Returns true if the specified |url| is a deep link, false otherwise.
bool IsDeepLinkUrl(const GURL& url);
ASH_EXPORT bool IsDeepLinkUrl(const GURL& url);
// Returns true if the specified |url| is an Assistant onboarding deep link,
// false otherwise.
ASH_EXPORT bool IsAssistantOnboardingDeepLink(const GURL& url);
// Returns true if the specified |url| is an Assistant reminders deep link,
// false otherwise.
ASH_EXPORT bool IsAssistantRemindersDeepLink(const GURL& url);
// Returns a deep link to top level Assistant Settings.
GURL CreateAssistantSettingsDeepLink();
ASH_EXPORT GURL CreateAssistantSettingsDeepLink();
// Returns true if the specified |url| is an Assistant Settings deep link, false
// otherwise.
bool IsAssistantSettingsDeepLink(const GURL& url);
ASH_EXPORT bool IsAssistantSettingsDeepLink(const GURL& url);
// Returns the web URL for the specified |deep_link|. A return value will only
// be present if |deep_link| is a web deep link as identified by the
// IsWebDeepLink(GURL) API.
base::Optional<GURL> GetWebUrl(const GURL& deep_link);
ASH_EXPORT base::Optional<GURL> GetWebUrl(const GURL& deep_link);
// Returns true if the specified |url| is a web deep link, false otherwise.
bool IsWebDeepLink(const GURL& url);
ASH_EXPORT bool IsWebDeepLink(const GURL& url);
// Parses the specified |deep_link| for the values corresponding to the keys in
// |params|. If a value for a key in |params| is found, it is inserted into the
// map. If not, the existing value in the map is untouched, so it is recommended
// to initiate the map with default values prior to utilizing this API. The
// return value is true if the deep link was successfully parse, false
// otherwise.
ASH_EXPORT bool ParseDeepLinkParams(const GURL& deep_link,
std::map<std::string, std::string>& params);
} // namespace util
} // namespace assistant
......
// Copyright 2018 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 "ash/assistant/util/deep_link_util.h"
#include <map>
#include <string>
#include "ash/test/ash_test_base.h"
#include "base/macros.h"
#include "url/gurl.h"
namespace ash {
using namespace assistant::util;
class DeepLinkUnitTest : public AshTestBase {
protected:
DeepLinkUnitTest() = default;
~DeepLinkUnitTest() override = default;
void SetUp() override { AshTestBase::SetUp(); }
private:
DISALLOW_COPY_AND_ASSIGN(DeepLinkUnitTest);
};
TEST_F(DeepLinkUnitTest, IsDeepLink) {
auto AssertDeepLinkUrl = [](const GURL& url) {
ASSERT_TRUE(IsDeepLinkUrl(url));
};
auto AssertNotDeepLinkUrl = [](const GURL& url) {
ASSERT_FALSE(IsDeepLinkUrl(url));
};
// OK: Supported deep links.
AssertDeepLinkUrl(GURL("googleassistant://onboarding"));
AssertDeepLinkUrl(GURL("googleassistant://onboarding?param=true"));
AssertDeepLinkUrl(GURL("googleassistant://reminders"));
AssertDeepLinkUrl(GURL("googleassistant://reminders?param=true"));
AssertDeepLinkUrl(GURL("googleassistant://settings"));
AssertDeepLinkUrl(GURL("googleassistant://settings?param=true"));
// FAIL: Deep links are case sensitive.
AssertNotDeepLinkUrl(GURL("GOOGLEASSISTANT://ONBOARDING"));
AssertNotDeepLinkUrl(GURL("GOOGLEASSISTANT://REMINDERS"));
AssertNotDeepLinkUrl(GURL("GOOGLEASSISTANT://SETTINGS"));
// FAIL: Unsupported deep links.
AssertNotDeepLinkUrl(GURL("googleassistant://"));
AssertNotDeepLinkUrl(GURL("googleassistant://unsupported"));
// FAIL: Non-deep link URLs.
AssertNotDeepLinkUrl(GURL());
AssertNotDeepLinkUrl(GURL("https://www.google.com/"));
}
TEST_F(DeepLinkUnitTest, IsAssistantOnboardingDeepLink) {
auto AssertOnboardingDeepLink = [](const GURL& url) {
ASSERT_TRUE(IsAssistantOnboardingDeepLink(url));
};
auto AssertNotOnboardingDeepLink = [](const GURL& url) {
ASSERT_FALSE(IsAssistantOnboardingDeepLink(url));
};
// OK: Supported Assistant onboarding deep links.
AssertOnboardingDeepLink(GURL("googleassistant://onboarding"));
AssertOnboardingDeepLink(GURL("googleassistant://onboarding?param=true"));
// FAIL: Deep links are case sensitive.
AssertNotOnboardingDeepLink(GURL("GOOGLEASSISTANT://ONBOARDING"));
// FAIL: Non-Assistant onboarding deep links.
AssertNotOnboardingDeepLink(GURL("googleassistant://reminders"));
AssertNotOnboardingDeepLink(GURL("googleassistant://reminders?param=true"));
AssertNotOnboardingDeepLink(GURL("googleassistant://settings"));
AssertNotOnboardingDeepLink(GURL("googleassistant://settings?param=true"));
// FAIL: Non-deep link URLs.
AssertNotOnboardingDeepLink(GURL());
AssertNotOnboardingDeepLink(GURL("https://www.google.com/"));
}
TEST_F(DeepLinkUnitTest, IsAssistantRemindersDeepLink) {
auto AssertRemindersDeepLink = [](const GURL& url) {
ASSERT_TRUE(IsAssistantRemindersDeepLink(url));
};
auto AssertNotRemindersDeepLink = [](const GURL& url) {
ASSERT_FALSE(IsAssistantRemindersDeepLink(url));
};
// OK: Supported Assistant reminders deep links.
AssertRemindersDeepLink(GURL("googleassistant://reminders"));
AssertRemindersDeepLink(GURL("googleassistant://reminders?param=true"));
// FAIL: Deep links are case sensitive.
AssertNotRemindersDeepLink(GURL("GOOGLEASSISTANT://REMINDERS"));
// FAIL: Non-Assistant reminders deep links.
AssertNotRemindersDeepLink(GURL("googleassistant://onboarding"));
AssertNotRemindersDeepLink(GURL("googleassistant://onboarding?param=true"));
AssertNotRemindersDeepLink(GURL("googleassistant://settings"));
AssertNotRemindersDeepLink(GURL("googleassistant://settings?param=true"));
// FAIL: Non-deep link URLs.
AssertNotRemindersDeepLink(GURL());
AssertNotRemindersDeepLink(GURL("https://www.google.com/"));
}
TEST_F(DeepLinkUnitTest, CreateAssistantSettingsDeepLink) {
ASSERT_EQ(GURL("googleassistant://settings"),
CreateAssistantSettingsDeepLink());
}
TEST_F(DeepLinkUnitTest, IsAssistantSettingsDeepLink) {
auto AssertSettingsDeepLink = [](const GURL& url) {
ASSERT_TRUE(IsAssistantSettingsDeepLink(url));
};
auto AssertNotSettingsDeepLink = [](const GURL& url) {
ASSERT_FALSE(IsAssistantSettingsDeepLink(url));
};
// OK: Supported Assistant Settings deep links.
AssertSettingsDeepLink(GURL("googleassistant://settings"));
AssertSettingsDeepLink(GURL("googleassistant://settings?param=true"));
// FAIL: Deep links are case sensitive.
AssertNotSettingsDeepLink(GURL("GOOGLEASSISTANT://SETTINGS"));
// FAIL: Non-Assistant Settings deep links.
AssertNotSettingsDeepLink(GURL("googleassistant://onboarding"));
AssertNotSettingsDeepLink(GURL("googleassistant://onboarding?param=true"));
AssertNotSettingsDeepLink(GURL("googleassistant://reminders"));
AssertNotSettingsDeepLink(GURL("googleassistant://reminders?param=true"));
// FAIL: Non-deep link URLs.
AssertNotSettingsDeepLink(GURL());
AssertNotSettingsDeepLink(GURL("https://www.google.com/"));
}
// TODO(dmblack): Assert actual web URLs when available.
TEST_F(DeepLinkUnitTest, GetWebUrl) {
auto AssertWebUrlPresent = [](const GURL& url) {
ASSERT_TRUE(GetWebUrl(url).has_value());
};
auto AssertWebUrlAbsent = [](const GURL& url) {
ASSERT_FALSE(GetWebUrl(url).has_value());
};
// OK: Supported web deep links.
AssertWebUrlPresent(GURL("googleassistant://reminders"));
AssertWebUrlPresent(GURL("googleassistant://reminders?param=true"));
AssertWebUrlPresent(GURL("googleassistant://settings"));
AssertWebUrlPresent(GURL("googleassistant://settings?param=true"));
// FAIL: Deep links are case sensitive.
AssertWebUrlAbsent(GURL("GOOGLEASSISTANT://REMINDERS"));
AssertWebUrlAbsent(GURL("GOOGLEASSISTANT://SETTINGS"));
// FAIL: Non-web deep links.
AssertWebUrlAbsent(GURL("googleassistant://onboarding"));
AssertWebUrlAbsent(GURL("googleassistant://onboarding?param=true"));
// FAIL: Non-deep link URLS.
AssertWebUrlAbsent(GURL());
AssertWebUrlAbsent(GURL("https://www.google.com/"));
}
TEST_F(DeepLinkUnitTest, IsWebDeepLink) {
auto AssertWebDeepLink = [](const GURL& url) {
ASSERT_TRUE(IsWebDeepLink(url));
};
auto AssertNotWebDeepLink = [](const GURL& url) {
ASSERT_FALSE(IsWebDeepLink(url));
};
// OK: Supported web deep links.
AssertWebDeepLink(GURL("googleassistant://reminders"));
AssertWebDeepLink(GURL("googleassistant://reminders?param=true"));
AssertWebDeepLink(GURL("googleassistant://settings"));
AssertWebDeepLink(GURL("googleassistant://settings?param=true"));
// FAIL: Deep links are case sensitive.
AssertNotWebDeepLink(GURL("GOOGLEASSISTANT://REMINDERS"));
AssertNotWebDeepLink(GURL("GOOGLEASSISTANT://SETTINGS"));
// FAIL: Non-web deep links.
AssertNotWebDeepLink(GURL("googleassistant://onboarding"));
AssertNotWebDeepLink(GURL("googleassistant://onboarding?param=true"));
// FAIL: Non-deep link URLs.
AssertNotWebDeepLink(GURL());
AssertNotWebDeepLink(GURL("https://www.google.com/"));
}
TEST_F(DeepLinkUnitTest, ParseDeepLinkParams) {
auto AssertParamsParsed = [](const GURL& deep_link,
std::map<std::string, std::string>& params) {
ASSERT_TRUE(ParseDeepLinkParams(deep_link, params));
};
auto AssertParamsNotParsed = [](const GURL& deep_link,
std::map<std::string, std::string>& params) {
ASSERT_FALSE(ParseDeepLinkParams(deep_link, params));
};
std::map<std::string, std::string> params;
auto ResetParams = [&params]() {
params["k1"] = "default";
params["k2"] = "default";
};
ResetParams();
// OK: All parameters present.
AssertParamsParsed(GURL("googleassistant://onboarding?k1=v1&k2=v2"), params);
ASSERT_EQ("v1", params["k1"]);
ASSERT_EQ("v2", params["k2"]);
ResetParams();
// OK: Some parameters present.
AssertParamsParsed(GURL("googleassistant://onboarding?k1=v1"), params);
ASSERT_EQ("v1", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// OK: Unknown parameters present.
AssertParamsParsed(GURL("googleassistant://onboarding?k1=v1&k3=v3"), params);
ASSERT_EQ("v1", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// OK: No parameters present.
AssertParamsParsed(GURL("googleassistant://onboarding"), params);
ASSERT_EQ("default", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// OK: Parameters are case sensitive.
AssertParamsParsed(GURL("googleassistant://onboarding?K1=v1"), params);
ASSERT_EQ("default", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// FAIL: Deep links are case sensitive.
AssertParamsNotParsed(GURL("GOOGLEASSISTANT://ONBOARDING?k1=v1"), params);
ASSERT_EQ("default", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// FAIL: Malformed parameters.
AssertParamsNotParsed(GURL("googleassistant://onboarding?k1="), params);
ASSERT_EQ("default", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// FAIL: Non-deep link URLs.
AssertParamsNotParsed(GURL("https://www.google.com/search?q=query"), params);
ASSERT_EQ("default", params["k1"]);
ASSERT_EQ("default", params["k2"]);
ResetParams();
// FAIL: Empty URLs.
AssertParamsNotParsed(GURL(), params);
ASSERT_EQ("default", params["k1"]);
ASSERT_EQ("default", params["k2"]);
}
} // namespace ash
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