Commit 4e5b2c2c authored by Lakshmi Kumar Dabbiru's avatar Lakshmi Kumar Dabbiru Committed by Commit Bot

Editable UI to use in chrome Autofill

CL splitting Plan

1) Current CL - End to end flow and functional demo. Fix flow UI is quite basic and need to make small changes and I will chat with you tomorrow on UX layout here. Today at save card, it is crashing in JNI code. Matthew, will swing by your desk tomorrow. It is again at some Context OOO or some thing. This time I want to learn how to debug that stuff.

This is major part of CL where I have to get ack from multiple reviewers. I tried to make flow as basic as possible.

2) Pretty up the UI and fix all UI nits to match production one - This is mostly mdjones@ review and UX Ok with spacing and etc.

3) Metrics, tests and preferences - Today there is not much testing on Android side. So need to see what I can add - This jsaul@ can review.

What to implement - https://docs.google.com/presentation/d/1hfCDQJle0SB5AX2vdhERC7JuduR9jvOTiszSy4BON2Q/edit#slide=id.g433d7fc08d_1_8
Demo - https://drive.google.com/file/d/0Bw9uo2EXAqJ_NmtQbGtVdlpHWF9PQ1Y2QVR1SGtuRjBQeFI4/view?usp=sharing

Bug: 848955
Change-Id: I080684d8a864cba760b5be6fef96b1aa52478eb8
Reviewed-on: https://chromium-review.googlesource.com/c/1180438Reviewed-by: default avatarTed Choc <tedchoc@chromium.org>
Reviewed-by: default avatarMoe Ahmadi <mahmadi@chromium.org>
Reviewed-by: default avatarFabio Tirelo <ftirelo@chromium.org>
Reviewed-by: default avatarSebastien Seguin-Gagnon <sebsg@chromium.org>
Reviewed-by: default avatarMatthew Jones <mdjones@chromium.org>
Reviewed-by: default avatarJared Saul <jsaul@google.com>
Reviewed-by: default avatarChangwan Ryu <changwan@chromium.org>
Commit-Queue: Lakshmi Kumar Dabbiru <dlkumar@google.com>
Cr-Commit-Position: refs/heads/master@{#606544}
parent c20223cc
...@@ -281,6 +281,12 @@ void AwAutofillClient::ShowLocalCardMigrationDialog( ...@@ -281,6 +281,12 @@ void AwAutofillClient::ShowLocalCardMigrationDialog(
NOTIMPLEMENTED(); NOTIMPLEMENTED();
} }
void AwAutofillClient::ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) {
NOTIMPLEMENTED();
}
void AwAutofillClient::ConfirmMigrateLocalCardToCloud( void AwAutofillClient::ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
const std::vector<autofill::MigratableCreditCard>& migratable_credit_cards, const std::vector<autofill::MigratableCreditCard>& migratable_credit_cards,
......
...@@ -79,6 +79,9 @@ class AwAutofillClient : public autofill::AutofillClient, ...@@ -79,6 +79,9 @@ class AwAutofillClient : public autofill::AutofillClient,
void OnUnmaskVerificationResult(PaymentsRpcResult result) override; void OnUnmaskVerificationResult(PaymentsRpcResult result) override;
void ShowLocalCardMigrationDialog( void ShowLocalCardMigrationDialog(
base::OnceClosure show_migration_dialog_closure) override; base::OnceClosure show_migration_dialog_closure) override;
void ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) override;
void ConfirmMigrateLocalCardToCloud( void ConfirmMigrateLocalCardToCloud(
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
const std::vector<autofill::MigratableCreditCard>& const std::vector<autofill::MigratableCreditCard>&
......
<?xml version="1.0" encoding="utf-8"?>
<!-- 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. -->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/pref_autofill_field_horizontal_padding"
android:minHeight="36dp"
android:orientation="vertical"
android:gravity="center_vertical">
<TextView
android:id="@+id/cc_name_label_text"
android:labelFor="@+id/cc_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/pref_autofill_field_top_margin"
android:layout_marginEnd="@dimen/pref_autofill_field_horizontal_padding"
android:textAppearance="@style/BlackCaption"
android:text="@string/autofill_credit_card_editor_name" />
<org.chromium.chrome.browser.widget.CompatibilityTextInputLayout
android:id="@+id/cc_name"
android:labelFor="@+id/cc_name_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/cc_name_edit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:inputType="textCapWords"/>
</org.chromium.chrome.browser.widget.CompatibilityTextInputLayout>
<TextView
android:id="@+id/cc_name_legal_message"
android:layout_width="match_parent"
android:layout_marginTop="@dimen/pref_autofill_field_top_margin"
android:layout_height="wrap_content"
android:textAppearance="@style/BlackBody"
android:textColorLink="@color/infobar_accent_blue" />
</LinearLayout>
// 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.
package org.chromium.chrome.browser.autofill;
import android.app.Activity;
import org.chromium.base.ThreadUtils;
import org.chromium.base.annotations.CalledByNative;
import org.chromium.base.annotations.JNINamespace;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.ResourceId;
import org.chromium.chrome.browser.autofill.AutofillNameFixFlowPrompt.AutofillNameFixFlowPromptDelegate;
import org.chromium.chrome.browser.autofill.AutofillNameFixFlowPrompt.LegalMessageLine;
import org.chromium.ui.base.WindowAndroid;
import java.util.ArrayList;
import java.util.List;
/**
* JNI call glue for AutofillNameFixFlowPrompt C++ and Java objects.
*/
@JNINamespace("autofill")
final class AutofillNameFixFlowBridge implements AutofillNameFixFlowPromptDelegate {
private final long mNativeCardNameFixFlowViewAndroid;
private final Activity mActivity;
private final String mTitle;
private final String mInferredName;
private final String mConfirmButtonLabel;
private final int mIconId;
private final List<LegalMessageLine> mLegalMessageLines = new ArrayList<LegalMessageLine>();
private AutofillNameFixFlowPrompt mNameFixFlowPrompt;
private AutofillNameFixFlowBridge(long nativeCardNameFixFlowViewAndroid, String title,
String inferredName, String confirmButtonLabel, int iconId,
WindowAndroid windowAndroid) {
mNativeCardNameFixFlowViewAndroid = nativeCardNameFixFlowViewAndroid;
mTitle = title;
mInferredName = inferredName;
mConfirmButtonLabel = confirmButtonLabel;
mIconId = iconId;
mActivity = windowAndroid.getActivity().get();
if (mActivity == null) {
mNameFixFlowPrompt = null;
// Clean up the native counterpart. This is posted to allow the native counterpart
// to fully finish the construction of this glue object before we attempt to delete it.
ThreadUtils.postOnUiThread(() -> onPromptDismissed());
}
}
@CalledByNative
private static AutofillNameFixFlowBridge create(long nativeNameFixFlowPrompt, String title,
String inferredName, String confirmButtonLabel, int iconId,
WindowAndroid windowAndroid) {
return new AutofillNameFixFlowBridge(nativeNameFixFlowPrompt, title, inferredName,
confirmButtonLabel, iconId, windowAndroid);
}
/**
* Adds a line of legal message plain text to the infobar.
*
* @param text The legal message plain text.
*/
@CalledByNative
private void addLegalMessageLine(String text) {
mLegalMessageLines.add(new LegalMessageLine(text));
}
/**
* Marks up the last added line of legal message text with a link.
*
* @param start The inclusive offset of the start of the link in the text.
* @param end The exclusive offset of the end of the link in the text.
* @param url The URL to open when the link is clicked.
*/
@CalledByNative
private void addLinkToLastLegalMessageLine(int start, int end, String url) {
mLegalMessageLines.get(mLegalMessageLines.size() - 1)
.links.add(new LegalMessageLine.Link(start, end, url));
}
@Override
public void onPromptDismissed() {
nativePromptDismissed(mNativeCardNameFixFlowViewAndroid);
}
@Override
public void onUserAccept(String name) {
nativeOnUserAccept(mNativeCardNameFixFlowViewAndroid, name);
}
@Override
public void onLegalMessageLinkClicked(String url) {
nativeOnLegalMessageLinkClicked(mNativeCardNameFixFlowViewAndroid, url);
}
/**
* Shows a prompt for name fix flow.
*/
@CalledByNative
private void show(WindowAndroid windowAndroid) {
mNameFixFlowPrompt = new AutofillNameFixFlowPrompt(mActivity, this, mTitle, mInferredName,
mLegalMessageLines, mConfirmButtonLabel, ResourceId.mapToDrawableId(mIconId));
if (mNameFixFlowPrompt != null) {
mNameFixFlowPrompt.show((ChromeActivity) (windowAndroid.getActivity().get()));
}
}
/**
* Dismisses the prompt without returning any user response.
*/
@CalledByNative
private void dismiss() {
if (mNameFixFlowPrompt != null) mNameFixFlowPrompt.dismiss();
}
private native void nativePromptDismissed(long nativeCardNameFixFlowViewAndroid);
private native void nativeOnUserAccept(long nativeCardNameFixFlowViewAndroid, String name);
private native void nativeOnLegalMessageLinkClicked(
long nativeCardNameFixFlowViewAndroid, String url);
}
// 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.
package org.chromium.chrome.browser.autofill;
import android.content.Context;
import android.text.SpannableString;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.method.LinkMovementMethod;
import android.text.style.ClickableSpan;
import android.view.LayoutInflater;
import android.view.View;
import android.view.inputmethod.EditorInfo;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.TextView.BufferType;
import org.chromium.chrome.R;
import org.chromium.chrome.browser.ChromeActivity;
import org.chromium.chrome.browser.modaldialog.DialogDismissalCause;
import org.chromium.chrome.browser.modaldialog.ModalDialogManager;
import org.chromium.chrome.browser.modaldialog.ModalDialogView;
import java.util.ArrayList;
import java.util.List;
/**
* Prompt that asks users to confirm user's name before saving card to Google.
*/
public class AutofillNameFixFlowPrompt implements ModalDialogView.Controller {
/**
* Legal message line with links to show in the fix flow prompt.
*/
public static class LegalMessageLine {
/**
* A link in the legal message line.
*/
public static class Link {
/**
* The starting inclusive index of the link position in the text.
*/
public int start;
/**
* The ending exclusive index of the link position in the text.
*/
public int end;
/**
* The URL of the link.
*/
public String url;
/**
* Creates a new instance of the link.
*
* @param start The starting inclusive index of the link position in the text.
* @param end The ending exclusive index of the link position in the text.
* @param url The URL of the link.
*/
public Link(int start, int end, String url) {
this.start = start;
this.end = end;
this.url = url;
}
}
/**
* The plain text legal message line.
*/
public String text;
/**
* A collection of links in the legal message line.
*/
public final List<Link> links = new ArrayList<Link>();
/**
* Creates a new instance of the legal message line.
*
* @param legalText The plain text legal message.
*/
public LegalMessageLine(String legalText) {
text = legalText;
}
}
/**
* An interface to handle the interaction with
* an AutofillNameFixFlowPrompt object.
*/
public interface AutofillNameFixFlowPromptDelegate {
/**
* Called when dialog is dismissed.
*/
void onPromptDismissed();
/**
* Called when user accepted/confirmed the prompt.
*
* @param name Card holder name.
*/
void onUserAccept(String name);
/**
* Called when user clicked on legal message.
*
* @param url Legal message URL that user clicked.
*/
void onLegalMessageLinkClicked(String url);
}
private final AutofillNameFixFlowPromptDelegate mDelegate;
private final ModalDialogView mDialog;
private final EditText mUserNameInput;
private ModalDialogManager mModalDialogManager;
private Context mContext;
/**
* Fix flow prompt to confirm user name before saving the card to Google.
*/
public AutofillNameFixFlowPrompt(Context context, AutofillNameFixFlowPromptDelegate delegate,
String title, String inferredName, List<LegalMessageLine> legalMessageLines,
String confirmButtonLabel, int drawableId) {
mDelegate = delegate;
LayoutInflater inflater = LayoutInflater.from(context);
View v = inflater.inflate(R.layout.autofill_name_fixflow, null);
mUserNameInput = (EditText) v.findViewById(R.id.cc_name_edit);
mUserNameInput.setText(inferredName, BufferType.EDITABLE);
SpannableStringBuilder legalMessageText = new SpannableStringBuilder();
for (LegalMessageLine line : legalMessageLines) {
SpannableString text = new SpannableString(line.text);
for (final LegalMessageLine.Link link : line.links) {
text.setSpan(new ClickableSpan() {
@Override
public void onClick(View view) {
delegate.onLegalMessageLinkClicked(link.url);
}
}, link.start, link.end, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
}
legalMessageText.append(legalMessageText);
}
TextView legalMessageView = (TextView) v.findViewById(R.id.cc_name_legal_message);
legalMessageView.setText(legalMessageText);
legalMessageView.setMovementMethod(LinkMovementMethod.getInstance());
ModalDialogView.Params params = new ModalDialogView.Params();
params.title = title;
params.customView = v;
params.negativeButtonTextId = R.string.cancel;
params.positiveButtonText = confirmButtonLabel;
params.cancelOnTouchOutside = true;
mDialog = new ModalDialogView(this, params);
// Hitting the "submit" button on the software keyboard should submit.
mUserNameInput.setOnEditorActionListener((view, actionId, event) -> {
if (actionId == EditorInfo.IME_ACTION_DONE) {
onClick(ModalDialogView.ButtonType.POSITIVE);
return true;
}
return false;
});
}
/**
* Show the dialog. If activity is null this method will not do anything.
*/
public void show(ChromeActivity activity) {
if (activity == null) return;
mContext = activity;
mModalDialogManager = activity.getModalDialogManager();
mModalDialogManager.showDialog(mDialog, ModalDialogManager.ModalDialogType.APP);
Button saveButton = mDialog.getButton(ModalDialogView.ButtonType.POSITIVE);
}
protected void dismiss() {
mModalDialogManager.dismissDialog(mDialog);
}
@Override
public void onClick(@ModalDialogView.ButtonType int buttonType) {
if (buttonType == ModalDialogView.ButtonType.POSITIVE) {
mDelegate.onUserAccept(mUserNameInput.getText().toString());
} else if (buttonType == ModalDialogView.ButtonType.NEGATIVE) {
mModalDialogManager.dismissDialog(
mDialog, DialogDismissalCause.NEGATIVE_BUTTON_CLICKED);
}
}
@Override
public void onDismiss(@DialogDismissalCause int dismissalCause) {
mDelegate.onPromptDismissed();
}
}
...@@ -90,6 +90,8 @@ chrome_java_sources = [ ...@@ -90,6 +90,8 @@ chrome_java_sources = [
"java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java", "java/src/org/chromium/chrome/browser/appmenu/AppMenuPropertiesDelegate.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryBridge.java", "java/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryBridge.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java", "java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillNameFixFlowBridge.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillNameFixFlowPrompt.java",
"java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java", "java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java",
"java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java", "java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java",
"java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java", "java/src/org/chromium/chrome/browser/autofill/CardUnmaskPrompt.java",
......
...@@ -4613,6 +4613,7 @@ if (is_android) { ...@@ -4613,6 +4613,7 @@ if (is_android) {
"../android/java/src/org/chromium/chrome/browser/accessibility/FontSizePrefs.java", "../android/java/src/org/chromium/chrome/browser/accessibility/FontSizePrefs.java",
"../android/java/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryBridge.java", "../android/java/src/org/chromium/chrome/browser/autofill/AutofillKeyboardAccessoryBridge.java",
"../android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java", "../android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java",
"../android/java/src/org/chromium/chrome/browser/autofill/AutofillNameFixFlowBridge.java",
"../android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java", "../android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java",
"../android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java", "../android/java/src/org/chromium/chrome/browser/autofill/CardUnmaskBridge.java",
"../android/java/src/org/chromium/chrome/browser/autofill/CreditCardScannerBridge.java", "../android/java/src/org/chromium/chrome/browser/autofill/CreditCardScannerBridge.java",
......
...@@ -118,7 +118,8 @@ AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegateWithLegalMessage( ...@@ -118,7 +118,8 @@ AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegateWithLegalMessage(
credit_card_to_save_ = credit_card; credit_card_to_save_ = credit_card;
std::unique_ptr<ConfirmInfoBarDelegate> delegate( std::unique_ptr<ConfirmInfoBarDelegate> delegate(
new AutofillSaveCardInfoBarDelegateMobile( new AutofillSaveCardInfoBarDelegateMobile(
is_uploading, credit_card, std::move(legal_message), is_uploading, /*should_request_name_from_user=*/false, credit_card,
std::move(legal_message),
/*strike_database=*/nullptr, /*strike_database=*/nullptr,
/*upload_save_card_callback=*/ /*upload_save_card_callback=*/
base::BindOnce(&AutofillSaveCardInfoBarDelegateMobileTest:: base::BindOnce(&AutofillSaveCardInfoBarDelegateMobileTest::
...@@ -131,7 +132,8 @@ AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegateWithLegalMessage( ...@@ -131,7 +132,8 @@ AutofillSaveCardInfoBarDelegateMobileTest::CreateDelegateWithLegalMessage(
// Local save infobar delegate: // Local save infobar delegate:
std::unique_ptr<ConfirmInfoBarDelegate> delegate( std::unique_ptr<ConfirmInfoBarDelegate> delegate(
new AutofillSaveCardInfoBarDelegateMobile( new AutofillSaveCardInfoBarDelegateMobile(
is_uploading, credit_card, std::move(legal_message), is_uploading, /*should_request_name_from_user=*/false, credit_card,
std::move(legal_message),
/*strike_database=*/nullptr, /*strike_database=*/nullptr,
/*upload_save_card_callback=*/ /*upload_save_card_callback=*/
AutofillClient::UserAcceptedUploadCallback(), AutofillClient::UserAcceptedUploadCallback(),
......
...@@ -589,6 +589,8 @@ jumbo_split_static_library("ui") { ...@@ -589,6 +589,8 @@ jumbo_split_static_library("ui") {
"android/autofill/autofill_logger_android.h", "android/autofill/autofill_logger_android.h",
"android/autofill/autofill_popup_view_android.cc", "android/autofill/autofill_popup_view_android.cc",
"android/autofill/autofill_popup_view_android.h", "android/autofill/autofill_popup_view_android.h",
"android/autofill/card_name_fix_flow_view_android.cc",
"android/autofill/card_name_fix_flow_view_android.h",
"android/autofill/card_unmask_prompt_view_android.cc", "android/autofill/card_unmask_prompt_view_android.cc",
"android/autofill/card_unmask_prompt_view_android.h", "android/autofill/card_unmask_prompt_view_android.h",
"android/autofill/credit_card_scanner_view_android.cc", "android/autofill/credit_card_scanner_view_android.cc",
......
// 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 "chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h"
#include "chrome/browser/android/resource_mapper.h"
#include "components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h"
#include "content/public/browser/web_contents.h"
#include "jni/AutofillNameFixFlowBridge_jni.h"
#include "ui/android/view_android.h"
#include "ui/android/window_android.h"
using base::android::JavaParamRef;
using base::android::ScopedJavaLocalRef;
namespace autofill {
CardNameFixFlowViewAndroid::CardNameFixFlowViewAndroid(
std::unique_ptr<CardNameFixFlowViewDelegateMobile> delegate,
content::WebContents* web_contents)
: delegate_(std::move(delegate)), web_contents_(web_contents) {}
CardNameFixFlowViewAndroid::~CardNameFixFlowViewAndroid() {
JNIEnv* env = base::android::AttachCurrentThread();
Java_AutofillNameFixFlowBridge_dismiss(env, java_object_);
}
void CardNameFixFlowViewAndroid::Show() {
JNIEnv* env = base::android::AttachCurrentThread();
ui::ViewAndroid* view_android = web_contents_->GetNativeView();
ScopedJavaLocalRef<jstring> dialog_title =
base::android::ConvertUTF16ToJavaString(env, delegate_->GetTitleText());
ScopedJavaLocalRef<jstring> inferred_name =
base::android::ConvertUTF16ToJavaString(
env, delegate_->GetInferredCardHolderName());
ScopedJavaLocalRef<jstring> confirm = base::android::ConvertUTF16ToJavaString(
env, delegate_->GetSaveButtonLabel());
java_object_.Reset(Java_AutofillNameFixFlowBridge_create(
env, reinterpret_cast<intptr_t>(this), dialog_title, inferred_name,
confirm, ResourceMapper::MapFromChromiumId(delegate_->GetIconId()),
view_android->GetWindowAndroid()->GetJavaObject()));
for (const auto& line : delegate_->GetLegalMessageLines()) {
Java_AutofillNameFixFlowBridge_addLegalMessageLine(
env, java_object_,
base::android::ConvertUTF16ToJavaString(env, line.text()));
for (const auto& link : line.links()) {
Java_AutofillNameFixFlowBridge_addLinkToLastLegalMessageLine(
env, java_object_, link.range.start(), link.range.end(),
base::android::ConvertUTF8ToJavaString(env, link.url.spec()));
}
}
Java_AutofillNameFixFlowBridge_show(
env, java_object_, view_android->GetWindowAndroid()->GetJavaObject());
}
void CardNameFixFlowViewAndroid::OnUserAccept(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& name) {
delegate_->Accept(base::android::ConvertJavaStringToUTF16(env, name));
Java_AutofillNameFixFlowBridge_dismiss(env, java_object_);
}
void CardNameFixFlowViewAndroid::PromptDismissed(
JNIEnv* env,
const JavaParamRef<jobject>& obj) {
delete this;
}
void CardNameFixFlowViewAndroid::OnLegalMessageLinkClicked(
JNIEnv* env,
const JavaParamRef<jobject>& obj,
const JavaParamRef<jstring>& url) {
web_contents_->OpenURL(content::OpenURLParams(
GURL(base::android::ConvertJavaStringToUTF16(env, url)),
content::Referrer(), WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui::PAGE_TRANSITION_AUTO_TOPLEVEL, /*is_renderer_initiated=*/false));
}
} // namespace autofill
// 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.
#ifndef CHROME_BROWSER_UI_ANDROID_AUTOFILL_CARD_NAME_FIX_FLOW_VIEW_ANDROID_H_
#define CHROME_BROWSER_UI_ANDROID_AUTOFILL_CARD_NAME_FIX_FLOW_VIEW_ANDROID_H_
#include <jni.h>
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
#include "base/macros.h"
#include "base/strings/string16.h"
namespace content {
class WebContents;
}
namespace autofill {
class CardNameFixFlowViewDelegateMobile;
class CardNameFixFlowViewAndroid {
public:
CardNameFixFlowViewAndroid(
std::unique_ptr<CardNameFixFlowViewDelegateMobile> delegate,
content::WebContents* web_contents);
~CardNameFixFlowViewAndroid();
void OnUserAccept(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jstring>& name);
void PromptDismissed(JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj);
void OnLegalMessageLinkClicked(
JNIEnv* env,
const base::android::JavaParamRef<jobject>& obj,
const base::android::JavaParamRef<jstring>& url);
void Show();
private:
// The corresponding java object.
base::android::ScopedJavaGlobalRef<jobject> java_object_;
std::unique_ptr<CardNameFixFlowViewDelegateMobile> delegate_;
content::WebContents* web_contents_;
DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowViewAndroid);
};
} // namespace autofill
#endif // CHROME_BROWSER_UI_ANDROID_AUTOFILL_CARD_NAME_FIX_FLOW_VIEW_ANDROID_H_
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include "base/command_line.h" #include "base/command_line.h"
#include "base/feature_list.h" #include "base/feature_list.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/autofill/address_normalizer_factory.h" #include "chrome/browser/autofill/address_normalizer_factory.h"
#include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/autofill/personal_data_manager_factory.h"
#include "chrome/browser/autofill/risk_util.h" #include "chrome/browser/autofill/risk_util.h"
...@@ -18,7 +19,9 @@ ...@@ -18,7 +19,9 @@
#include "chrome/browser/password_manager/chrome_password_manager_client.h" #include "chrome/browser/password_manager/chrome_password_manager_client.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/signin/account_tracker_service_factory.h"
#include "chrome/browser/signin/identity_manager_factory.h" #include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/signin/signin_manager_factory.h"
#include "chrome/browser/signin/signin_promo_util.h" #include "chrome/browser/signin/signin_promo_util.h"
#include "chrome/browser/ssl/insecure_sensitive_input_driver_factory.h" #include "chrome/browser/ssl/insecure_sensitive_input_driver_factory.h"
#include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/browser/ssl/security_state_tab_helper.h"
...@@ -49,7 +52,12 @@ ...@@ -49,7 +52,12 @@
#include "components/password_manager/core/browser/password_manager_metrics_util.h" #include "components/password_manager/core/browser/password_manager_metrics_util.h"
#include "components/password_manager/core/browser/password_requirements_service.h" #include "components/password_manager/core/browser/password_requirements_service.h"
#include "components/prefs/pref_service.h" #include "components/prefs/pref_service.h"
#include "components/signin/core/browser/account_info.h"
#include "components/signin/core/browser/account_tracker_service.h"
#include "components/signin/core/browser/signin_buildflags.h"
#include "components/signin/core/browser/signin_header_helper.h" #include "components/signin/core/browser/signin_header_helper.h"
#include "components/signin/core/browser/signin_manager.h"
#include "components/signin/core/browser/signin_manager_base.h"
#include "components/signin/core/browser/signin_metrics.h" #include "components/signin/core/browser/signin_metrics.h"
#include "components/ukm/content/source_url_recorder.h" #include "components/ukm/content/source_url_recorder.h"
#include "components/user_prefs/user_prefs.h" #include "components/user_prefs/user_prefs.h"
...@@ -64,10 +72,12 @@ ...@@ -64,10 +72,12 @@
#include "chrome/browser/android/signin/signin_promo_util_android.h" #include "chrome/browser/android/signin/signin_promo_util_android.h"
#include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/infobars/infobar_service.h"
#include "chrome/browser/ui/android/autofill/autofill_logger_android.h" #include "chrome/browser/ui/android/autofill/autofill_logger_android.h"
#include "chrome/browser/ui/android/autofill/card_name_fix_flow_view_android.h"
#include "chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h" #include "chrome/browser/ui/android/infobars/autofill_credit_card_filling_infobar.h"
#include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h" #include "components/autofill/core/browser/autofill_credit_card_filling_infobar_delegate_mobile.h"
#include "components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h" #include "components/autofill/core/browser/autofill_save_card_infobar_delegate_mobile.h"
#include "components/autofill/core/browser/autofill_save_card_infobar_mobile.h" #include "components/autofill/core/browser/autofill_save_card_infobar_mobile.h"
#include "components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h"
#include "components/infobars/core/infobar.h" #include "components/infobars/core/infobar.h"
#include "ui/android/window_android.h" #include "ui/android/window_android.h"
#else // !OS_ANDROID #else // !OS_ANDROID
...@@ -301,8 +311,8 @@ void ChromeAutofillClient::ConfirmSaveCreditCardLocally( ...@@ -301,8 +311,8 @@ void ChromeAutofillClient::ConfirmSaveCreditCardLocally(
InfoBarService::FromWebContents(web_contents()) InfoBarService::FromWebContents(web_contents())
->AddInfoBar(CreateSaveCardInfoBarMobile( ->AddInfoBar(CreateSaveCardInfoBarMobile(
std::make_unique<AutofillSaveCardInfoBarDelegateMobile>( std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
false, card, std::unique_ptr<base::DictionaryValue>(nullptr), /*upload=*/false, /*should_request_name_from_user=*/false, card,
GetStrikeDatabase(), std::make_unique<base::DictionaryValue>(), GetStrikeDatabase(),
/*upload_save_card_callback=*/ /*upload_save_card_callback=*/
UserAcceptedUploadCallback(), UserAcceptedUploadCallback(),
/*local_save_card_callback=*/std::move(callback), GetPrefs()))); /*local_save_card_callback=*/std::move(callback), GetPrefs())));
...@@ -316,6 +326,23 @@ void ChromeAutofillClient::ConfirmSaveCreditCardLocally( ...@@ -316,6 +326,23 @@ void ChromeAutofillClient::ConfirmSaveCreditCardLocally(
#endif #endif
} }
#if defined(OS_ANDROID)
void ChromeAutofillClient::ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) {
std::unique_ptr<CardNameFixFlowViewDelegateMobile>
card_name_fix_flow_view_delegate_mobile =
std::make_unique<CardNameFixFlowViewDelegateMobile>(
GetAccountHolderName(), std::move(legal_message),
/*upload_save_card_callback=*/std::move(callback));
card_name_fix_flow_view_android_ =
std::make_unique<CardNameFixFlowViewAndroid>(
std::move(card_name_fix_flow_view_delegate_mobile), web_contents());
card_name_fix_flow_view_android_->Show();
}
#endif
void ChromeAutofillClient::ConfirmSaveCreditCardToCloud( void ChromeAutofillClient::ConfirmSaveCreditCardToCloud(
const CreditCard& card, const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
...@@ -328,7 +355,8 @@ void ChromeAutofillClient::ConfirmSaveCreditCardToCloud( ...@@ -328,7 +355,8 @@ void ChromeAutofillClient::ConfirmSaveCreditCardToCloud(
std::unique_ptr<AutofillSaveCardInfoBarDelegateMobile> std::unique_ptr<AutofillSaveCardInfoBarDelegateMobile>
save_card_info_bar_delegate_mobile = save_card_info_bar_delegate_mobile =
std::make_unique<AutofillSaveCardInfoBarDelegateMobile>( std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
true, card, std::move(legal_message), GetStrikeDatabase(), /*upload=*/true, should_request_name_from_user, card,
std::move(legal_message), GetStrikeDatabase(),
/*upload_save_card_callback=*/std::move(callback), /*upload_save_card_callback=*/std::move(callback),
/*local_save_card_callback=*/base::Closure(), GetPrefs()); /*local_save_card_callback=*/base::Closure(), GetPrefs());
if (save_card_info_bar_delegate_mobile->LegalMessagesParsedSuccessfully()) { if (save_card_info_bar_delegate_mobile->LegalMessagesParsedSuccessfully()) {
...@@ -533,4 +561,25 @@ void ChromeAutofillClient::ExecuteCommand(int id) { ...@@ -533,4 +561,25 @@ void ChromeAutofillClient::ExecuteCommand(int id) {
} }
} }
Profile* ChromeAutofillClient::GetProfile() const {
if (!web_contents())
return nullptr;
return Profile::FromBrowserContext(web_contents()->GetBrowserContext());
}
base::string16 ChromeAutofillClient::GetAccountHolderName() {
Profile* profile = GetProfile();
if (!profile)
return base::string16();
SigninManagerBase* signin_manager =
SigninManagerFactory::GetForProfile(profile);
AccountTrackerService* account_tracker =
AccountTrackerServiceFactory::GetForProfile(profile);
if (!signin_manager || !account_tracker)
return base::string16();
AccountInfo account_info = account_tracker->GetAccountInfo(
signin_manager->GetAuthenticatedAccountId());
return base::UTF8ToUTF16(account_info.full_name);
}
} // namespace autofill } // namespace autofill
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "build/build_config.h" #include "build/build_config.h"
#include "chrome/browser/profiles/profile.h"
#include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h" #include "components/autofill/core/browser/ui/card_unmask_prompt_controller_impl.h"
#include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_observer.h"
...@@ -34,6 +35,7 @@ class WebContents; ...@@ -34,6 +35,7 @@ class WebContents;
namespace autofill { namespace autofill {
class AutofillPopupControllerImpl; class AutofillPopupControllerImpl;
class CardNameFixFlowViewAndroid;
// Chrome implementation of AutofillClient. // Chrome implementation of AutofillClient.
class ChromeAutofillClient class ChromeAutofillClient
...@@ -87,6 +89,12 @@ class ChromeAutofillClient ...@@ -87,6 +89,12 @@ class ChromeAutofillClient
bool should_request_expiration_date_from_user, bool should_request_expiration_date_from_user,
bool show_prompt, bool show_prompt,
UserAcceptedUploadCallback callback) override; UserAcceptedUploadCallback callback) override;
#if defined(OS_ANDROID)
void ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) override;
#endif // defined(OS_ANDROID)
void ConfirmCreditCardFillAssist(const CreditCard& card, void ConfirmCreditCardFillAssist(const CreditCard& card,
const base::Closure& callback) override; const base::Closure& callback) override;
void LoadRiskData( void LoadRiskData(
...@@ -138,11 +146,18 @@ class ChromeAutofillClient ...@@ -138,11 +146,18 @@ class ChromeAutofillClient
void ShowHttpNotSecureExplanation(); void ShowHttpNotSecureExplanation();
Profile* GetProfile() const;
base::string16 GetAccountHolderName();
std::unique_ptr<payments::PaymentsClient> payments_client_; std::unique_ptr<payments::PaymentsClient> payments_client_;
std::unique_ptr<FormDataImporter> form_data_importer_; std::unique_ptr<FormDataImporter> form_data_importer_;
base::WeakPtr<AutofillPopupControllerImpl> popup_controller_; base::WeakPtr<AutofillPopupControllerImpl> popup_controller_;
CardUnmaskPromptControllerImpl unmask_controller_; CardUnmaskPromptControllerImpl unmask_controller_;
#if defined(OS_ANDROID)
std::unique_ptr<CardNameFixFlowViewAndroid> card_name_fix_flow_view_android_;
#endif // defined(OS_ANDROID)
DISALLOW_COPY_AND_ASSIGN(ChromeAutofillClient); DISALLOW_COPY_AND_ASSIGN(ChromeAutofillClient);
}; };
......
...@@ -231,6 +231,8 @@ jumbo_static_library("browser") { ...@@ -231,6 +231,8 @@ jumbo_static_library("browser") {
"autofill_save_card_infobar_delegate_mobile.cc", "autofill_save_card_infobar_delegate_mobile.cc",
"autofill_save_card_infobar_delegate_mobile.h", "autofill_save_card_infobar_delegate_mobile.h",
"autofill_save_card_infobar_mobile.h", "autofill_save_card_infobar_mobile.h",
"ui/card_name_fix_flow_view_delegate_mobile.cc",
"ui/card_name_fix_flow_view_delegate_mobile.h",
] ]
} }
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/memory/weak_ptr.h" #include "base/memory/weak_ptr.h"
#include "base/strings/string16.h" #include "base/strings/string16.h"
#include "base/values.h" #include "base/values.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/risk_data_loader.h" #include "components/autofill/core/browser/risk_data_loader.h"
#include "components/security_state/core/security_state.h" #include "components/security_state/core/security_state.h"
#include "services/metrics/public/cpp/ukm_source_id.h" #include "services/metrics/public/cpp/ukm_source_id.h"
...@@ -197,6 +198,14 @@ class AutofillClient : public RiskDataLoader { ...@@ -197,6 +198,14 @@ class AutofillClient : public RiskDataLoader {
bool show_prompt, bool show_prompt,
base::OnceClosure callback) = 0; base::OnceClosure callback) = 0;
#if defined(OS_ANDROID)
// Run |callback| if the card should be uploaded to payments with updated
// name from the user. Displays the contents of |legal_message| to the user.
virtual void ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) = 0;
#endif // defined(OS_ANDROID)
// Runs |callback| if the |card| should be uploaded to Payments. Displays the // Runs |callback| if the |card| should be uploaded to Payments. Displays the
// contents of |legal_message| to the user. Displays a cardholder name // contents of |legal_message| to the user. Displays a cardholder name
// textfield in the bubble if |should_request_name_from_user| is true. // textfield in the bubble if |should_request_name_from_user| is true.
......
...@@ -29,6 +29,7 @@ namespace autofill { ...@@ -29,6 +29,7 @@ namespace autofill {
AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile(
bool upload, bool upload,
bool should_request_name_from_user,
const CreditCard& card, const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
StrikeDatabase* strike_database, StrikeDatabase* strike_database,
...@@ -37,6 +38,7 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( ...@@ -37,6 +38,7 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile(
PrefService* pref_service) PrefService* pref_service)
: ConfirmInfoBarDelegate(), : ConfirmInfoBarDelegate(),
upload_(upload), upload_(upload),
should_request_name_from_user_(should_request_name_from_user),
upload_save_card_callback_(std::move(upload_save_card_callback)), upload_save_card_callback_(std::move(upload_save_card_callback)),
local_save_card_callback_(std::move(local_save_card_callback)), local_save_card_callback_(std::move(local_save_card_callback)),
pref_service_(pref_service), pref_service_(pref_service),
...@@ -54,7 +56,7 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile( ...@@ -54,7 +56,7 @@ AutofillSaveCardInfoBarDelegateMobile::AutofillSaveCardInfoBarDelegateMobile(
DCHECK(upload_save_card_callback_.is_null()); DCHECK(upload_save_card_callback_.is_null());
DCHECK(!local_save_card_callback_.is_null()); DCHECK(!local_save_card_callback_.is_null());
} }
if (legal_message) { if (legal_message && !should_request_name_from_user) {
if (!LegalMessageLine::Parse(*legal_message, &legal_messages_, if (!LegalMessageLine::Parse(*legal_message, &legal_messages_,
/*escape_apostrophes=*/true)) { /*escape_apostrophes=*/true)) {
AutofillMetrics::LogCreditCardInfoBarMetric( AutofillMetrics::LogCreditCardInfoBarMetric(
...@@ -94,8 +96,8 @@ void AutofillSaveCardInfoBarDelegateMobile::OnLegalMessageLinkClicked( ...@@ -94,8 +96,8 @@ void AutofillSaveCardInfoBarDelegateMobile::OnLegalMessageLinkClicked(
bool AutofillSaveCardInfoBarDelegateMobile::LegalMessagesParsedSuccessfully() { bool AutofillSaveCardInfoBarDelegateMobile::LegalMessagesParsedSuccessfully() {
// If we are uploading to the server, verify that legal lines have been parsed // If we are uploading to the server, verify that legal lines have been parsed
// into |legal_messages_|. // into |legal_messages_| unless |should_request_name_from_user_| is enabled.
return !upload_ || !legal_messages_.empty(); return !upload_ || !legal_messages_.empty() || should_request_name_from_user_;
} }
bool AutofillSaveCardInfoBarDelegateMobile::IsGooglePayBrandingEnabled() const { bool AutofillSaveCardInfoBarDelegateMobile::IsGooglePayBrandingEnabled() const {
...@@ -169,7 +171,9 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetButtonLabel( ...@@ -169,7 +171,9 @@ base::string16 AutofillSaveCardInfoBarDelegateMobile::GetButtonLabel(
return base::string16(); return base::string16();
} }
return l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT); return should_request_name_from_user_
? l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_NEXT)
: l10n_util::GetStringUTF16(IDS_AUTOFILL_SAVE_CARD_PROMPT_ACCEPT);
} }
bool AutofillSaveCardInfoBarDelegateMobile::Accept() { bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
...@@ -177,6 +181,7 @@ bool AutofillSaveCardInfoBarDelegateMobile::Accept() { ...@@ -177,6 +181,7 @@ bool AutofillSaveCardInfoBarDelegateMobile::Accept() {
std::move(upload_save_card_callback_).Run({}); std::move(upload_save_card_callback_).Run({});
else else
std::move(local_save_card_callback_).Run(); std::move(local_save_card_callback_).Run();
LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED); LogUserAction(AutofillMetrics::INFOBAR_ACCEPTED);
return true; return true;
} }
......
...@@ -32,6 +32,7 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { ...@@ -32,6 +32,7 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
public: public:
AutofillSaveCardInfoBarDelegateMobile( AutofillSaveCardInfoBarDelegateMobile(
bool upload, bool upload,
bool should_request_name_from_user,
const CreditCard& card, const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
StrikeDatabase* strike_database, StrikeDatabase* strike_database,
...@@ -77,6 +78,9 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate { ...@@ -77,6 +78,9 @@ class AutofillSaveCardInfoBarDelegateMobile : public ConfirmInfoBarDelegate {
// Whether the action is an upload or a local save. // Whether the action is an upload or a local save.
bool upload_; bool upload_;
// Whether the user should enter/confirm cardholder name.
bool should_request_name_from_user_;
// The callback to save the credit card to Google Payments if |upload_| is // The callback to save the credit card to Google Payments if |upload_| is
// true and the user accepts the infobar. // true and the user accepts the infobar.
AutofillClient::UserAcceptedUploadCallback upload_save_card_callback_; AutofillClient::UserAcceptedUploadCallback upload_save_card_callback_;
......
...@@ -432,8 +432,21 @@ void CreditCardSaveManager::OfferCardUploadSave() { ...@@ -432,8 +432,21 @@ void CreditCardSaveManager::OfferCardUploadSave() {
// should not display the offer-to-save infobar at all. // should not display the offer-to-save infobar at all.
if (!is_mobile_build || show_save_prompt_.value()) { if (!is_mobile_build || show_save_prompt_.value()) {
user_did_accept_upload_prompt_ = false; user_did_accept_upload_prompt_ = false;
// legal_message_ ownership is always handled out to chrome autofill client
// and eventually to UI classes. In Android, cards name fix flows take two
// steps and legal messsage is shown only in second step, hence nullptr is
// sent now.
std::unique_ptr<base::DictionaryValue> legal_message_tmp;
#if defined(OS_ANDROID)
legal_message_tmp =
should_request_name_from_user_ ? nullptr : std::move(legal_message_);
#else
legal_message_tmp = std::move(legal_message_);
#endif // #if defined(OS_ANDROID)
client_->ConfirmSaveCreditCardToCloud( client_->ConfirmSaveCreditCardToCloud(
upload_request_.card, std::move(legal_message_), upload_request_.card, std::move(legal_message_tmp),
should_request_name_from_user_, should_request_name_from_user_,
should_request_expiration_date_from_user_, show_save_prompt_.value(), should_request_expiration_date_from_user_, show_save_prompt_.value(),
base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptUpload, base::BindOnce(&CreditCardSaveManager::OnUserDidAcceptUpload,
...@@ -719,6 +732,35 @@ int CreditCardSaveManager::GetDetectedValues() const { ...@@ -719,6 +732,35 @@ int CreditCardSaveManager::GetDetectedValues() const {
void CreditCardSaveManager::OnUserDidAcceptUpload( void CreditCardSaveManager::OnUserDidAcceptUpload(
const AutofillClient::UserProvidedCardDetails& user_provided_card_details) { const AutofillClient::UserProvidedCardDetails& user_provided_card_details) {
// On Android, requesting cardholder name is a two step flow.
#if defined(OS_ANDROID)
if (should_request_name_from_user_) {
client_->ConfirmAccountNameFixFlow(
std::move(legal_message_),
base::BindOnce(
&CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow,
weak_ptr_factory_.GetWeakPtr()));
} else {
OnUserDidAcceptUploadHelper(user_provided_card_details);
}
#else
OnUserDidAcceptUploadHelper(user_provided_card_details);
#endif
}
#if defined(OS_ANDROID)
void CreditCardSaveManager::OnUserDidAcceptAccountNameFixFlow(
const base::string16& cardholder_name) {
DCHECK(should_request_name_from_user_);
OnUserDidAcceptUploadHelper({cardholder_name,
/*expiration_date_month=*/base::string16(),
/*expiration_date_year=*/base::string16()});
}
#endif
void CreditCardSaveManager::OnUserDidAcceptUploadHelper(
const AutofillClient::UserProvidedCardDetails& user_provided_card_details) {
// If cardholder name was explicitly requested for the user to enter/confirm, // If cardholder name was explicitly requested for the user to enter/confirm,
// replace the name on |upload_request_.card| with the entered name. (Note // replace the name on |upload_request_.card| with the entered name. (Note
// that it is possible a name already existed on the card if conflicting names // that it is possible a name already existed on the card if conflicting names
...@@ -729,6 +771,7 @@ void CreditCardSaveManager::OnUserDidAcceptUpload( ...@@ -729,6 +771,7 @@ void CreditCardSaveManager::OnUserDidAcceptUpload(
user_provided_card_details.cardholder_name, user_provided_card_details.cardholder_name,
app_locale_); app_locale_);
} }
user_did_accept_upload_prompt_ = true; user_did_accept_upload_prompt_ = true;
// If expiration date was explicitly requested for the user to select, replace // If expiration date was explicitly requested for the user to select, replace
// the expiration date on |upload_request_.card| with the selected date. // the expiration date on |upload_request_.card| with the selected date.
......
...@@ -181,6 +181,22 @@ class CreditCardSaveManager { ...@@ -181,6 +181,22 @@ class CreditCardSaveManager {
// |user_provided_card_details.expiration_date_year| are both set. // |user_provided_card_details.expiration_date_year| are both set.
void OnUserDidAcceptUpload(const AutofillClient::UserProvidedCardDetails& void OnUserDidAcceptUpload(const AutofillClient::UserProvidedCardDetails&
user_provided_card_details); user_provided_card_details);
#if defined(OS_ANDROID)
// Sets |user_did_accept_upload_prompt_| and calls SendUploadCardRequest if
// the risk data is available. Sets the cardholder name on the upload request
// if |cardholder_name| is set.
// Only relevant for mobile as fix flow is two steps on mobile compared to
// one step on desktop.
void OnUserDidAcceptAccountNameFixFlow(const base::string16& cardholder_name);
#endif // defined(OS_ANDROID)
// Helper function that calls SendUploadCardRequest by setting
// UserProvidedCardDetails.
void OnUserDidAcceptUploadHelper(
const AutofillClient::UserProvidedCardDetails&
user_provided_card_details);
// Saves risk data in |uploading_risk_data_| and calls SendUploadCardRequest // Saves risk data in |uploading_risk_data_| and calls SendUploadCardRequest
// if the user has accepted the prompt. // if the user has accepted the prompt.
void OnDidGetUploadRiskData(const std::string& risk_data); void OnDidGetUploadRiskData(const std::string& risk_data);
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "components/autofill/core/browser/test_autofill_client.h" #include "components/autofill/core/browser/test_autofill_client.h"
#include "base/strings/utf_string_conversions.h"
#include "components/autofill/core/browser/autofill_metrics.h" #include "components/autofill/core/browser/autofill_metrics.h"
#include "components/autofill/core/browser/local_card_migration_manager.h" #include "components/autofill/core/browser/local_card_migration_manager.h"
#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" #include "components/autofill/core/browser/webdata/autofill_webdata_service.h"
...@@ -123,6 +124,15 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally( ...@@ -123,6 +124,15 @@ void TestAutofillClient::ConfirmSaveCreditCardLocally(
std::move(callback).Run(); std::move(callback).Run();
} }
#if defined(OS_ANDROID)
void TestAutofillClient::ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) {
credit_card_name_fix_flow_bubble_was_shown_ = true;
std::move(callback).Run(base::string16(base::ASCIIToUTF16("Gaia Name")));
}
#endif // defined(OS_ANDROID)
void TestAutofillClient::ConfirmSaveCreditCardToCloud( void TestAutofillClient::ConfirmSaveCreditCardToCloud(
const CreditCard& card, const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/compiler_specific.h" #include "base/compiler_specific.h"
#include "base/i18n/rtl.h" #include "base/i18n/rtl.h"
#include "base/macros.h" #include "base/macros.h"
#include "build/build_config.h"
#include "components/autofill/core/browser/autofill_client.h" #include "components/autofill/core/browser/autofill_client.h"
#include "components/autofill/core/browser/payments/test_payments_client.h" #include "components/autofill/core/browser/payments/test_payments_client.h"
#include "components/autofill/core/browser/test_address_normalizer.h" #include "components/autofill/core/browser/test_address_normalizer.h"
...@@ -62,6 +63,12 @@ class TestAutofillClient : public AutofillClient { ...@@ -62,6 +63,12 @@ class TestAutofillClient : public AutofillClient {
void ConfirmSaveCreditCardLocally(const CreditCard& card, void ConfirmSaveCreditCardLocally(const CreditCard& card,
bool show_prompt, bool show_prompt,
base::OnceClosure callback) override; base::OnceClosure callback) override;
#if defined(OS_ANDROID)
void ConfirmAccountNameFixFlow(
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> callback) override;
#endif // defined(OS_ANDROID)
void ConfirmSaveCreditCardToCloud( void ConfirmSaveCreditCardToCloud(
const CreditCard& card, const CreditCard& card,
std::unique_ptr<base::DictionaryValue> legal_message, std::unique_ptr<base::DictionaryValue> legal_message,
...@@ -173,6 +180,10 @@ class TestAutofillClient : public AutofillClient { ...@@ -173,6 +180,10 @@ class TestAutofillClient : public AutofillClient {
// Populated if save was offered. True if bubble was shown, false otherwise. // Populated if save was offered. True if bubble was shown, false otherwise.
base::Optional<bool> offer_to_save_credit_card_bubble_was_shown_; base::Optional<bool> offer_to_save_credit_card_bubble_was_shown_;
// Populated if name fix flow was offered. True if bubble was shown, false
// otherwise.
base::Optional<bool> credit_card_name_fix_flow_bubble_was_shown_;
std::vector<std::string> migration_card_selection_; std::vector<std::string> migration_card_selection_;
DISALLOW_COPY_AND_ASSIGN(TestAutofillClient); DISALLOW_COPY_AND_ASSIGN(TestAutofillClient);
......
// 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 "components/autofill/core/browser/ui/card_name_fix_flow_view_delegate_mobile.h"
#include <utility>
#include "base/logging.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
#include "ui/base/l10n/l10n_util.h"
namespace autofill {
CardNameFixFlowViewDelegateMobile::CardNameFixFlowViewDelegateMobile(
const base::string16& inferred_cardholder_name,
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)> upload_save_card_callback)
: inferred_cardholder_name_(inferred_cardholder_name),
upload_save_card_callback_(std::move(upload_save_card_callback)) {
DCHECK(!upload_save_card_callback_.is_null());
if (legal_message &&
!LegalMessageLine::Parse(*legal_message, &legal_messages_,
/*escape_apostrophes=*/true)) {
return;
}
}
CardNameFixFlowViewDelegateMobile::~CardNameFixFlowViewDelegateMobile() {}
int CardNameFixFlowViewDelegateMobile::GetIconId() const {
return IDR_AUTOFILL_GOOGLE_PAY_WITH_DIVIDER;
}
base::string16 CardNameFixFlowViewDelegateMobile::GetTitleText() const {
return l10n_util::GetStringUTF16(
IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER);
}
base::string16 CardNameFixFlowViewDelegateMobile::GetInferredCardHolderName()
const {
return inferred_cardholder_name_;
}
base::string16 CardNameFixFlowViewDelegateMobile::GetSaveButtonLabel() const {
return l10n_util::GetStringUTF16(IDS_AUTOFILL_NAME_FIX_FLOW_PROMPT_SAVE_CARD);
}
void CardNameFixFlowViewDelegateMobile::Accept(const base::string16& name) {
std::move(upload_save_card_callback_).Run(name);
}
} // namespace autofill
// 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.
#ifndef COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_
#define COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_
#include <memory>
#include "base/callback.h"
#include "base/macros.h"
#include "base/strings/string16.h"
#include "components/autofill/core/browser/legal_message_line.h"
namespace base {
class DictionaryValue;
}
namespace autofill {
// Enables the user to accept or deny cardholder name fix flow prompt.
// Only used on mobile.
class CardNameFixFlowViewDelegateMobile {
public:
CardNameFixFlowViewDelegateMobile(
const base::string16& inferred_cardholder_name,
std::unique_ptr<base::DictionaryValue> legal_message,
base::OnceCallback<void(const base::string16&)>
upload_save_card_callback);
~CardNameFixFlowViewDelegateMobile();
const LegalMessageLines& GetLegalMessageLines() const {
return legal_messages_;
}
int GetIconId() const;
base::string16 GetTitleText() const;
base::string16 GetInferredCardHolderName() const;
base::string16 GetSaveButtonLabel() const;
void Accept(const base::string16& name);
private:
// Inferred cardholder name from Gaia account.
base::string16 inferred_cardholder_name_;
// The callback to save the credit card to Google Payments once user accepts
// fix flow.
base::OnceCallback<void(const base::string16&)> upload_save_card_callback_;
// The legal messages to show in the fix flow.
LegalMessageLines legal_messages_;
DISALLOW_COPY_AND_ASSIGN(CardNameFixFlowViewDelegateMobile);
};
} // namespace autofill
#endif // COMPONENTS_AUTOFILL_CORE_BROWSER_UI_CARD_NAME_FIX_FLOW_VIEW_DELEGATE_MOBILE_H_
...@@ -198,6 +198,9 @@ ...@@ -198,6 +198,9 @@
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar."> <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_LOCAL" desc="Title text for the Autofill save card prompt when the card is to be saved locally. The prompt can be either a bubble or an infobar.">
Save card? Save card?
</message> </message>
<message name="IDS_AUTOFILL_NAME_FIX_FLOW_PROMPT_SAVE_CARD" desc="Text to show for the Autofill save credit card prompt card holder name fix flow button.">
Save card
</message>
<if expr="is_linux and not chromeos"> <if expr="is_linux and not chromeos">
<then> <then>
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar."> <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_TITLE_TO_CLOUD" desc="Title text for the Autofill save card prompt when the card is to be saved by uploading it to Google Payments and also saved locally. The prompt can be either a bubble or an infobar.">
...@@ -243,6 +246,9 @@ ...@@ -243,6 +246,9 @@
<message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP" desc="The tooltip text for the cardholder name textfield."> <message name="IDS_AUTOFILL_SAVE_CARD_PROMPT_CARDHOLDER_NAME_TOOLTIP" desc="The tooltip text for the cardholder name textfield.">
This name is from your Google Account. This name is from your Google Account.
</message> </message>
<message name="IDS_AUTOFILL_SAVE_CARD_CARDHOLDER_NAME_FIX_FLOW_HEADER" desc="Header for the cardholder name fix flow.">
Confirm name
</message>
<!-- Autofill Local card migration bubble or dialog --> <!-- Autofill Local card migration bubble or dialog -->
<if expr="not is_ios and not is_android"> <if expr="not is_ios and not is_android">
......
...@@ -198,8 +198,8 @@ void ChromeAutofillClientIOS::ConfirmSaveCreditCardLocally( ...@@ -198,8 +198,8 @@ void ChromeAutofillClientIOS::ConfirmSaveCreditCardLocally(
DCHECK(show_prompt); DCHECK(show_prompt);
infobar_manager_->AddInfoBar(CreateSaveCardInfoBarMobile( infobar_manager_->AddInfoBar(CreateSaveCardInfoBarMobile(
std::make_unique<AutofillSaveCardInfoBarDelegateMobile>( std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
false, card, std::unique_ptr<base::DictionaryValue>(nullptr), /*upload=*/false, /*should_request_name_from_user=*/false, card,
GetStrikeDatabase(), std::make_unique<base::DictionaryValue>(), GetStrikeDatabase(),
/*upload_save_card_callback=*/UserAcceptedUploadCallback(), /*upload_save_card_callback=*/UserAcceptedUploadCallback(),
/*local_save_card_callback=*/std::move(callback), GetPrefs()))); /*local_save_card_callback=*/std::move(callback), GetPrefs())));
} }
...@@ -232,7 +232,8 @@ void ChromeAutofillClientIOS::ConfirmSaveCreditCardToCloud( ...@@ -232,7 +232,8 @@ void ChromeAutofillClientIOS::ConfirmSaveCreditCardToCloud(
DCHECK(show_prompt); DCHECK(show_prompt);
auto save_card_info_bar_delegate_mobile = auto save_card_info_bar_delegate_mobile =
std::make_unique<AutofillSaveCardInfoBarDelegateMobile>( std::make_unique<AutofillSaveCardInfoBarDelegateMobile>(
true, card, std::move(legal_message), GetStrikeDatabase(), /*upload=*/true, /*should_request_name_from_user=*/false, card,
std::move(legal_message), GetStrikeDatabase(),
/*upload_save_card_callback=*/std::move(callback), /*upload_save_card_callback=*/std::move(callback),
/*local_save_card_callback=*/base::Closure(), GetPrefs()); /*local_save_card_callback=*/base::Closure(), GetPrefs());
// Allow user to save card only if legal messages are successfully parsed. // Allow user to save card only if legal messages are successfully parsed.
......
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