Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / android / autofill / autofill_dialog_controller_android.cc
index 97ea589..e2f8451 100644 (file)
@@ -57,6 +57,42 @@ const char kLastUsedBillingAddressGuid[] = "last_used_billing";
 const char kLastUsedShippingAddressGuid[] = "last_used_shipping";
 const char kLastUsedCreditCardGuid[] = "last_used_card";
 
+// Constructs |inputs| for the SECTION_CC_BILLING section.
+void BuildCcBillingInputs(DetailInputs* inputs) {
+  const DetailInput kCcBillingInputs[] = {
+    { DetailInput::LONG, NAME_BILLING_FULL },
+    { DetailInput::LONG, ADDRESS_BILLING_STREET_ADDRESS },
+    { DetailInput::LONG, ADDRESS_BILLING_CITY },
+    { DetailInput::LONG, ADDRESS_BILLING_DEPENDENT_LOCALITY },
+    { DetailInput::LONG, ADDRESS_BILLING_STATE },
+    { DetailInput::LONG, ADDRESS_BILLING_ZIP },
+    { DetailInput::LONG, ADDRESS_BILLING_SORTING_CODE },
+    { DetailInput::LONG, ADDRESS_BILLING_COUNTRY },
+    { DetailInput::LONG, PHONE_BILLING_WHOLE_NUMBER },
+    { DetailInput::LONG, CREDIT_CARD_NUMBER },
+    { DetailInput::LONG, CREDIT_CARD_EXP_MONTH },
+    { DetailInput::LONG, CREDIT_CARD_EXP_4_DIGIT_YEAR },
+    { DetailInput::LONG, CREDIT_CARD_VERIFICATION_CODE },
+  };
+  common::BuildInputs(kCcBillingInputs, arraysize(kCcBillingInputs), inputs);
+}
+
+// Constructs |inputs| for the SECTION_SHIPPING section.
+void BuildShippingInputs(DetailInputs* inputs) {
+  const DetailInput kShippingInputs[] = {
+    { DetailInput::LONG, NAME_FULL },
+    { DetailInput::LONG, ADDRESS_HOME_STREET_ADDRESS },
+    { DetailInput::LONG, ADDRESS_HOME_CITY },
+    { DetailInput::LONG, ADDRESS_HOME_DEPENDENT_LOCALITY },
+    { DetailInput::LONG, ADDRESS_HOME_STATE },
+    { DetailInput::LONG, ADDRESS_HOME_ZIP },
+    { DetailInput::LONG, ADDRESS_HOME_SORTING_CODE },
+    { DetailInput::LONG, ADDRESS_HOME_COUNTRY },
+    { DetailInput::LONG, PHONE_HOME_WHOLE_NUMBER },
+  };
+  common::BuildInputs(kShippingInputs, arraysize(kShippingInputs), inputs);
+}
+
 base::string16 NullGetInfo(const AutofillType& type) {
   return base::string16();
 }
@@ -90,8 +126,12 @@ void FillOutputForSection(
     FormStructure& form_structure,
     FullWallet* full_wallet,
     const base::string16& email_address) {
+  DCHECK(section == SECTION_CC_BILLING || section == SECTION_SHIPPING);
   DetailInputs inputs;
-  common::BuildInputsForSection(section, "US", &inputs);
+  if (section == SECTION_CC_BILLING)
+    BuildCcBillingInputs(&inputs);
+  else
+    BuildShippingInputs(&inputs);
 
   FillOutputForSectionWithComparator(
       section, inputs,
@@ -142,7 +182,7 @@ base::WeakPtr<AutofillDialogController> AutofillDialogControllerAndroid::Create(
     content::WebContents* contents,
     const FormData& form_structure,
     const GURL& source_url,
-    const base::Callback<void(const FormStructure*)>& callback) {
+    const AutofillManagerDelegate::ResultCallback& callback) {
   // AutofillDialogControllerAndroid owns itself.
   AutofillDialogControllerAndroid* autofill_dialog_controller =
       new AutofillDialogControllerAndroid(contents,
@@ -159,7 +199,7 @@ AutofillDialogController::Create(
     content::WebContents* contents,
     const FormData& form_structure,
     const GURL& source_url,
-    const base::Callback<void(const FormStructure*)>& callback) {
+    const AutofillManagerDelegate::ResultCallback& callback) {
   return AutofillDialogControllerAndroid::Create(contents,
                                                  form_structure,
                                                  source_url,
@@ -190,10 +230,27 @@ void AutofillDialogControllerAndroid::Show() {
   JNIEnv* env = base::android::AttachCurrentThread();
   dialog_shown_timestamp_ = base::Time::Now();
 
+  // The Autofill dialog is shown in response to a message from the renderer and
+  // as such, it can only be made in the context of the current document. A call
+  // to GetActiveEntry would return a pending entry, if there was one, which
+  // would be a security bug. Therefore, we use the last committed URL for the
+  // access checks.
   const GURL& current_url = contents_->GetLastCommittedURL();
   invoked_from_same_origin_ =
       current_url.GetOrigin() == source_url_.GetOrigin();
 
+  // Fail if the dialog factory (e.g. SDK) doesn't support cross-origin calls.
+  if (!Java_AutofillDialogControllerAndroid_isDialogAllowed(
+          env,
+          invoked_from_same_origin_)) {
+    callback_.Run(
+        AutofillManagerDelegate::AutocompleteResultErrorDisabled,
+        base::ASCIIToUTF16("Cross-origin form invocations are not supported."),
+        NULL);
+    delete this;
+    return;
+  }
+
   // Determine what field types should be included in the dialog.
   bool has_types = false;
   bool has_sections = false;
@@ -202,11 +259,32 @@ void AutofillDialogControllerAndroid::Show() {
 
   // Fail if the author didn't specify autocomplete types, or
   // if the dialog shouldn't be shown in a given circumstances.
-  if (!has_types ||
-      !Java_AutofillDialogControllerAndroid_isDialogAllowed(
-          env,
-          invoked_from_same_origin_)) {
-    callback_.Run(NULL);
+  if (!has_types) {
+    callback_.Run(
+        AutofillManagerDelegate::AutocompleteResultErrorDisabled,
+        base::ASCIIToUTF16("Form is missing autocomplete attributes."),
+        NULL);
+    delete this;
+    return;
+  }
+
+  // Fail if the author didn't ask for at least some kind of credit card
+  // information.
+  bool has_credit_card_field = false;
+  for (size_t i = 0; i < form_structure_.field_count(); ++i) {
+    AutofillType type = form_structure_.field(i)->Type();
+    if (type.html_type() != HTML_TYPE_UNKNOWN && type.group() == CREDIT_CARD) {
+      has_credit_card_field = true;
+      break;
+    }
+  }
+
+  if (!has_credit_card_field) {
+    callback_.Run(
+        AutofillManagerDelegate::AutocompleteResultErrorDisabled,
+        base::ASCIIToUTF16("Form is not a payment form (must contain "
+                           "some autocomplete=\"cc-*\" fields). "),
+        NULL);
     delete this;
     return;
   }
@@ -225,10 +303,22 @@ void AutofillDialogControllerAndroid::Show() {
   const ServerFieldType full_billing_is_necessary_if[] = {
       ADDRESS_BILLING_LINE1,
       ADDRESS_BILLING_LINE2,
+      ADDRESS_BILLING_APT_NUM,
       ADDRESS_BILLING_CITY,
       ADDRESS_BILLING_STATE,
+      // ADDRESS_BILLING_ZIP,  // Postal code alone is a short form.
+      ADDRESS_BILLING_COUNTRY,
+      ADDRESS_BILLING_STREET_ADDRESS,
+      ADDRESS_BILLING_DEPENDENT_LOCALITY,
+      ADDRESS_BILLING_SORTING_CODE,
       PHONE_BILLING_WHOLE_NUMBER
   };
+  const ServerFieldType billing_phone_number_is_necessary_if[] = {
+      PHONE_BILLING_WHOLE_NUMBER
+  };
+  const ServerFieldType shipping_phone_number_is_necessary_if[] = {
+      PHONE_HOME_WHOLE_NUMBER
+  };
   const bool request_full_billing_address =
       IsSectionInputsUsedInFormStructure(
           SECTION_BILLING,
@@ -236,19 +326,21 @@ void AutofillDialogControllerAndroid::Show() {
           arraysize(full_billing_is_necessary_if),
           form_structure_);
   const bool request_phone_numbers =
-      IsSectionInputUsedInFormStructure(
+      IsSectionInputsUsedInFormStructure(
           SECTION_BILLING,
-          PHONE_BILLING_WHOLE_NUMBER,
+          billing_phone_number_is_necessary_if,
+          arraysize(billing_phone_number_is_necessary_if),
           form_structure_) ||
-      IsSectionInputUsedInFormStructure(
+      IsSectionInputsUsedInFormStructure(
           SECTION_SHIPPING,
-          PHONE_HOME_WHOLE_NUMBER,
+          shipping_phone_number_is_necessary_if,
+          arraysize(shipping_phone_number_is_necessary_if),
           form_structure_);
 
   bool request_shipping_address = false;
   {
     DetailInputs inputs;
-    common::BuildInputsForSection(SECTION_SHIPPING, "US", &inputs);
+    BuildShippingInputs(&inputs);
     request_shipping_address = form_structure_.FillFields(
         common::TypesFromInputs(inputs),
         base::Bind(common::ServerTypeMatchesField, SECTION_SHIPPING),
@@ -296,6 +388,14 @@ void AutofillDialogControllerAndroid::Show() {
   ScopedJavaLocalRef<jstring> jmerchant_domain =
       base::android::ConvertUTF8ToJavaString(
           env, source_url_.GetOrigin().spec());
+  const std::set<base::string16> availableShippingCountriesSet =
+      form_structure_.PossibleValues(ADDRESS_HOME_COUNTRY);
+  ScopedJavaLocalRef<jobjectArray> jshipping_countries =
+      base::android::ToJavaArrayOfStrings(
+          env,
+          std::vector<base::string16>(availableShippingCountriesSet.begin(),
+                                      availableShippingCountriesSet.end()));
+
   java_object_.Reset(Java_AutofillDialogControllerAndroid_create(
       env,
       reinterpret_cast<intptr_t>(this),
@@ -306,7 +406,8 @@ void AutofillDialogControllerAndroid::Show() {
       last_used_choice_is_autofill, jlast_used_account_name.obj(),
       jlast_used_billing.obj(), jlast_used_shipping.obj(),
       jlast_used_card.obj(),
-      jmerchant_domain.obj()));
+      jmerchant_domain.obj(),
+      jshipping_countries.obj()));
 }
 
 void AutofillDialogControllerAndroid::Hide() {
@@ -324,7 +425,9 @@ bool AutofillDialogControllerAndroid::
 void AutofillDialogControllerAndroid::DialogCancel(JNIEnv* env,
                                                    jobject obj) {
   LogOnCancelMetrics();
-  callback_.Run(NULL);
+  callback_.Run(AutofillManagerDelegate::AutocompleteResultErrorCancel,
+                base::string16(),
+                NULL);
 }
 
 void AutofillDialogControllerAndroid::DialogContinue(
@@ -373,14 +476,16 @@ void AutofillDialogControllerAndroid::DialogContinue(
       if (!last_used_card.empty())
         defaults->SetString(kLastUsedCreditCardGuid, last_used_card);
     } else {
-      LOG(ERROR) << "Failed to save AutofillDialog preferences";
+      DLOG(ERROR) << "Failed to save AutofillDialog preferences";
     }
   }
 
   LogOnFinishSubmitMetrics();
 
   // Callback should be called as late as possible.
-  callback_.Run(&form_structure_);
+  callback_.Run(AutofillManagerDelegate::AutocompleteResultSuccess,
+                base::string16(),
+                &form_structure_);
 
   // This might delete us.
   Hide();
@@ -390,7 +495,7 @@ AutofillDialogControllerAndroid::AutofillDialogControllerAndroid(
     content::WebContents* contents,
     const FormData& form_structure,
     const GURL& source_url,
-    const base::Callback<void(const FormStructure*)>& callback)
+    const AutofillManagerDelegate::ResultCallback& callback)
     : profile_(Profile::FromBrowserContext(contents->GetBrowserContext())),
       contents_(contents),
       initial_user_state_(AutofillMetrics::DIALOG_USER_STATE_UNKNOWN),