Commit 7c56e6bf authored by sandromaggi's avatar sandromaggi Committed by Commit Bot

[Autofill Assistant] Sending onboarding flag to server.

Before this change the server had no knowledge of whether or not the
onboarding was shown to the user in this run.
To be able to log this, a new flag is now sent to the server in the
requests for getting scripts.

Adding unit tests to check new behaviour.

Bug: b/142846407
Change-Id: Ic77bbc70c8add122beaff80a47e3cf7dca4454d7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1866631
Commit-Queue: Sandro Maggi <sandromaggi@google.com>
Reviewed-by: default avatarClemens Arbesser <arbesser@google.com>
Reviewed-by: default avatarMathias Carlen <mcarlen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#707763}
parent 7038e810
...@@ -49,6 +49,8 @@ class AssistantOnboardingCoordinator { ...@@ -49,6 +49,8 @@ class AssistantOnboardingCoordinator {
private AssistantBottomSheetContent mContent; private AssistantBottomSheetContent mContent;
private boolean mAnimate = true; private boolean mAnimate = true;
private boolean mOnboardingShown;
AssistantOnboardingCoordinator(String experimentIds, Context context, AssistantOnboardingCoordinator(String experimentIds, Context context,
BottomSheetController controller, @Nullable Tab tab) { BottomSheetController controller, @Nullable Tab tab) {
mExperimentIds = experimentIds; mExperimentIds = experimentIds;
...@@ -69,6 +71,7 @@ class AssistantOnboardingCoordinator { ...@@ -69,6 +71,7 @@ class AssistantOnboardingCoordinator {
*/ */
void show(Callback<Boolean> callback) { void show(Callback<Boolean> callback) {
AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_SHOWN); AutofillAssistantMetrics.recordOnBoarding(OnBoarding.OB_SHOWN);
mOnboardingShown = true;
if (mTab != null) { if (mTab != null) {
// If there's a tab, cover it with an overlay. // If there's a tab, cover it with an overlay.
...@@ -127,6 +130,14 @@ class AssistantOnboardingCoordinator { ...@@ -127,6 +130,14 @@ class AssistantOnboardingCoordinator {
mAnimate = false; mAnimate = false;
} }
/**
* Returns {@code true} if the onboarding has been shown at the beginning when this
* autofill assistant flow got triggered.
*/
boolean getOnboardingShown() {
return mOnboardingShown;
}
/** /**
* Set the content of the bottom sheet to be the Autofill Assistant onboarding. * Set the content of the bottom sheet to be the Autofill Assistant onboarding.
*/ */
......
...@@ -112,6 +112,8 @@ class AutofillAssistantClient { ...@@ -112,6 +112,8 @@ class AutofillAssistantClient {
AutofillAssistantClient.this, initialUrl, experimentIds, AutofillAssistantClient.this, initialUrl, experimentIds,
parameters.keySet().toArray(new String[parameters.size()]), parameters.keySet().toArray(new String[parameters.size()]),
parameters.values().toArray(new String[parameters.size()]), onboardingCoordinator, parameters.values().toArray(new String[parameters.size()]), onboardingCoordinator,
/* onboardingShown= */
onboardingCoordinator != null && onboardingCoordinator.getOnboardingShown(),
AutofillAssistantServiceInjector.getServiceToInject()); AutofillAssistantServiceInjector.getServiceToInject());
} }
...@@ -344,7 +346,8 @@ class AutofillAssistantClient { ...@@ -344,7 +346,8 @@ class AutofillAssistantClient {
AutofillAssistantClient fromWebContents(WebContents webContents); AutofillAssistantClient fromWebContents(WebContents webContents);
boolean start(long nativeClientAndroid, AutofillAssistantClient caller, String initialUrl, boolean start(long nativeClientAndroid, AutofillAssistantClient caller, String initialUrl,
String experimentIds, String[] parameterNames, String[] parameterValues, String experimentIds, String[] parameterNames, String[] parameterValues,
@Nullable AssistantOnboardingCoordinator onboardingCoordinator, long nativeService); @Nullable AssistantOnboardingCoordinator onboardingCoordinator,
boolean onboardingShown, long nativeService);
void onAccessToken(long nativeClientAndroid, AutofillAssistantClient caller, void onAccessToken(long nativeClientAndroid, AutofillAssistantClient caller,
boolean success, String accessToken); boolean success, String accessToken);
String getPrimaryAccountName(long nativeClientAndroid, AutofillAssistantClient caller); String getPrimaryAccountName(long nativeClientAndroid, AutofillAssistantClient caller);
......
...@@ -157,6 +157,17 @@ public class AssistantOnboardingCoordinatorTest { ...@@ -157,6 +157,17 @@ public class AssistantOnboardingCoordinatorTest {
instanceOf(AssistantBottomSheetContent.class)); instanceOf(AssistantBottomSheetContent.class));
} }
@Test
@MediumTest
@DisableIf.Build(sdk_is_greater_than = 22) // TODO(crbug/991938): re-enable
public void testShownFlag() throws Exception {
AssistantOnboardingCoordinator coordinator = createCoordinator(/* tab= */ null);
assertFalse(coordinator.getOnboardingShown());
showOnboardingAndWait(coordinator, mCallback);
assertTrue(coordinator.getOnboardingShown());
}
/** Trigger onboarding and wait until it is fully displayed. */ /** Trigger onboarding and wait until it is fully displayed. */
private void showOnboardingAndWait( private void showOnboardingAndWait(
AssistantOnboardingCoordinator coordinator, Callback<Boolean> callback) { AssistantOnboardingCoordinator coordinator, Callback<Boolean> callback) {
......
...@@ -131,6 +131,7 @@ bool ClientAndroid::Start(JNIEnv* env, ...@@ -131,6 +131,7 @@ bool ClientAndroid::Start(JNIEnv* env,
const JavaParamRef<jobjectArray>& parameter_names, const JavaParamRef<jobjectArray>& parameter_names,
const JavaParamRef<jobjectArray>& parameter_values, const JavaParamRef<jobjectArray>& parameter_values,
const JavaParamRef<jobject>& jonboarding_coordinator, const JavaParamRef<jobject>& jonboarding_coordinator,
jboolean jonboarding_shown,
jlong jservice) { jlong jservice) {
// When Start() is called, AA_START should have been measured. From now on, // When Start() is called, AA_START should have been measured. From now on,
// the client is responsible for keeping track of dropouts, so that for each // the client is responsible for keeping track of dropouts, so that for each
...@@ -151,6 +152,7 @@ bool ClientAndroid::Start(JNIEnv* env, ...@@ -151,6 +152,7 @@ bool ClientAndroid::Start(JNIEnv* env,
std::unique_ptr<TriggerContextImpl> trigger_context = CreateTriggerContext( std::unique_ptr<TriggerContextImpl> trigger_context = CreateTriggerContext(
env, jexperiment_ids, parameter_names, parameter_values); env, jexperiment_ids, parameter_names, parameter_values);
trigger_context->SetCCT(true); trigger_context->SetCCT(true);
trigger_context->SetOnboardingShown(jonboarding_shown);
GURL initial_url(base::android::ConvertJavaStringToUTF8(env, jinitial_url)); GURL initial_url(base::android::ConvertJavaStringToUTF8(env, jinitial_url));
return controller_->Start(initial_url, std::move(trigger_context)); return controller_->Start(initial_url, std::move(trigger_context));
......
...@@ -47,6 +47,7 @@ class ClientAndroid : public Client, ...@@ -47,6 +47,7 @@ class ClientAndroid : public Client,
const base::android::JavaParamRef<jobjectArray>& parameter_names, const base::android::JavaParamRef<jobjectArray>& parameter_names,
const base::android::JavaParamRef<jobjectArray>& parameter_values, const base::android::JavaParamRef<jobjectArray>& parameter_values,
const base::android::JavaParamRef<jobject>& jonboarding_coordinator, const base::android::JavaParamRef<jobject>& jonboarding_coordinator,
jboolean jonboarding_shown,
jlong jservice); jlong jservice);
void DestroyUI(JNIEnv* env, void DestroyUI(JNIEnv* env,
const base::android::JavaParamRef<jobject>& jcaller); const base::android::JavaParamRef<jobject>& jcaller);
......
...@@ -52,6 +52,9 @@ void FillClientContext(const ClientContextProto& client_context, ...@@ -52,6 +52,9 @@ void FillClientContext(const ClientContextProto& client_context,
if (trigger_context.is_cct()) { if (trigger_context.is_cct()) {
proto->set_is_cct(true); proto->set_is_cct(true);
} }
if (trigger_context.is_onboarding_shown()) {
proto->set_is_onboarding_shown(true);
}
if (trigger_context.is_direct_action()) { if (trigger_context.is_direct_action()) {
proto->set_is_direct_action(true); proto->set_is_direct_action(true);
} }
......
...@@ -98,6 +98,7 @@ TEST(ProtocolUtilsTest, CreateInitialScriptActionsRequest) { ...@@ -98,6 +98,7 @@ TEST(ProtocolUtilsTest, CreateInitialScriptActionsRequest) {
AssertClientContext(request.client_context()); AssertClientContext(request.client_context());
EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3")); EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3"));
EXPECT_TRUE(request.client_context().is_cct()); EXPECT_TRUE(request.client_context().is_cct());
EXPECT_FALSE(request.client_context().is_onboarding_shown());
EXPECT_FALSE(request.client_context().is_direct_action()); EXPECT_FALSE(request.client_context().is_direct_action());
const InitialScriptActionsRequestProto& initial = request.initial_request(); const InitialScriptActionsRequestProto& initial = request.initial_request();
...@@ -112,6 +113,41 @@ TEST(ProtocolUtilsTest, CreateInitialScriptActionsRequest) { ...@@ -112,6 +113,41 @@ TEST(ProtocolUtilsTest, CreateInitialScriptActionsRequest) {
EXPECT_EQ("script_payload", request.script_payload()); EXPECT_EQ("script_payload", request.script_payload());
} }
TEST(ProtocolUtilsTest, TestCreateInitialScriptActionsRequestFlags) {
std::map<std::string, std::string> parameters;
ScriptActionRequestProto request;
// With flags.
TriggerContextImpl trigger_context_flags(parameters, std::string());
trigger_context_flags.SetCCT(true);
trigger_context_flags.SetOnboardingShown(true);
trigger_context_flags.SetDirectAction(true);
EXPECT_TRUE(
request.ParseFromString(ProtocolUtils::CreateInitialScriptActionsRequest(
"script_path", GURL("http://example.com/"), trigger_context_flags,
"global_payload", "script_payload", CreateClientContextProto())));
AssertClientContext(request.client_context());
EXPECT_TRUE(request.client_context().is_cct());
EXPECT_TRUE(request.client_context().is_onboarding_shown());
EXPECT_TRUE(request.client_context().is_direct_action());
// Without flags.
TriggerContextImpl trigger_context_no_flags(parameters, std::string());
EXPECT_TRUE(
request.ParseFromString(ProtocolUtils::CreateInitialScriptActionsRequest(
"script_path", GURL("http://example.com/"), trigger_context_no_flags,
"global_payload", "script_payload", CreateClientContextProto())));
AssertClientContext(request.client_context());
EXPECT_FALSE(request.client_context().is_cct());
EXPECT_FALSE(request.client_context().is_onboarding_shown());
EXPECT_FALSE(request.client_context().is_direct_action());
}
TEST(ProtocolUtilsTest, CreateNextScriptActionsRequest) { TEST(ProtocolUtilsTest, CreateNextScriptActionsRequest) {
std::map<std::string, std::string> parameters; std::map<std::string, std::string> parameters;
parameters["a"] = "b"; parameters["a"] = "b";
...@@ -131,6 +167,44 @@ TEST(ProtocolUtilsTest, CreateNextScriptActionsRequest) { ...@@ -131,6 +167,44 @@ TEST(ProtocolUtilsTest, CreateNextScriptActionsRequest) {
EXPECT_EQ(1, request.next_request().processed_actions().size()); EXPECT_EQ(1, request.next_request().processed_actions().size());
} }
TEST(ProtocolUtilsTest, TestCreateNextScriptActionsRequestFlags) {
std::map<std::string, std::string> parameters;
std::vector<ProcessedActionProto> processed_actions;
processed_actions.emplace_back(ProcessedActionProto());
ScriptActionRequestProto request;
// With flags.
TriggerContextImpl trigger_context_flags(parameters, std::string());
trigger_context_flags.SetCCT(true);
trigger_context_flags.SetOnboardingShown(true);
trigger_context_flags.SetDirectAction(true);
EXPECT_TRUE(
request.ParseFromString(ProtocolUtils::CreateNextScriptActionsRequest(
trigger_context_flags, "global_payload", "script_payload",
processed_actions, CreateClientContextProto())));
AssertClientContext(request.client_context());
EXPECT_TRUE(request.client_context().is_cct());
EXPECT_TRUE(request.client_context().is_onboarding_shown());
EXPECT_TRUE(request.client_context().is_direct_action());
// Without flags.
TriggerContextImpl trigger_context_no_flags(parameters, std::string());
EXPECT_TRUE(
request.ParseFromString(ProtocolUtils::CreateNextScriptActionsRequest(
trigger_context_no_flags, "global_payload", "script_payload",
processed_actions, CreateClientContextProto())));
AssertClientContext(request.client_context());
EXPECT_FALSE(request.client_context().is_cct());
EXPECT_FALSE(request.client_context().is_onboarding_shown());
EXPECT_FALSE(request.client_context().is_direct_action());
}
TEST(ProtocolUtilsTest, CreateGetScriptsRequest) { TEST(ProtocolUtilsTest, CreateGetScriptsRequest) {
std::map<std::string, std::string> parameters; std::map<std::string, std::string> parameters;
parameters["a"] = "b"; parameters["a"] = "b";
...@@ -146,6 +220,7 @@ TEST(ProtocolUtilsTest, CreateGetScriptsRequest) { ...@@ -146,6 +220,7 @@ TEST(ProtocolUtilsTest, CreateGetScriptsRequest) {
AssertClientContext(request.client_context()); AssertClientContext(request.client_context());
EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3")); EXPECT_THAT(request.client_context().experiment_ids(), Eq("1,2,3"));
EXPECT_FALSE(request.client_context().is_cct()); EXPECT_FALSE(request.client_context().is_cct());
EXPECT_FALSE(request.client_context().is_onboarding_shown());
EXPECT_TRUE(request.client_context().is_direct_action()); EXPECT_TRUE(request.client_context().is_direct_action());
EXPECT_EQ("http://example.com/", request.url()); EXPECT_EQ("http://example.com/", request.url());
...@@ -156,6 +231,38 @@ TEST(ProtocolUtilsTest, CreateGetScriptsRequest) { ...@@ -156,6 +231,38 @@ TEST(ProtocolUtilsTest, CreateGetScriptsRequest) {
EXPECT_EQ("d", request.script_parameters(1).value()); EXPECT_EQ("d", request.script_parameters(1).value());
} }
TEST(ProtocolUtilsTest, TestCreateGetScriptsRequestFlags) {
std::map<std::string, std::string> parameters;
SupportsScriptRequestProto request;
// With flags.
TriggerContextImpl trigger_context_flags(parameters, std::string());
trigger_context_flags.SetCCT(true);
trigger_context_flags.SetOnboardingShown(true);
trigger_context_flags.SetDirectAction(true);
EXPECT_TRUE(request.ParseFromString(ProtocolUtils::CreateGetScriptsRequest(
GURL("http://example.com/"), trigger_context_flags,
CreateClientContextProto())));
AssertClientContext(request.client_context());
EXPECT_TRUE(request.client_context().is_cct());
EXPECT_TRUE(request.client_context().is_onboarding_shown());
EXPECT_TRUE(request.client_context().is_direct_action());
// Without flags.
TriggerContextImpl trigger_context_no_flags(parameters, std::string());
EXPECT_TRUE(request.ParseFromString(ProtocolUtils::CreateGetScriptsRequest(
GURL("http://example.com/"), trigger_context_no_flags,
CreateClientContextProto())));
AssertClientContext(request.client_context());
EXPECT_FALSE(request.client_context().is_cct());
EXPECT_FALSE(request.client_context().is_onboarding_shown());
EXPECT_FALSE(request.client_context().is_direct_action());
}
TEST(ProtocolUtilsTest, AddScriptIgnoreInvalid) { TEST(ProtocolUtilsTest, AddScriptIgnoreInvalid) {
SupportedScriptProto script_proto; SupportedScriptProto script_proto;
std::vector<std::unique_ptr<Script>> scripts; std::vector<std::unique_ptr<Script>> scripts;
......
...@@ -42,6 +42,9 @@ message ClientContextProto { ...@@ -42,6 +42,9 @@ message ClientContextProto {
// Assistant. // Assistant.
optional bool is_cct = 8; optional bool is_cct = 8;
// True if the onboarding screen was shown to the user.
optional bool is_onboarding_shown = 10;
// True if the script was triggered by a direct action. // True if the script was triggered by a direct action.
optional bool is_direct_action = 9; optional bool is_direct_action = 9;
} }
......
...@@ -62,6 +62,10 @@ bool TriggerContextImpl::is_cct() const { ...@@ -62,6 +62,10 @@ bool TriggerContextImpl::is_cct() const {
return cct_; return cct_;
} }
bool TriggerContextImpl::is_onboarding_shown() const {
return onboarding_shown_;
}
bool TriggerContextImpl::is_direct_action() const { bool TriggerContextImpl::is_direct_action() const {
return direct_action_; return direct_action_;
} }
...@@ -112,6 +116,14 @@ bool MergedTriggerContext::is_cct() const { ...@@ -112,6 +116,14 @@ bool MergedTriggerContext::is_cct() const {
return false; return false;
} }
bool MergedTriggerContext::is_onboarding_shown() const {
for (const TriggerContext* context : contexts_) {
if (context->is_onboarding_shown())
return true;
}
return false;
}
bool MergedTriggerContext::is_direct_action() const { bool MergedTriggerContext::is_direct_action() const {
for (const TriggerContext* context : contexts_) { for (const TriggerContext* context : contexts_) {
if (context->is_direct_action()) if (context->is_direct_action())
......
...@@ -53,6 +53,10 @@ class TriggerContext { ...@@ -53,6 +53,10 @@ class TriggerContext {
// Java. // Java.
virtual bool is_cct() const = 0; virtual bool is_cct() const = 0;
// Returns true if the onboarding was shown at the beginning when this
// autofill assistant flow got triggered.
virtual bool is_onboarding_shown() const = 0;
// Returns true if the current action was triggered by a direct action. // Returns true if the current action was triggered by a direct action.
virtual bool is_direct_action() const = 0; virtual bool is_direct_action() const = 0;
}; };
...@@ -76,10 +80,12 @@ class TriggerContextImpl : public TriggerContext { ...@@ -76,10 +80,12 @@ class TriggerContextImpl : public TriggerContext {
const std::string& name) const override; const std::string& name) const override;
void SetCCT(bool value) { cct_ = value; } void SetCCT(bool value) { cct_ = value; }
void SetOnboardingShown(bool value) { onboarding_shown_ = value; }
void SetDirectAction(bool value) { direct_action_ = value; } void SetDirectAction(bool value) { direct_action_ = value; }
std::string experiment_ids() const override; std::string experiment_ids() const override;
bool is_cct() const override; bool is_cct() const override;
bool is_onboarding_shown() const override;
bool is_direct_action() const override; bool is_direct_action() const override;
private: private:
...@@ -93,6 +99,8 @@ class TriggerContextImpl : public TriggerContext { ...@@ -93,6 +99,8 @@ class TriggerContextImpl : public TriggerContext {
bool cct_ = false; bool cct_ = false;
bool direct_action_ = false; bool direct_action_ = false;
bool onboarding_shown_ = false;
}; };
// Merges several TriggerContexts together. // Merges several TriggerContexts together.
...@@ -110,6 +118,7 @@ class MergedTriggerContext : public TriggerContext { ...@@ -110,6 +118,7 @@ class MergedTriggerContext : public TriggerContext {
const std::string& name) const override; const std::string& name) const override;
std::string experiment_ids() const override; std::string experiment_ids() const override;
bool is_cct() const override; bool is_cct() const override;
bool is_onboarding_shown() const override;
bool is_direct_action() const override; bool is_direct_action() const override;
private: private:
......
...@@ -102,6 +102,28 @@ TEST(TriggerContextText, MergeCCT) { ...@@ -102,6 +102,28 @@ TEST(TriggerContextText, MergeCCT) {
EXPECT_TRUE(one_with_cct->is_cct()); EXPECT_TRUE(one_with_cct->is_cct());
} }
TEST(TriggerContextTest, OnboardingShown) {
TriggerContextImpl context;
EXPECT_FALSE(context.is_onboarding_shown());
context.SetOnboardingShown(true);
EXPECT_TRUE(context.is_onboarding_shown());
}
TEST(TriggerContextTest, MergeOnboardingShown) {
auto empty = TriggerContext::CreateEmpty();
auto all_empty = TriggerContext::Merge({empty.get(), empty.get()});
EXPECT_FALSE(all_empty->is_onboarding_shown());
TriggerContextImpl onboarding_context;
onboarding_context.SetOnboardingShown(true);
auto one_with_onboarding =
TriggerContext::Merge({empty.get(), &onboarding_context, empty.get()});
EXPECT_TRUE(one_with_onboarding->is_onboarding_shown());
}
TEST(TriggerContextText, DirectAction) { TEST(TriggerContextText, DirectAction) {
TriggerContextImpl context; TriggerContextImpl context;
......
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