diff options
author | rouslan <rouslan@chromium.org> | 2014-11-26 12:30:34 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-26 20:31:41 +0000 |
commit | 497109dae349b8ba88e6abad95f697fbd8f80454 (patch) | |
tree | b185725bc8579987ef4ec444141ddf2d8a7b2a00 | |
parent | 711e0bc408a3123e457006dfb5476da93a3dc592 (diff) | |
download | chromium_src-497109dae349b8ba88e6abad95f697fbd8f80454.zip chromium_src-497109dae349b8ba88e6abad95f697fbd8f80454.tar.gz chromium_src-497109dae349b8ba88e6abad95f697fbd8f80454.tar.bz2 |
[android] Scan new credit card from autofill popup.
This patch adds a "Scan new card" menu item to the autofill popup on
Android. The feature is behind the command line flag:
--enable-credit-card-scan
BUG=428085
Review URL: https://codereview.chromium.org/700623004
Cr-Commit-Position: refs/heads/master@{#305869}
34 files changed, 829 insertions, 127 deletions
diff --git a/android_webview/native/aw_autofill_client.cc b/android_webview/native/aw_autofill_client.cc index 2460088..31c21a8 100644 --- a/android_webview/native/aw_autofill_client.cc +++ b/android_webview/native/aw_autofill_client.cc @@ -187,6 +187,14 @@ void AwAutofillClient::ConfirmSaveCreditCard( NOTIMPLEMENTED(); } +bool AwAutofillClient::HasCreditCardScanFeature() { + return false; +} + +void AwAutofillClient::ScanCreditCard(const CreditCardScanCallback& callback) { + NOTIMPLEMENTED(); +} + void AwAutofillClient::ShowRequestAutocompleteDialog( const autofill::FormData& form, const GURL& source_url, diff --git a/android_webview/native/aw_autofill_client.h b/android_webview/native/aw_autofill_client.h index 372c220..10a2310 100644 --- a/android_webview/native/aw_autofill_client.h +++ b/android_webview/native/aw_autofill_client.h @@ -64,6 +64,8 @@ class AwAutofillClient : public autofill::AutofillClient, virtual void ConfirmSaveCreditCard( const autofill::AutofillMetrics& metric_logger, const base::Closure& save_card_callback) override; + virtual bool HasCreditCardScanFeature() override; + virtual void ScanCreditCard(const CreditCardScanCallback& callback) override; virtual void ShowRequestAutocompleteDialog( const autofill::FormData& form, const GURL& source_url, diff --git a/build/ios/grit_whitelist.txt b/build/ios/grit_whitelist.txt index aa579ce..6fbe58d5 100644 --- a/build/ios/grit_whitelist.txt +++ b/build/ios/grit_whitelist.txt @@ -154,6 +154,7 @@ IDS_AUTOFILL_FIELD_LABEL_PROVINCE IDS_AUTOFILL_FIELD_LABEL_STATE IDS_AUTOFILL_FIELD_LABEL_ZIP_CODE IDS_AUTOFILL_OPTIONS_POPUP +IDS_AUTOFILL_SCAN_CREDIT_CARD IDS_AUTOFILL_WARNING_FORM_DISABLED IDS_AUTOFILL_WARNING_INSECURE_CONNECTION IDS_AUTOLOGIN_INFOBAR_CANCEL_BUTTON diff --git a/chrome/android/java/src/org/chromium/chrome/browser/autofill/CreditCardScanner.java b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CreditCardScanner.java new file mode 100644 index 0000000..b03efca --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/autofill/CreditCardScanner.java @@ -0,0 +1,121 @@ +// Copyright 2014 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 org.chromium.base.CalledByNative; +import org.chromium.base.JNINamespace; +import org.chromium.ui.base.WindowAndroid; + +/** + * Helper for detecting whether the device supports scanning credit cards and for scanning credit + * cards. The default implementation cannot scan cards. An implementing subclass must provide a + * factory that builds its instances. + */ +@JNINamespace("autofill") +public class CreditCardScanner { + /** + * Can be used to build subclasses of the scanner without the user of the class knowing about + * the subclass name. + */ + static Factory sFactory; + + /** + * Pointer to the native object that receives scanning callbacks. + */ + protected long mNativeScanner; + + /** + * Application context. + */ + protected Context mContext; + + /** + * The window that's requesting a scan. + */ + protected WindowAndroid mWindow; + + /** + * Builds instances of credit card scanners. + */ + public interface Factory { + /** + * Builds an instance of credit card scanner. + * @param nativeScanner Pointer to the native object that receives scanning callbacks. + * @param context Application context. + * @param window The window that's requesting a scan. + * @return An object that can scan a credit card. + */ + CreditCardScanner create(long nativeScanner, Context context, WindowAndroid window); + } + + /** + * Sets the factory that can build instances of credit card scanners. + * @param factory Can build instances of credit card scanners. + */ + public static void setFactory(Factory factory) { + sFactory = factory; + } + + /** + * Called by the native object to create an instance of a credit card scanner. + * @param nativeScanner Pointer to the native object that receives scanning callbacks. + * @param context Application context. + * @param window The window that's requesting a scan. + * @return An object that can scan a credit card. + */ + @CalledByNative + private static CreditCardScanner create(long nativeScanner, Context context, + WindowAndroid window) { + return sFactory != null ? sFactory.create(nativeScanner, context, window) + : new CreditCardScanner(nativeScanner, context, window); + } + + /** + * Constructor for the credit card scanner. + * @param nativeScanner Pointer to the native object that receives scanning callbacks. + * @param context Application context. + * @param window The window that's requesting a scan. + */ + protected CreditCardScanner(long nativeScanner, Context context, WindowAndroid window) { + mNativeScanner = nativeScanner; + mContext = context; + mWindow = window; + } + + /** + * Returns true if this instance has the ability to scan credit cards. + * @return True if has ability to scan credit cards. + */ + @CalledByNative + protected boolean canScan() { + return false; + } + + /** + * Scans a credit card. Will invoke a native callback with the result. + */ + @CalledByNative + protected void scan() { + nativeScanCancelled(mNativeScanner); + } + + /** + * Notifies the native object that scanning was cancelled. + * @param nativeCreditCardScannerViewAndroid Pointer to the native object. + */ + protected native void nativeScanCancelled(long nativeCreditCardScannerViewAndroid); + + /** + * Notifies the native object that scanning was successful. + * @param nativeCreditCardScannerViewAndroid Pointer to the native object. + * @param cardNumber Credit card number. + * @param expirationMonth Expiration month in the range [1, 12]. + * @param expirationYear Expiration year, e.g. 2000. + */ + protected native void nativeScanCompleted(long nativeCreditCardScannerViewAndroid, + String cardNumber, int expirationMonth, int expirationYear); +} diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index c5c900a..013df0e 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -14123,6 +14123,14 @@ Do you accept? TLS 1.2 </message> + <!-- Strings for controlling credit card scanning feature in about:flags. --> + <message name="IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_NAME" desc="The name of about:flags option to enable scanning of credit cards using device camera."> + Credit card scanning + </message> + <message name="IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_DESCRIPTION" desc="The description of about:flags option to enable scanning of credit cards using device camera."> + Enable scanning a new credit card number when filling out a credit card form. + </message> + <!-- Simple Cache Backend experiment. --> <message name="IDS_FLAGS_ENABLE_SIMPLE_CACHE_BACKEND_NAME" desc="Name of about:flags option to turn on the Simple Cache Backend"> Simple Cache for HTTP. diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc index f7bbfd3..4d440a0 100644 --- a/chrome/browser/about_flags.cc +++ b/chrome/browser/about_flags.cc @@ -2016,6 +2016,13 @@ const Experiment kExperiments[] = { kOsAll, MULTI_VALUE_TYPE(kSSLVersionMinChoices) }, + { + "enable-credit-card-scan", + IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_NAME, + IDS_FLAGS_ENABLE_CREDIT_CARD_SCAN_DESCRIPTION, + kOsAndroid, + SINGLE_VALUE_TYPE(autofill::switches::kEnableCreditCardScan) + }, // NOTE: Adding new command-line switches requires adding corresponding // entries to enum "LoginCustomFlags" in histograms.xml. See note in // histograms.xml and don't forget to run AboutFlagsHistogramTest unit test. diff --git a/chrome/browser/android/chrome_jni_registrar.cc b/chrome/browser/android/chrome_jni_registrar.cc index bcfcdec..1d033fd 100644 --- a/chrome/browser/android/chrome_jni_registrar.cc +++ b/chrome/browser/android/chrome_jni_registrar.cc @@ -60,6 +60,7 @@ #include "chrome/browser/ui/android/autofill/autofill_dialog_result.h" #include "chrome/browser/ui/android/autofill/autofill_logger_android.h" #include "chrome/browser/ui/android/autofill/autofill_popup_view_android.h" +#include "chrome/browser/ui/android/autofill/credit_card_scanner_view_android.h" #include "chrome/browser/ui/android/autofill/password_generation_popup_view_android.h" #include "chrome/browser/ui/android/chrome_http_auth_handler.h" #include "chrome/browser/ui/android/context_menu_helper.h" @@ -137,6 +138,7 @@ static base::android::RegistrationMethod kChromeRegisteredMethods[] = { { "ConfirmInfoBarDelegate", RegisterConfirmInfoBarDelegate }, { "ContentViewUtil", RegisterContentViewUtil }, { "ContextMenuHelper", RegisterContextMenuHelper }, + { "CreditCardScanner", autofill::CreditCardScannerViewAndroid::Register }, { "DataReductionProxyInfoBarDelegate", DataReductionProxyInfoBar::Register }, { "DataReductionProxySettings", DataReductionProxySettingsAndroid::Register }, { "DevToolsServer", RegisterDevToolsServer }, diff --git a/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc new file mode 100644 index 0000000..7121557 --- /dev/null +++ b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.cc @@ -0,0 +1,73 @@ +// Copyright 2014 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/credit_card_scanner_view_android.h" + +#include "base/android/jni_android.h" +#include "base/android/jni_string.h" +#include "base/memory/scoped_ptr.h" +#include "chrome/browser/ui/android/window_android_helper.h" +#include "chrome/browser/ui/autofill/credit_card_scanner_view_delegate.h" +#include "content/public/browser/android/content_view_core.h" +#include "jni/CreditCardScanner_jni.h" +#include "ui/base/android/view_android.h" +#include "ui/base/android/window_android.h" + +namespace autofill { + +// static +bool CreditCardScannerView::CanShow() { + JNIEnv* env = base::android::AttachCurrentThread(); + base::android::ScopedJavaGlobalRef<jobject> java_object( + Java_CreditCardScanner_create( + env, 0, base::android::GetApplicationContext(), 0)); + return Java_CreditCardScanner_canScan(env, java_object.obj()); +} + +// static +scoped_ptr<CreditCardScannerView> CreditCardScannerView::Create( + const base::WeakPtr<CreditCardScannerViewDelegate>& delegate, + content::WebContents* web_contents) { + return make_scoped_ptr( + new CreditCardScannerViewAndroid(delegate, web_contents)); +} + +// static +bool CreditCardScannerViewAndroid::Register(JNIEnv* env) { + return RegisterNativesImpl(env); +} + +CreditCardScannerViewAndroid::CreditCardScannerViewAndroid( + const base::WeakPtr<CreditCardScannerViewDelegate>& delegate, + content::WebContents* web_contents) + : delegate_(delegate), + java_object_(Java_CreditCardScanner_create( + base::android::AttachCurrentThread(), + reinterpret_cast<intptr_t>(this), + base::android::GetApplicationContext(), + WindowAndroidHelper::FromWebContents(web_contents) + ->GetWindowAndroid()->GetJavaObject().obj())) {} + +CreditCardScannerViewAndroid::~CreditCardScannerViewAndroid() {} + +void CreditCardScannerViewAndroid::ScanCancelled(JNIEnv* env, jobject object) { + delegate_->ScanCancelled(); +} + +void CreditCardScannerViewAndroid::ScanCompleted(JNIEnv* env, + jobject object, + jstring card_number, + jint expiration_month, + jint expiration_year) { + delegate_->ScanCompleted( + base::android::ConvertJavaStringToUTF16(env, card_number), + static_cast<int>(expiration_month), static_cast<int>(expiration_year)); +} + +void CreditCardScannerViewAndroid::Show() { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_CreditCardScanner_scan(env, java_object_.obj()); +} + +} // namespace autofill diff --git a/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.h b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.h new file mode 100644 index 0000000..8bfb3be --- /dev/null +++ b/chrome/browser/ui/android/autofill/credit_card_scanner_view_android.h @@ -0,0 +1,59 @@ +// Copyright 2014 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_CREDIT_CARD_SCANNER_VIEW_ANDROID_H_ +#define CHROME_BROWSER_UI_ANDROID_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_ANDROID_H_ + +#include <jni.h> + +#include "base/android/scoped_java_ref.h" +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "chrome/browser/ui/autofill/credit_card_scanner_view.h" + +namespace content { +class WebContents; +} + +namespace autofill { + +class CreditCardScannerViewDelegate; + +// Android implementation of the view for credit card scanner UI. Uses Android +// APIs through JNI service. +class CreditCardScannerViewAndroid : public CreditCardScannerView { + public: + // Registers with JNI services. + static bool Register(JNIEnv* env); + + CreditCardScannerViewAndroid( + const base::WeakPtr<CreditCardScannerViewDelegate>& delegate, + content::WebContents* web_contents); + ~CreditCardScannerViewAndroid() override; + + // Called by JNI when user cancelled credit card scan. + void ScanCancelled(JNIEnv* env, jobject object); + + // Called by JNI when credit card scan completed successfully. + void ScanCompleted(JNIEnv* env, + jobject object, + jstring card_number, + jint expiration_month, + jint expiration_year); + private: + // CreditCardScannerView implementation. + void Show() override; + + // The object to be notified when scanning was cancelled or completed. + base::WeakPtr<CreditCardScannerViewDelegate> delegate_; + + // The corresponding Java object that uses Android APIs for scanning. + base::android::ScopedJavaGlobalRef<jobject> java_object_; + + DISALLOW_COPY_AND_ASSIGN(CreditCardScannerViewAndroid); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_ANDROID_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_ANDROID_H_ diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.cc b/chrome/browser/ui/autofill/chrome_autofill_client.cc index 41f2aaa..c008944 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.cc +++ b/chrome/browser/ui/autofill/chrome_autofill_client.cc @@ -13,6 +13,7 @@ #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/autofill/autofill_dialog_controller.h" #include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" +#include "chrome/browser/ui/autofill/credit_card_scanner_controller.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_window.h" @@ -113,6 +114,15 @@ void ChromeAutofillClient::ConfirmSaveCreditCard( infobar_service, &metric_logger, save_card_callback); } +bool ChromeAutofillClient::HasCreditCardScanFeature() { + return CreditCardScannerController::HasCreditCardScanFeature(); +} + +void ChromeAutofillClient::ScanCreditCard( + const CreditCardScanCallback& callback) { + CreditCardScannerController::ScanCreditCard(web_contents(), callback); +} + void ChromeAutofillClient::ShowRequestAutocompleteDialog( const FormData& form, const GURL& source_url, diff --git a/chrome/browser/ui/autofill/chrome_autofill_client.h b/chrome/browser/ui/autofill/chrome_autofill_client.h index 323eb5f..09d346a 100644 --- a/chrome/browser/ui/autofill/chrome_autofill_client.h +++ b/chrome/browser/ui/autofill/chrome_autofill_client.h @@ -25,6 +25,7 @@ namespace autofill { class AutofillDialogController; class AutofillKeystoneBridgeWrapper; class AutofillPopupControllerImpl; +class CreditCardScannerController; struct FormData; // Chrome implementation of AutofillClient. @@ -47,6 +48,8 @@ class ChromeAutofillClient void ShowAutofillSettings() override; void ConfirmSaveCreditCard(const AutofillMetrics& metric_logger, const base::Closure& save_card_callback) override; + bool HasCreditCardScanFeature() override; + void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowRequestAutocompleteDialog(const FormData& form, const GURL& source_url, const ResultCallback& callback) override; diff --git a/chrome/browser/ui/autofill/credit_card_scanner_controller.cc b/chrome/browser/ui/autofill/credit_card_scanner_controller.cc new file mode 100644 index 0000000..2d3d0bc --- /dev/null +++ b/chrome/browser/ui/autofill/credit_card_scanner_controller.cc @@ -0,0 +1,76 @@ +// Copyright 2014 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/autofill/credit_card_scanner_controller.h" + +#include "base/callback.h" +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" +#include "chrome/browser/ui/autofill/credit_card_scanner_view.h" +#include "chrome/browser/ui/autofill/credit_card_scanner_view_delegate.h" + +namespace autofill { + +namespace { + +// Controller for the credit card scanner UI. The controller deletes itself +// after the view is dismissed. +class Controller : public CreditCardScannerViewDelegate, + public base::SupportsWeakPtr<Controller> { + public: + Controller(content::WebContents* web_contents, + const AutofillClient::CreditCardScanCallback& callback) + : view_(CreditCardScannerView::Create(AsWeakPtr(), web_contents)), + callback_(callback) { + DCHECK(view_); + } + + // Shows the UI to scan the credit card. + void Show() { + view_->Show(); + } + + private: + ~Controller() {} + + // CreditCardScannerViewDelegate implementation. + void ScanCancelled() override { + delete this; + } + + // CreditCardScannerViewDelegate implementation. + void ScanCompleted(const base::string16& card_number, + int expiration_month, + int expiration_year) override { + callback_.Run(card_number, expiration_month, expiration_year); + delete this; + } + + // The view for the credit card scanner. + scoped_ptr<CreditCardScannerView> view_; + + // The callback to be invoked when scanning completes successfully. + AutofillClient::CreditCardScanCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(Controller); +}; + +} // namespace + +// static +bool CreditCardScannerController::HasCreditCardScanFeature() { + return CreditCardScannerView::CanShow(); +} + +// static +void CreditCardScannerController::ScanCreditCard( + content::WebContents* web_contents, + const AutofillClient::CreditCardScanCallback& callback) { + (new Controller(web_contents, callback))->Show(); +} + +} // namespace autofill diff --git a/chrome/browser/ui/autofill/credit_card_scanner_controller.h b/chrome/browser/ui/autofill/credit_card_scanner_controller.h new file mode 100644 index 0000000..7329f08 --- /dev/null +++ b/chrome/browser/ui/autofill/credit_card_scanner_controller.h @@ -0,0 +1,37 @@ +// Copyright 2014 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_AUTOFILL_CREDIT_CARD_SCANNER_CONTROLLER_H_ +#define CHROME_BROWSER_UI_AUTOFILL_CREDIT_CARD_SCANNER_CONTROLLER_H_ + +#include "components/autofill/core/browser/autofill_client.h" + +namespace content { +class WebContents; +} + +namespace autofill { + +class CreditCardScannerView; + +// Controller for the credit card scanner UI. The controller deletes itself +// after the view is dismissed. +class CreditCardScannerController { + public: + // Returns true if both platform and device support scanning credit cards. The + // platform must have the required APIs. The device must have, e.g., a camera. + static bool HasCreditCardScanFeature(); + + // Shows the UI to scan a credit card. The UI is associated with the + // |web_contents|. Notifies the |delegate| when scanning completes + // successfully. Destroys itself when the UI is dismissed. Should be called + // only if HasCreditCardScanScanFeature() returns true. + static void ScanCreditCard( + content::WebContents* web_contents, + const AutofillClient::CreditCardScanCallback& callback); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_CREDIT_CARD_SCANNER_CONTROLLER_H_ diff --git a/chrome/browser/ui/autofill/credit_card_scanner_view.cc b/chrome/browser/ui/autofill/credit_card_scanner_view.cc new file mode 100644 index 0000000..0f6e5b6 --- /dev/null +++ b/chrome/browser/ui/autofill/credit_card_scanner_view.cc @@ -0,0 +1,24 @@ +// Copyright 2014 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/autofill/credit_card_scanner_view.h" + +namespace autofill { + +// Not implemented on other platforms yet. +#if !defined(OS_ANDROID) +// static +bool CreditCardScannerView::CanShow() { + return false; +} + +// static +scoped_ptr<CreditCardScannerView> CreditCardScannerView::Create( + const base::WeakPtr<CreditCardScannerViewDelegate>& delegate, + content::WebContents* web_contents) { + return scoped_ptr<CreditCardScannerView>(); +} +#endif // !defined(OS_ANDROID) + +} // namespace autofill diff --git a/chrome/browser/ui/autofill/credit_card_scanner_view.h b/chrome/browser/ui/autofill/credit_card_scanner_view.h new file mode 100644 index 0000000..c01e2eb --- /dev/null +++ b/chrome/browser/ui/autofill/credit_card_scanner_view.h @@ -0,0 +1,41 @@ +// Copyright 2014 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_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_H_ +#define CHROME_BROWSER_UI_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_H_ + +#include "base/memory/scoped_ptr.h" +#include "base/memory/weak_ptr.h" + +namespace content { +class WebContents; +} + +namespace autofill { + +class CreditCardScannerViewDelegate; + +// View for the credit card scanner UI. Owned by the controller. +class CreditCardScannerView { + public: + // Returns true if the platform implements the credit card scanner UI and the + // device supports scanning credit cards, e.g., it has a camera. + static bool CanShow(); + + // Creates a view for the credit card scanner UI. The view is associated with + // the |web_contents| and notifies the |delegate| when a scan is cancelled or + // completed. Should be called only if CanShow() returns true. + static scoped_ptr<CreditCardScannerView> Create( + const base::WeakPtr<CreditCardScannerViewDelegate>& delegate, + content::WebContents* web_contents); + + virtual ~CreditCardScannerView() {} + + // Shows the UI for scanning credit cards. + virtual void Show() = 0; +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_H_ diff --git a/chrome/browser/ui/autofill/credit_card_scanner_view_delegate.h b/chrome/browser/ui/autofill/credit_card_scanner_view_delegate.h new file mode 100644 index 0000000..48956d2 --- /dev/null +++ b/chrome/browser/ui/autofill/credit_card_scanner_view_delegate.h @@ -0,0 +1,32 @@ +// Copyright 2014 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_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_DELEGATE_H_ +#define CHROME_BROWSER_UI_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_DELEGATE_H_ + +#include "base/strings/string16.h" +#include "ui/gfx/native_widget_types.h" + +namespace autofill { + +// Receives notifications when credit card scanner UI is dismissed either due to +// user cancelling the scan or successfully completing the scan. +class CreditCardScannerViewDelegate { + public: + // Called when user cancelled the scan. + virtual void ScanCancelled() = 0; + + // Called when the scan completed successfully. + virtual void ScanCompleted(const base::string16& card_number, + int expiration_month, + int expiration_year) = 0; + + protected: + // Destroys the delegate. + virtual ~CreditCardScannerViewDelegate() {} +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_CREDIT_CARD_SCANNER_VIEW_DELEGATE_H_ diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index df5d523..da7a572 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -2749,6 +2749,7 @@ 'android/java/src/org/chromium/chrome/browser/autofill/AutofillDialogResult.java', 'android/java/src/org/chromium/chrome/browser/autofill/AutofillLogger.java', 'android/java/src/org/chromium/chrome/browser/autofill/AutofillPopupBridge.java', + 'android/java/src/org/chromium/chrome/browser/autofill/CreditCardScanner.java', 'android/java/src/org/chromium/chrome/browser/autofill/PasswordGenerationPopupBridge.java', 'android/java/src/org/chromium/chrome/browser/autofill/PersonalDataManager.java', 'android/java/src/org/chromium/chrome/browser/BookmarksBridge.java', diff --git a/chrome/chrome_browser_ui.gypi b/chrome/chrome_browser_ui.gypi index b233c86..331b042e 100644 --- a/chrome/chrome_browser_ui.gypi +++ b/chrome/chrome_browser_ui.gypi @@ -86,6 +86,11 @@ 'browser/ui/autofill/chrome_autofill_client_mac.mm', 'browser/ui/autofill/country_combobox_model.cc', 'browser/ui/autofill/country_combobox_model.h', + 'browser/ui/autofill/credit_card_scanner_controller.cc', + 'browser/ui/autofill/credit_card_scanner_controller.h', + 'browser/ui/autofill/credit_card_scanner_view_delegate.h', + 'browser/ui/autofill/credit_card_scanner_view.cc', + 'browser/ui/autofill/credit_card_scanner_view.h', 'browser/ui/autofill/loading_animation.cc', 'browser/ui/autofill/loading_animation.h', 'browser/ui/autofill/password_generation_popup_controller_impl.cc', @@ -1318,6 +1323,8 @@ 'browser/ui/certificate_dialogs.h', ], 'chrome_browser_ui_android_sources': [ + 'browser/ui/android/autofill/credit_card_scanner_view_android.cc', + 'browser/ui/android/autofill/credit_card_scanner_view_android.h', 'browser/ui/android/infobars/generated_password_saved_infobar.cc', 'browser/ui/android/infobars/generated_password_saved_infobar.h', 'browser/ui/auto_login_infobar_delegate.cc', diff --git a/components/autofill/core/browser/autofill_client.h b/components/autofill/core/browser/autofill_client.h index 28bd59f..452c793 100644 --- a/components/autofill/core/browser/autofill_client.h +++ b/components/autofill/core/browser/autofill_client.h @@ -51,6 +51,10 @@ class AutofillClient { const base::string16&, const FormStructure*)> ResultCallback; + typedef base::Callback<void(const base::string16& /* card number */, + int /* exp month */, + int /* exp year */)> CreditCardScanCallback; + virtual ~AutofillClient() {} // Gets the PersonalDataManager instance associated with the client. @@ -74,6 +78,15 @@ class AutofillClient { const AutofillMetrics& metric_logger, const base::Closure& save_card_callback) = 0; + // Returns true if both the platform and the device support scanning credit + // cards. Should be called before ScanCreditCard(). + virtual bool HasCreditCardScanFeature() = 0; + + // Shows the user interface for scanning a credit card. Invokes the |callback| + // when a credit card is scanned successfully. Should be called only if + // HasCreditCardScanFeature() returns true. + virtual void ScanCreditCard(const CreditCardScanCallback& callback) = 0; + // Causes the dialog for request autocomplete feature to be shown. virtual void ShowRequestAutocompleteDialog( const FormData& form, diff --git a/components/autofill/core/browser/autofill_external_delegate.cc b/components/autofill/core/browser/autofill_external_delegate.cc index eccd75a..82a6d67 100644 --- a/components/autofill/core/browser/autofill_external_delegate.cc +++ b/components/autofill/core/browser/autofill_external_delegate.cc @@ -4,6 +4,7 @@ #include "components/autofill/core/browser/autofill_external_delegate.h" +#include "base/bind.h" #include "base/command_line.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" @@ -107,6 +108,13 @@ void AutofillExternalDelegate::OnSuggestionsReturned( icons.push_back(base::string16()); ids.push_back(POPUP_ITEM_ID_SEPARATOR); + if (manager_->ShouldShowScanCreditCard(query_form_, query_field_)) { + values.push_back(l10n_util::GetStringUTF16(IDS_AUTOFILL_SCAN_CREDIT_CARD)); + labels.push_back(base::string16()); + icons.push_back(base::string16()); + ids.push_back(POPUP_ITEM_ID_SCAN_CREDIT_CARD); + } + // Only include "Autofill Options" special menu item if we have Autofill // suggestions. has_suggestion_ = false; @@ -253,6 +261,9 @@ void AutofillExternalDelegate::DidAcceptSuggestion(const base::string16& value, #else NOTREACHED(); #endif // defined(OS_MACOSX) && !defined(OS_IOS) + } else if (identifier == POPUP_ITEM_ID_SCAN_CREDIT_CARD) { + manager_->client()->ScanCreditCard(base::Bind( + &AutofillExternalDelegate::OnCreditCardScanned, GetWeakPtr())); } else { FillAutofillFormData(identifier, false); } @@ -295,6 +306,15 @@ base::WeakPtr<AutofillExternalDelegate> AutofillExternalDelegate::GetWeakPtr() { return weak_ptr_factory_.GetWeakPtr(); } +void AutofillExternalDelegate::OnCreditCardScanned( + const base::string16& card_number, + int expiration_month, + int expiration_year) { + manager_->FillCreditCardForm( + query_id_, query_form_, query_field_, + CreditCard(card_number, expiration_month, expiration_year)); +} + void AutofillExternalDelegate::FillAutofillFormData(int unique_id, bool is_preview) { // If the selected element is a warning we don't want to do anything. diff --git a/components/autofill/core/browser/autofill_external_delegate.h b/components/autofill/core/browser/autofill_external_delegate.h index 971af23..ed745e0 100644 --- a/components/autofill/core/browser/autofill_external_delegate.h +++ b/components/autofill/core/browser/autofill_external_delegate.h @@ -8,6 +8,7 @@ #include <vector> #include "base/compiler_specific.h" +#include "base/gtest_prod_util.h" #include "base/memory/weak_ptr.h" #include "base/strings/string16.h" #include "components/autofill/core/browser/autofill_popup_delegate.h" @@ -25,8 +26,7 @@ class AutofillManager; // this logic. See http://crbug.com/51644 // Delegate for in-browser Autocomplete and Autofill display and selection. -class AutofillExternalDelegate - : public AutofillPopupDelegate { +class AutofillExternalDelegate : public AutofillPopupDelegate { public: // Creates an AutofillExternalDelegate for the specified AutofillManager and // AutofillDriver. @@ -86,6 +86,14 @@ class AutofillExternalDelegate base::WeakPtr<AutofillExternalDelegate> GetWeakPtr(); private: + FRIEND_TEST_ALL_PREFIXES(AutofillExternalDelegateUnitTest, + FillCreditCardForm); + + // Called when a credit card is scanned using device camera. + void OnCreditCardScanned(const base::string16& card_number, + int expiration_month, + int expiration_year); + // Fills the form with the Autofill data corresponding to |unique_id|. // If |is_preview| is true then this is just a preview to show the user what // would be selected and if |is_preview| is false then the user has selected diff --git a/components/autofill/core/browser/autofill_external_delegate_unittest.cc b/components/autofill/core/browser/autofill_external_delegate_unittest.cc index 4899a10..267bc5f 100644 --- a/components/autofill/core/browser/autofill_external_delegate_unittest.cc +++ b/components/autofill/core/browser/autofill_external_delegate_unittest.cc @@ -55,6 +55,9 @@ class MockAutofillClient : public autofill::TestAutofillClient { public: MockAutofillClient() {} + MOCK_METHOD1(ScanCreditCard, + void(const CreditCardScanCallback& callbacK)); + MOCK_METHOD7(ShowAutofillPopup, void(const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction, @@ -89,6 +92,12 @@ class MockAutofillManager : public AutofillManager { const FormFieldData& field, int unique_id)); + MOCK_METHOD4(FillCreditCardForm, + void(int query_id, + const FormData& form, + const FormFieldData& field, + const CreditCard& credit_card)); + private: DISALLOW_COPY_AND_ASSIGN(MockAutofillManager); }; @@ -429,6 +438,29 @@ TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateClearForm) { POPUP_ITEM_ID_CLEAR_FORM); } +// Test that autofill client will scan a credit card after use accepted the +// suggestion to scan a credit card. +TEST_F(AutofillExternalDelegateUnitTest, ScanCreditCardMenuItem) { + EXPECT_CALL(autofill_client_, ScanCreditCard(_)); + EXPECT_CALL(autofill_client_, HideAutofillPopup()); + external_delegate_->DidAcceptSuggestion(base::string16(), + POPUP_ITEM_ID_SCAN_CREDIT_CARD); +} + +// Test that autofill manager will fill the credit card form after user scans a +// credit card. +TEST_F(AutofillExternalDelegateUnitTest, FillCreditCardForm) { + base::string16 card_number = base::ASCIIToUTF16("test"); + int expiration_month = 1; + int expiration_year = 3000; + EXPECT_CALL( + *autofill_manager_, + FillCreditCardForm( + _, _, _, CreditCard(card_number, expiration_month, expiration_year))); + external_delegate_->OnCreditCardScanned(card_number, expiration_month, + expiration_year); +} + TEST_F(AutofillExternalDelegateUnitTest, ExternalDelegateHideWarning) { CommandLine::ForCurrentProcess()->AppendSwitch( switches::kRespectAutocompleteOffForAutofill); diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc index 63093c9..b1f3ad6 100644 --- a/components/autofill/core/browser/autofill_manager.cc +++ b/components/autofill/core/browser/autofill_manager.cc @@ -30,6 +30,7 @@ #include "components/autofill/core/browser/autofill_profile.h" #include "components/autofill/core/browser/autofill_type.h" #include "components/autofill/core/browser/credit_card.h" +#include "components/autofill/core/browser/field_types.h" #include "components/autofill/core/browser/form_structure.h" #include "components/autofill/core/browser/personal_data_manager.h" #include "components/autofill/core/browser/phone_number.h" @@ -282,19 +283,10 @@ void AutofillManager::ShowAutofillSettings() { bool AutofillManager::ShouldShowAccessAddressBookSuggestion( const FormData& form, const FormFieldData& field) { - if (!personal_data_ || !field.should_autocomplete) - return false; - - FormStructure* form_structure = NULL; - AutofillField* autofill_field = NULL; - if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field)) - return false; - - if (!form_structure->IsAutofillable()) - return false; - - return personal_data_->ShouldShowAccessAddressBookSuggestion( - autofill_field->Type()); + AutofillField* autofill_field = GetAutofillField(form, field); + return autofill_field && + personal_data_->ShouldShowAccessAddressBookSuggestion( + autofill_field->Type()); } bool AutofillManager::AccessAddressBook() { @@ -316,6 +308,21 @@ int AutofillManager::AccessAddressBookPromptCount() { } #endif // defined(OS_MACOSX) && !defined(OS_IOS) +bool AutofillManager::ShouldShowScanCreditCard(const FormData& form, + const FormFieldData& field) { + if (!CommandLine::ForCurrentProcess()->HasSwitch( + autofill::switches::kEnableCreditCardScan)) { + return false; + } + + if (!client_->HasCreditCardScanFeature()) + return false; + + AutofillField* autofill_field = GetAutofillField(form, field); + return autofill_field && + autofill_field->Type().GetStorableType() == CREDIT_CARD_NUMBER; +} + bool AutofillManager::OnFormSubmitted(const FormData& form, const TimeTicks& timestamp) { if (!IsValidFormData(form)) @@ -556,8 +563,6 @@ void AutofillManager::FillOrPreviewForm( const AutofillDataModel* data_model = NULL; size_t variant = 0; - FormStructure* form_structure = NULL; - AutofillField* autofill_field = NULL; bool is_credit_card = false; // NOTE: RefreshDataModels may invalidate |data_model| because it causes the // PersonalDataManager to reload Mac address book entries. Thus it must come @@ -565,119 +570,25 @@ void AutofillManager::FillOrPreviewForm( if (!RefreshDataModels() || !driver_->RendererIsAvailable() || !GetProfileOrCreditCard( - unique_id, &data_model, &variant, &is_credit_card) || - !GetCachedFormAndField(form, field, &form_structure, &autofill_field)) + unique_id, &data_model, &variant, &is_credit_card)) { return; - - DCHECK(form_structure); - DCHECK(autofill_field); - - FormData result = form; - - base::string16 profile_full_name; - std::string profile_language_code; - if (!is_credit_card) { - profile_full_name = data_model->GetInfo( - AutofillType(NAME_FULL), app_locale_); - profile_language_code = - static_cast<const AutofillProfile*>(data_model)->language_code(); } - // If the relevant section is auto-filled, we should fill |field| but not the - // rest of the form. - if (SectionIsAutofilled(*form_structure, form, autofill_field->section())) { - for (std::vector<FormFieldData>::iterator iter = result.fields.begin(); - iter != result.fields.end(); ++iter) { - if (iter->SameFieldAs(field)) { - base::string16 value = data_model->GetInfoForVariant( - autofill_field->Type(), variant, app_locale_); - if (AutofillField::FillFormField(*autofill_field, - value, - profile_language_code, - app_locale_, - &(*iter))) { - // Mark the cached field as autofilled, so that we can detect when a - // user edits an autofilled field (for metrics). - autofill_field->is_autofilled = true; - - // Mark the field as autofilled when a non-empty value is assigned to - // it. This allows the renderer to distinguish autofilled fields from - // fields with non-empty values, such as select-one fields. - iter->is_autofilled = true; - - if (!is_credit_card && !value.empty()) - client_->DidFillOrPreviewField(value, profile_full_name); - } - break; - } - } + FillOrPreviewDataModelForm(action, query_id, form, field, data_model, variant, + is_credit_card); +} - driver_->SendFormDataToRenderer(query_id, action, result); +void AutofillManager::FillCreditCardForm(int query_id, + const FormData& form, + const FormFieldData& field, + const CreditCard& credit_card) { + if (!IsValidFormData(form) || !IsValidFormFieldData(field) || + !driver_->RendererIsAvailable()) { return; } - // Cache the field type for the field from which the user initiated autofill. - FieldTypeGroup initiating_group_type = autofill_field->Type().group(); - DCHECK_EQ(form_structure->field_count(), form.fields.size()); - for (size_t i = 0; i < form_structure->field_count(); ++i) { - if (form_structure->field(i)->section() != autofill_field->section()) - continue; - - DCHECK(form_structure->field(i)->SameFieldAs(result.fields[i])); - - const AutofillField* cached_field = form_structure->field(i); - FieldTypeGroup field_group_type = cached_field->Type().group(); - if (field_group_type != NO_GROUP) { - // If the field being filled is either - // (a) the field that the user initiated the fill from, or - // (b) part of the same logical unit, e.g. name or phone number, - // then take the multi-profile "variant" into account. - // Otherwise fill with the default (zeroth) variant. - size_t use_variant = 0; - if (result.fields[i].SameFieldAs(field) || - field_group_type == initiating_group_type) { - use_variant = variant; - } - base::string16 value = data_model->GetInfoForVariant( - cached_field->Type(), use_variant, app_locale_); - - // Must match ForEachMatchingFormField() in form_autofill_util.cc. - // Only notify autofilling of empty fields and the field that initiated - // the filling (note that "select-one" controls may not be empty but will - // still be autofilled). - bool should_notify = - !is_credit_card && - !value.empty() && - (result.fields[i].SameFieldAs(field) || - result.fields[i].form_control_type == "select-one" || - result.fields[i].value.empty()); - if (AutofillField::FillFormField(*cached_field, - value, - profile_language_code, - app_locale_, - &result.fields[i])) { - // Mark the cached field as autofilled, so that we can detect when a - // user edits an autofilled field (for metrics). - form_structure->field(i)->is_autofilled = true; - - // Mark the field as autofilled when a non-empty value is assigned to - // it. This allows the renderer to distinguish autofilled fields from - // fields with non-empty values, such as select-one fields. - result.fields[i].is_autofilled = true; - - if (should_notify) - client_->DidFillOrPreviewField(value, profile_full_name); - } - } - } - - autofilled_form_signatures_.push_front(form_structure->FormSignature()); - // Only remember the last few forms that we've seen, both to avoid false - // positives and to avoid wasting memory. - if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember) - autofilled_form_signatures_.pop_back(); - - driver_->SendFormDataToRenderer(query_id, action, result); + FillOrPreviewDataModelForm(AutofillDriver::FORM_DATA_ACTION_FILL, query_id, + form, field, &credit_card, 0, true); } void AutofillManager::OnDidPreviewAutofillFormData() { @@ -970,6 +881,130 @@ bool AutofillManager::GetProfileOrCreditCard( return !!*data_model; } +void AutofillManager::FillOrPreviewDataModelForm( + AutofillDriver::RendererFormDataAction action, + int query_id, + const FormData& form, + const FormFieldData& field, + const AutofillDataModel* data_model, + size_t variant, + bool is_credit_card) { + FormStructure* form_structure = NULL; + AutofillField* autofill_field = NULL; + if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field)) + return; + + DCHECK(form_structure); + DCHECK(autofill_field); + + FormData result = form; + + base::string16 profile_full_name; + std::string profile_language_code; + if (!is_credit_card) { + profile_full_name = data_model->GetInfo( + AutofillType(NAME_FULL), app_locale_); + profile_language_code = + static_cast<const AutofillProfile*>(data_model)->language_code(); + } + + // If the relevant section is auto-filled, we should fill |field| but not the + // rest of the form. + if (SectionIsAutofilled(*form_structure, form, autofill_field->section())) { + for (std::vector<FormFieldData>::iterator iter = result.fields.begin(); + iter != result.fields.end(); ++iter) { + if (iter->SameFieldAs(field)) { + base::string16 value = data_model->GetInfoForVariant( + autofill_field->Type(), variant, app_locale_); + if (AutofillField::FillFormField(*autofill_field, + value, + profile_language_code, + app_locale_, + &(*iter))) { + // Mark the cached field as autofilled, so that we can detect when a + // user edits an autofilled field (for metrics). + autofill_field->is_autofilled = true; + + // Mark the field as autofilled when a non-empty value is assigned to + // it. This allows the renderer to distinguish autofilled fields from + // fields with non-empty values, such as select-one fields. + iter->is_autofilled = true; + + if (!is_credit_card && !value.empty()) + client_->DidFillOrPreviewField(value, profile_full_name); + } + break; + } + } + + driver_->SendFormDataToRenderer(query_id, action, result); + return; + } + + // Cache the field type for the field from which the user initiated autofill. + FieldTypeGroup initiating_group_type = autofill_field->Type().group(); + DCHECK_EQ(form_structure->field_count(), form.fields.size()); + for (size_t i = 0; i < form_structure->field_count(); ++i) { + if (form_structure->field(i)->section() != autofill_field->section()) + continue; + + DCHECK(form_structure->field(i)->SameFieldAs(result.fields[i])); + + const AutofillField* cached_field = form_structure->field(i); + FieldTypeGroup field_group_type = cached_field->Type().group(); + if (field_group_type != NO_GROUP) { + // If the field being filled is either + // (a) the field that the user initiated the fill from, or + // (b) part of the same logical unit, e.g. name or phone number, + // then take the multi-profile "variant" into account. + // Otherwise fill with the default (zeroth) variant. + size_t use_variant = 0; + if (result.fields[i].SameFieldAs(field) || + field_group_type == initiating_group_type) { + use_variant = variant; + } + base::string16 value = data_model->GetInfoForVariant( + cached_field->Type(), use_variant, app_locale_); + + // Must match ForEachMatchingFormField() in form_autofill_util.cc. + // Only notify autofilling of empty fields and the field that initiated + // the filling (note that "select-one" controls may not be empty but will + // still be autofilled). + bool should_notify = + !is_credit_card && + !value.empty() && + (result.fields[i].SameFieldAs(field) || + result.fields[i].form_control_type == "select-one" || + result.fields[i].value.empty()); + if (AutofillField::FillFormField(*cached_field, + value, + profile_language_code, + app_locale_, + &result.fields[i])) { + // Mark the cached field as autofilled, so that we can detect when a + // user edits an autofilled field (for metrics). + form_structure->field(i)->is_autofilled = true; + + // Mark the field as autofilled when a non-empty value is assigned to + // it. This allows the renderer to distinguish autofilled fields from + // fields with non-empty values, such as select-one fields. + result.fields[i].is_autofilled = true; + + if (should_notify) + client_->DidFillOrPreviewField(value, profile_full_name); + } + } + } + + autofilled_form_signatures_.push_front(form_structure->FormSignature()); + // Only remember the last few forms that we've seen, both to avoid false + // positives and to avoid wasting memory. + if (autofilled_form_signatures_.size() > kMaxRecentFormSignaturesToRemember) + autofilled_form_signatures_.pop_back(); + + driver_->SendFormDataToRenderer(query_id, action, result); +} + bool AutofillManager::FindCachedForm(const FormData& form, FormStructure** form_structure) const { // Find the FormStructure that corresponds to |form|. @@ -1036,6 +1071,22 @@ bool AutofillManager::GetCachedFormAndField(const FormData& form, return *autofill_field != NULL; } +AutofillField* AutofillManager::GetAutofillField(const FormData& form, + const FormFieldData& field) { + if (!personal_data_ || !field.should_autocomplete) + return NULL; + + FormStructure* form_structure = NULL; + AutofillField* autofill_field = NULL; + if (!GetCachedFormAndField(form, field, &form_structure, &autofill_field)) + return NULL; + + if (!form_structure->IsAutofillable()) + return NULL; + + return autofill_field; +} + bool AutofillManager::UpdateCachedForm(const FormData& live_form, const FormStructure* cached_form, FormStructure** updated_form) { diff --git a/components/autofill/core/browser/autofill_manager.h b/components/autofill/core/browser/autofill_manager.h index 58058c7..326dd8b 100644 --- a/components/autofill/core/browser/autofill_manager.h +++ b/components/autofill/core/browser/autofill_manager.h @@ -81,10 +81,10 @@ class AutofillManager : public AutofillDownloadManager::Observer { void ShowAutofillSettings(); #if defined(OS_MACOSX) && !defined(OS_IOS) - // Whether the field represented by |fieldData| should show an entry to prompt - // the user to give Chrome access to the user's address book. - bool ShouldShowAccessAddressBookSuggestion(const FormData& data, - const FormFieldData& field_data); + // Whether the |field| should show an entry to prompt the user to give Chrome + // access to the user's address book. + bool ShouldShowAccessAddressBookSuggestion(const FormData& form, + const FormFieldData& field); // If Chrome has not prompted for access to the user's address book, the // method prompts the user for permission and blocks the process. Otherwise, @@ -99,12 +99,20 @@ class AutofillManager : public AutofillDownloadManager::Observer { int AccessAddressBookPromptCount(); #endif // defined(OS_MACOSX) && !defined(OS_IOS) + // Whether the |field| should show an entry to scan a credit card. + bool ShouldShowScanCreditCard(const FormData& form, + const FormFieldData& field); + // Called from our external delegate so they cannot be private. virtual void FillOrPreviewForm(AutofillDriver::RendererFormDataAction action, int query_id, const FormData& form, const FormFieldData& field, int unique_id); + virtual void FillCreditCardForm(int query_id, + const FormData& form, + const FormFieldData& field, + const CreditCard& credit_card); void DidShowSuggestions(bool is_new_popup); void OnDidFillAutofillFormData(const base::TimeTicks& timestamp); void OnDidPreviewAutofillFormData(); @@ -229,6 +237,15 @@ class AutofillManager : public AutofillDownloadManager::Observer { size_t* variant, bool* is_credit_card) const WARN_UNUSED_RESULT; + // Fills or previews |data_model| in the |form|. + void FillOrPreviewDataModelForm(AutofillDriver::RendererFormDataAction action, + int query_id, + const FormData& form, + const FormFieldData& field, + const AutofillDataModel* data_model, + size_t variant, + bool is_credit_card); + // Fills |form_structure| cached element corresponding to |form|. // Returns false if the cached element was not found. bool FindCachedForm(const FormData& form, @@ -243,6 +260,12 @@ class AutofillManager : public AutofillDownloadManager::Observer { FormStructure** form_structure, AutofillField** autofill_field) WARN_UNUSED_RESULT; + // Returns the field corresponding to |form| and |field| that can be + // autofilled. Returns NULL if the field cannot be autofilled. + AutofillField* GetAutofillField(const FormData& form, + const FormFieldData& field) + WARN_UNUSED_RESULT; + // Re-parses |live_form| and adds the result to |form_structures_|. // |cached_form| should be a pointer to the existing version of the form, or // NULL if no cached version exists. The updated form is then written into diff --git a/components/autofill/core/browser/credit_card.cc b/components/autofill/core/browser/credit_card.cc index c15b9dc..85c50ed 100644 --- a/components/autofill/core/browser/credit_card.cc +++ b/components/autofill/core/browser/credit_card.cc @@ -118,6 +118,15 @@ CreditCard::CreditCard(const std::string& guid, const std::string& origin) expiration_year_(0) { } +CreditCard::CreditCard(const base::string16& card_number, + int expiration_month, + int expiration_year) + : AutofillDataModel(std::string(), std::string()) { + SetNumber(card_number); + SetExpirationMonth(expiration_month); + SetExpirationYear(expiration_year); +} + CreditCard::CreditCard() : AutofillDataModel(base::GenerateGUID(), std::string()), record_type_(LOCAL_CARD), diff --git a/components/autofill/core/browser/credit_card.h b/components/autofill/core/browser/credit_card.h index 9c38d4a..311d784 100644 --- a/components/autofill/core/browser/credit_card.h +++ b/components/autofill/core/browser/credit_card.h @@ -33,6 +33,9 @@ class CreditCard : public AutofillDataModel { }; CreditCard(const std::string& guid, const std::string& origin); + CreditCard(const base::string16& card_number, + int expiration_month, + int expiration_year); // For use in STL containers. CreditCard(); diff --git a/components/autofill/core/browser/credit_card_unittest.cc b/components/autofill/core/browser/credit_card_unittest.cc index 515b189..3469646 100644 --- a/components/autofill/core/browser/credit_card_unittest.cc +++ b/components/autofill/core/browser/credit_card_unittest.cc @@ -545,4 +545,14 @@ TEST(CreditCardTest, LastFourDigits) { ASSERT_EQ(base::ASCIIToUTF16("489"), card.LastFourDigits()); } +TEST(CreditCardTest, CanBuildFromCardNumberAndExpirationDate) { + base::string16 card_number = base::ASCIIToUTF16("test"); + int month = 1; + int year = 3000; + CreditCard card(card_number, month, year); + EXPECT_EQ(card_number, card.number()); + EXPECT_EQ(month, card.expiration_month()); + EXPECT_EQ(year, card.expiration_year()); +} + } // namespace autofill diff --git a/components/autofill/core/browser/popup_item_ids.h b/components/autofill/core/browser/popup_item_ids.h index 7a8e843..7dd75d8 100644 --- a/components/autofill/core/browser/popup_item_ids.h +++ b/components/autofill/core/browser/popup_item_ids.h @@ -18,6 +18,7 @@ enum PopupItemId { POPUP_ITEM_ID_AUTOFILL_OPTIONS = -5, POPUP_ITEM_ID_DATALIST_ENTRY = -6, POPUP_ITEM_ID_MAC_ACCESS_CONTACTS = -7, + POPUP_ITEM_ID_SCAN_CREDIT_CARD = -8, }; } // namespace autofill diff --git a/components/autofill/core/browser/test_autofill_client.cc b/components/autofill/core/browser/test_autofill_client.cc index 3b73339..6a2b1ae 100644 --- a/components/autofill/core/browser/test_autofill_client.cc +++ b/components/autofill/core/browser/test_autofill_client.cc @@ -36,6 +36,14 @@ void TestAutofillClient::ConfirmSaveCreditCard( const base::Closure& save_card_callback) { } +bool TestAutofillClient::HasCreditCardScanFeature() { + return false; +} + +void TestAutofillClient::ScanCreditCard( + const CreditCardScanCallback& callback) { +} + void TestAutofillClient::ShowRequestAutocompleteDialog( const FormData& form, const GURL& source_url, diff --git a/components/autofill/core/browser/test_autofill_client.h b/components/autofill/core/browser/test_autofill_client.h index 6fc8153..f3d8328 100644 --- a/components/autofill/core/browser/test_autofill_client.h +++ b/components/autofill/core/browser/test_autofill_client.h @@ -27,6 +27,8 @@ class TestAutofillClient : public AutofillClient { void ShowAutofillSettings() override; void ConfirmSaveCreditCard(const AutofillMetrics& metric_logger, const base::Closure& save_card_callback) override; + bool HasCreditCardScanFeature() override; + void ScanCreditCard(const CreditCardScanCallback& callback) override; void ShowRequestAutocompleteDialog(const FormData& form, const GURL& source_url, const ResultCallback& callback) override; diff --git a/components/autofill/core/common/autofill_switches.cc b/components/autofill/core/common/autofill_switches.cc index 7e7a16b..f0120d4 100644 --- a/components/autofill/core/common/autofill_switches.cc +++ b/components/autofill/core/common/autofill_switches.cc @@ -15,6 +15,10 @@ const char kDisablePasswordGeneration[] = "disable-password-generation"; const char kDisambiguateAutofillServerNameTypes[] = "disambiguate-autofill-server-name-types"; +// Enables using device's camera to scan a new credit card when filling out a +// credit card form. +const char kEnableCreditCardScan[] = "enable-credit-card-scan"; + // Enables password generation when we detect that the user is going through // account creation. const char kEnablePasswordGeneration[] = "enable-password-generation"; diff --git a/components/autofill/core/common/autofill_switches.h b/components/autofill/core/common/autofill_switches.h index 69f2e4a..cdf6078 100644 --- a/components/autofill/core/common/autofill_switches.h +++ b/components/autofill/core/common/autofill_switches.h @@ -12,6 +12,7 @@ namespace switches { // alongside the definition of their values in the .cc file. extern const char kDisablePasswordGeneration[]; extern const char kDisambiguateAutofillServerNameTypes[]; +extern const char kEnableCreditCardScan[]; extern const char kEnablePasswordGeneration[]; extern const char kIgnoreAutocompleteOffForAutofill[]; extern const char kLocalHeuristicsOnlyForPasswordGeneration[]; diff --git a/components/autofill_strings.grdp b/components/autofill_strings.grdp index 5a3fd5e..bb95163 100644 --- a/components/autofill_strings.grdp +++ b/components/autofill_strings.grdp @@ -124,4 +124,8 @@ </message> </if> + <message name="IDS_AUTOFILL_SCAN_CREDIT_CARD" desc="An item in the autofill popup that triggers a new credit card to be scanned using the camera on the device."> + Scan new card + </message> + </grit-part> diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index f0229db..95b8cea 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -48913,6 +48913,7 @@ To add a new entry, add it with any value and run test to compute valid value. <int value="887011602" label="enable-spelling-auto-correct"/> <int value="909439558" label="disable-device-discovery"/> <int value="929462705" label="disable-link-disambiguation-popup"/> + <int value="939554480" label="enable-credit-card-scan"/> <int value="952558794" label="enable-remote-assistance"/> <int value="980396200" label="enable-new-korean-ime"/> <int value="1022992701" label="enable-origin-chip-always"/> |