blob: 60815687c79ccd6db8e22a19b98628e63139a95a [file] [log] [blame]
// 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.
#import "ios/web_view/internal/autofill/cwv_autofill_data_manager_internal.h"
#include <memory>
#include "base/bind.h"
#include "base/task/post_task.h"
#include "components/autofill/core/browser/personal_data_manager.h"
#include "components/autofill/core/browser/personal_data_manager_observer.h"
#include "components/password_manager/core/browser/password_store_consumer.h"
#include "components/password_manager/core/browser/password_store_impl.h"
#include "ios/web/public/thread/web_task_traits.h"
#include "ios/web/public/thread/web_thread.h"
#import "ios/web_view/internal/autofill/cwv_autofill_profile_internal.h"
#import "ios/web_view/internal/autofill/cwv_credit_card_internal.h"
#import "ios/web_view/internal/passwords/cwv_password_internal.h"
#import "ios/web_view/public/cwv_autofill_data_manager_observer.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
// Typedefs of |completionHandler| in |fetchProfilesWithCompletionHandler:|,
// |fetchCreditCardsWithCompletionHandler:|, and
// |fetchPasswordsWithCompletionHandler|.
typedef void (^CWVFetchProfilesCompletionHandler)(
NSArray<CWVAutofillProfile*>* profiles);
typedef void (^CWVFetchCreditCardsCompletionHandler)(
NSArray<CWVCreditCard*>* creditCards);
typedef void (^CWVFetchPasswordsCompletionHandler)(
NSArray<CWVPassword*>* passwords);
@interface CWVAutofillDataManager ()
// Called when WebViewPasswordStoreConsumer's |OnGetPasswordStoreResults| is
// invoked.
- (void)handlePasswordStoreResults:(NSArray<CWVPassword*>*)passwords;
// Called when WebViewPersonalDataManagerObserverBridge's
// |OnPersonalDataChanged| is invoked.
- (void)personalDataDidChange;
// Collects and converts autofill::AutofillProfiles stored internally in
// |_personalDataManager| to CWVAutofillProfiles.
- (NSArray<CWVAutofillProfile*>*)profiles;
// Collects and converts autofill::CreditCards stored internally in
// |_personalDataManager| to CWVCreditCards.
- (NSArray<CWVCreditCard*>*)creditCards;
@end
namespace ios_web_view {
// C++ to ObjC bridge for PersonalDataManagerObserver.
class WebViewPersonalDataManagerObserverBridge
: public autofill::PersonalDataManagerObserver {
public:
explicit WebViewPersonalDataManagerObserverBridge(
CWVAutofillDataManager* data_manager)
: data_manager_(data_manager) {}
~WebViewPersonalDataManagerObserverBridge() override = default;
// autofill::PersonalDataManagerObserver implementation.
void OnPersonalDataChanged() override {
[data_manager_ personalDataDidChange];
}
void OnInsufficientFormData() override {
// Nop.
}
private:
__weak CWVAutofillDataManager* data_manager_;
};
// C++ to ObjC bridge for PasswordStoreConsumer.
class WebViewPasswordStoreConsumer
: public password_manager::PasswordStoreConsumer {
public:
explicit WebViewPasswordStoreConsumer(CWVAutofillDataManager* data_manager)
: data_manager_(data_manager) {}
void OnGetPasswordStoreResults(
std::vector<std::unique_ptr<password_manager::PasswordForm>> results)
override {
NSMutableArray<CWVPassword*>* passwords = [NSMutableArray array];
for (auto& form : results) {
CWVPassword* password = [[CWVPassword alloc] initWithPasswordForm:*form];
[passwords addObject:password];
}
[data_manager_ handlePasswordStoreResults:passwords];
}
private:
__weak CWVAutofillDataManager* data_manager_;
};
} // namespace ios_web_view
@implementation CWVAutofillDataManager {
autofill::PersonalDataManager* _personalDataManager;
std::unique_ptr<ios_web_view::WebViewPersonalDataManagerObserverBridge>
_personalDataManagerObserverBridge;
// These completion handlers are stored so they can be called later on when
// |_personalDataManager| completes its initial loading.
NSMutableArray<CWVFetchProfilesCompletionHandler>*
_fetchProfilesCompletionHandlers;
NSMutableArray<CWVFetchCreditCardsCompletionHandler>*
_fetchCreditCardsCompletionHandlers;
NSMutableArray<CWVFetchPasswordsCompletionHandler>*
_fetchPasswordsCompletionHandlers;
// Holds weak observers.
NSHashTable<id<CWVAutofillDataManagerObserver>>* _observers;
password_manager::PasswordStore* _passwordStore;
std::unique_ptr<ios_web_view::WebViewPasswordStoreConsumer>
_passwordStoreConsumer;
}
- (instancetype)initWithPersonalDataManager:
(autofill::PersonalDataManager*)personalDataManager
passwordStore:(password_manager::PasswordStore*)
passwordStore {
self = [super init];
if (self) {
_personalDataManager = personalDataManager;
_passwordStore = passwordStore;
_personalDataManagerObserverBridge = std::make_unique<
ios_web_view::WebViewPersonalDataManagerObserverBridge>(self);
_personalDataManager->AddObserver(_personalDataManagerObserverBridge.get());
_fetchProfilesCompletionHandlers = [NSMutableArray array];
_fetchCreditCardsCompletionHandlers = [NSMutableArray array];
_fetchPasswordsCompletionHandlers = [NSMutableArray array];
_observers = [NSHashTable weakObjectsHashTable];
}
return self;
}
- (void)dealloc {
_personalDataManager->RemoveObserver(
_personalDataManagerObserverBridge.get());
}
#pragma mark - Public Methods
- (void)addObserver:(__weak id<CWVAutofillDataManagerObserver>)observer {
[_observers addObject:observer];
}
- (void)removeObserver:(__weak id<CWVAutofillDataManagerObserver>)observer {
[_observers removeObject:observer];
}
- (void)fetchProfilesWithCompletionHandler:
(void (^)(NSArray<CWVAutofillProfile*>* profiles))completionHandler {
// If data is already loaded, return the existing data asynchronously to match
// client expectation. Otherwise, save the |completionHandler| and wait for
// |personalDataDidChange| to be invoked.
if (_personalDataManager->IsDataLoaded()) {
NSArray<CWVAutofillProfile*>* profiles = [self profiles];
base::PostTask(FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
completionHandler(profiles);
}));
} else {
[_fetchProfilesCompletionHandlers addObject:completionHandler];
}
}
- (void)updateProfile:(CWVAutofillProfile*)profile {
_personalDataManager->UpdateProfile(*profile.internalProfile);
}
- (void)deleteProfile:(CWVAutofillProfile*)profile {
_personalDataManager->RemoveByGUID(profile.internalProfile->guid());
}
- (void)fetchCreditCardsWithCompletionHandler:
(void (^)(NSArray<CWVCreditCard*>* creditCards))completionHandler {
// If data is already loaded, return the existing data asynchronously to match
// client expectation. Otherwise, save the |completionHandler| and wait for
// |personalDataDidChange| to be invoked.
if (_personalDataManager->IsDataLoaded()) {
NSArray<CWVCreditCard*>* creditCards = [self creditCards];
base::PostTask(FROM_HERE, {web::WebThread::UI}, base::BindOnce(^{
completionHandler(creditCards);
}));
} else {
[_fetchCreditCardsCompletionHandlers addObject:completionHandler];
}
}
- (void)fetchPasswordsWithCompletionHandler:
(void (^)(NSArray<CWVPassword*>* passwords))completionHandler {
[_fetchPasswordsCompletionHandlers addObject:completionHandler];
// Fetch is already pending.
if (_passwordStoreConsumer) {
return;
}
_passwordStoreConsumer.reset(
new ios_web_view::WebViewPasswordStoreConsumer(self));
_passwordStore->GetAllLogins(_passwordStoreConsumer.get());
}
- (void)deletePassword:(CWVPassword*)password {
_passwordStore->RemoveLogin(*[password internalPasswordForm]);
}
#pragma mark - Private Methods
- (void)handlePasswordStoreResults:(NSArray<CWVPassword*>*)passwords {
for (CWVFetchPasswordsCompletionHandler completionHandler in
_fetchPasswordsCompletionHandlers) {
completionHandler(passwords);
}
[_fetchPasswordsCompletionHandlers removeAllObjects];
_passwordStoreConsumer.reset();
}
- (void)personalDataDidChange {
// Invoke completionHandlers if they are still outstanding.
if (_personalDataManager->IsDataLoaded()) {
if (_fetchProfilesCompletionHandlers.count > 0) {
NSArray<CWVAutofillProfile*>* profiles = [self profiles];
for (CWVFetchProfilesCompletionHandler completionHandler in
_fetchProfilesCompletionHandlers) {
completionHandler(profiles);
}
[_fetchProfilesCompletionHandlers removeAllObjects];
}
if (_fetchCreditCardsCompletionHandlers.count > 0) {
NSArray<CWVCreditCard*>* creditCards = [self creditCards];
for (CWVFetchCreditCardsCompletionHandler completionHandler in
_fetchCreditCardsCompletionHandlers) {
completionHandler(creditCards);
}
[_fetchCreditCardsCompletionHandlers removeAllObjects];
}
}
for (id<CWVAutofillDataManagerObserver> observer in _observers) {
[observer autofillDataManagerDataDidChange:self];
}
}
- (NSArray<CWVAutofillProfile*>*)profiles {
NSMutableArray* profiles = [NSMutableArray array];
for (autofill::AutofillProfile* internalProfile :
_personalDataManager->GetProfiles()) {
CWVAutofillProfile* profile =
[[CWVAutofillProfile alloc] initWithProfile:*internalProfile];
[profiles addObject:profile];
}
return [profiles copy];
}
- (NSArray<CWVCreditCard*>*)creditCards {
NSMutableArray* creditCards = [NSMutableArray array];
for (autofill::CreditCard* internalCard :
_personalDataManager->GetCreditCards()) {
CWVCreditCard* creditCard =
[[CWVCreditCard alloc] initWithCreditCard:*internalCard];
[creditCards addObject:creditCard];
}
return [creditCards copy];
}
@end