chromium/ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_full_card_requester.mm

// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_full_card_requester.h"

#import <vector>

#import "components/autofill/core/browser/browser_autofill_manager.h"
#import "components/autofill/core/browser/data_model/credit_card.h"
#import "components/autofill/core/browser/payments/credit_card_access_manager.h"
#import "components/autofill/ios/browser/autofill_driver_ios.h"
#import "components/autofill/ios/browser/autofill_java_script_feature.h"
#import "ios/chrome/browser/shared/model/web_state_list/web_state_list.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/full_card_request_result_delegate_bridge.h"
#import "ios/chrome/browser/autofill/ui_bundled/manual_fill/manual_fill_constants.h"
#import "ios/web/public/js_messaging/web_frame.h"
#import "ios/web/public/js_messaging/web_frames_manager.h"
#import "ios/web/public/web_state.h"

using autofill::CreditCard::RecordType::kVirtualCard;

namespace autofill {
class CreditCard;
}  // namespace autofill

@interface ManualFillFullCardRequester ()

// The ChromeBrowserState instance passed to the initializer.
@property(nonatomic, readonly) ChromeBrowserState* browserState;

// The WebStateList for this instance. Used to instantiate the child
// coordinators lazily.
@property(nonatomic, readonly) WebStateList* webStateList;

@end

@implementation ManualFillFullCardRequester {
  // Obj-C delegate to receive the success or failure result, when
  // asking credit card unlocking.
  __weak id<FullCardRequestResultDelegateObserving> _delegate;
}

- (instancetype)initWithBrowserState:(ChromeBrowserState*)browserState
                        webStateList:(WebStateList*)webStateList
                      resultDelegate:
                          (id<FullCardRequestResultDelegateObserving>)delegate {
  self = [super init];
  if (self) {
    _browserState = browserState;
    _webStateList = webStateList;
    _delegate = delegate;
  }
  return self;
}

- (void)requestFullCreditCard:(const autofill::CreditCard)card
       withBaseViewController:(UIViewController*)viewController
                   recordType:(autofill::CreditCard::RecordType)recordType
                    fieldType:(manual_fill::PaymentFieldType)fieldType {
  // Payment Request is only enabled in main frame.
  web::WebState* webState = self.webStateList->GetActiveWebState();
  web::WebFramesManager* frames_manager =
      autofill::AutofillJavaScriptFeature::GetInstance()->GetWebFramesManager(
          webState);
  web::WebFrame* mainFrame = frames_manager->GetMainWebFrame();
  if (!mainFrame) {
    return;
  }
  autofill::BrowserAutofillManager& autofillManager =
      autofill::AutofillDriverIOS::FromWebStateAndWebFrame(webState, mainFrame)
          ->GetAutofillManager();

  autofill::CreditCard virtualCard;
  if (recordType == kVirtualCard) {
    virtualCard = autofill::CreditCard::CreateVirtualCard(card);
  }
  autofill::CreditCardAccessManager& creditCardAccessManager =
      autofillManager.GetCreditCardAccessManager();
  __weak __typeof(self) weakSelf = self;
  creditCardAccessManager.FetchCreditCard(
      (recordType == kVirtualCard ? &virtualCard : &card),
      base::BindOnce(^(autofill::CreditCardFetchResult result,
                       const autofill::CreditCard* fetchedCard) {
        [weakSelf onCreditCardFetched:result
                          fetchedCard:fetchedCard
                            fieldType:fieldType];
      }));

  // TODO(crbug.com/40577448): closing CVC requester doesn't restore icon bar
  // above keyboard.
}

#pragma mark - Private methods

// Callback invoked when the card retrieval is finished. It notifies the
// delegate the result of the card retrieval process and provides the card if
// the process succeeded.
- (void)onCreditCardFetched:(autofill::CreditCardFetchResult)result
                fetchedCard:(const autofill::CreditCard*)fetchedCard
                  fieldType:(manual_fill::PaymentFieldType)fieldType {
  if (result == autofill::CreditCardFetchResult::kSuccess && fetchedCard) {
    [_delegate onFullCardRequestSucceeded:*fetchedCard fieldType:fieldType];
  } else {
    [_delegate onFullCardRequestFailed];
  }
}

@end