// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "android_webview/browser/aw_form_database_service.h"
#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/task/sequenced_task_runner.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "components/autofill/core/browser/webdata/addresses/address_autofill_table.h"
#include "components/autofill/core/browser/webdata/autocomplete/autocomplete_table.h"
#include "components/autofill/core/browser/webdata/payments/payments_autofill_table.h"
#include "components/webdata/common/webdata_constants.h"
#include "content/public/browser/browser_thread.h"
using base::WaitableEvent;
namespace {
// Callback to handle database error. It seems chrome uses this to
// display an error dialog box only.
void DatabaseErrorCallback(sql::InitStatus init_status,
const std::string& diagnostics) {
LOG(WARNING) << "initializing autocomplete database failed";
}
} // namespace
namespace android_webview {
AwFormDatabaseService::AwFormDatabaseService(const base::FilePath path)
: has_form_data_result_(false),
has_form_data_completion_(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED) {
web_database_ = new WebDatabaseService(
path.Append(kWebDataFilename), content::GetUIThreadTaskRunner({}),
base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::BLOCK_SHUTDOWN}));
web_database_->AddTable(std::make_unique<autofill::AutocompleteTable>());
// WebView shouldn't depend on non-Autocomplete tables. However,
// `AwFormDatabaseService::ClearFormData()` also clear Autofill-related data.
// This is likely a bug.
// Once crbug.com/1501199 is resolved, all tables can be removed.
web_database_->AddTable(std::make_unique<autofill::AddressAutofillTable>());
web_database_->AddTable(std::make_unique<autofill::PaymentsAutofillTable>());
web_database_->LoadDatabase();
autofill_data_ = new autofill::AutofillWebDataService(
web_database_, content::GetUIThreadTaskRunner({}));
autofill_data_->Init(base::BindOnce(&DatabaseErrorCallback));
}
AwFormDatabaseService::~AwFormDatabaseService() {
Shutdown();
}
void AwFormDatabaseService::Shutdown() {
// TODO(sgurun) we don't run into this logic right now, but if we do, then we
// need to implement cancellation of pending queries.
autofill_data_->ShutdownOnUISequence();
web_database_->ShutdownDatabase();
}
scoped_refptr<autofill::AutofillWebDataService>
AwFormDatabaseService::get_autofill_webdata_service() {
return autofill_data_;
}
void AwFormDatabaseService::ClearFormData() {
base::Time begin;
base::Time end = base::Time::Max();
autofill_data_->RemoveFormElementsAddedBetween(begin, end);
autofill_data_->RemoveAutofillDataModifiedBetween(begin, end);
}
bool AwFormDatabaseService::HasFormData() {
has_form_data_result_ = false;
has_form_data_completion_.Reset();
using awds = autofill::AutofillWebDataService;
base::ThreadPool::PostTask(
FROM_HERE,
base::BindOnce(
base::IgnoreResult(&awds::GetCountOfValuesContainedBetween),
autofill_data_, base::Time(), base::Time::Max(), this));
{
base::ScopedAllowBaseSyncPrimitivesOutsideBlockingScope allow_wait;
has_form_data_completion_.Wait();
}
return has_form_data_result_;
}
void AwFormDatabaseService::OnWebDataServiceRequestDone(
WebDataServiceBase::Handle h,
std::unique_ptr<WDTypedResult> result) {
if (result) {
DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
const WDResult<int>* autofill_result =
static_cast<const WDResult<int>*>(result.get());
has_form_data_result_ = autofill_result->GetValue() > 0;
}
has_form_data_completion_.Signal();
}
} // namespace android_webview