1// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "android_webview/browser/aw_form_database_service.h"
6#include "base/logging.h"
7#include "base/synchronization/waitable_event.h"
8#include "components/autofill/core/browser/webdata/autofill_table.h"
9#include "components/webdata/common/webdata_constants.h"
10#include "content/public/browser/browser_thread.h"
11#include "ui/base/l10n/l10n_util_android.h"
12
13using base::WaitableEvent;
14using content::BrowserThread;
15
16namespace {
17
18// Callback to handle database error. It seems chrome uses this to
19// display an error dialog box only.
20void DatabaseErrorCallback(sql::InitStatus status) {
21  LOG(WARNING) << "initializing autocomplete database failed";
22}
23
24}  // namespace
25
26namespace android_webview {
27
28AwFormDatabaseService::AwFormDatabaseService(const base::FilePath path) {
29  CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
30  web_database_ = new WebDatabaseService(path.Append(kWebDataFilename),
31      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
32      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB));
33  web_database_->AddTable(
34      scoped_ptr<WebDatabaseTable>(new autofill::AutofillTable(
35          l10n_util::GetDefaultLocale())));
36  web_database_->LoadDatabase();
37
38  autofill_data_ = new autofill::AutofillWebDataService(
39      web_database_,
40      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI),
41      BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB),
42      base::Bind(&DatabaseErrorCallback));
43  autofill_data_->Init();
44}
45
46AwFormDatabaseService::~AwFormDatabaseService() {
47  Shutdown();
48}
49
50void AwFormDatabaseService::Shutdown() {
51  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52  DCHECK(result_map_.empty());
53  // TODO(sgurun) we don't run into this logic right now,
54  // but if we do, then we need to implement cancellation
55  // of pending queries.
56  autofill_data_->ShutdownOnUIThread();
57  web_database_->ShutdownDatabase();
58}
59
60scoped_refptr<autofill::AutofillWebDataService>
61AwFormDatabaseService::get_autofill_webdata_service() {
62  return autofill_data_;
63}
64
65void AwFormDatabaseService::ClearFormData() {
66  BrowserThread::PostTask(
67      BrowserThread::DB,
68      FROM_HERE,
69      base::Bind(&AwFormDatabaseService::ClearFormDataImpl,
70                 base::Unretained(this)));
71}
72
73void AwFormDatabaseService::ClearFormDataImpl() {
74  base::Time begin;
75  base::Time end = base::Time::Max();
76  autofill_data_->RemoveFormElementsAddedBetween(begin, end);
77  autofill_data_->RemoveAutofillDataModifiedBetween(begin, end);
78}
79
80bool AwFormDatabaseService::HasFormData() {
81  WaitableEvent completion(false, false);
82  bool result = false;
83  BrowserThread::PostTask(
84      BrowserThread::DB,
85      FROM_HERE,
86      base::Bind(&AwFormDatabaseService::HasFormDataImpl,
87                 base::Unretained(this),
88                 &completion,
89                 &result));
90  completion.Wait();
91  return result;
92}
93
94void AwFormDatabaseService::HasFormDataImpl(
95    WaitableEvent* completion,
96    bool* result) {
97  WebDataServiceBase::Handle pending_query_handle =
98      autofill_data_->HasFormElements(this);
99  PendingQuery query;
100  query.result = result;
101  query.completion = completion;
102  result_map_[pending_query_handle] = query;
103}
104
105void AwFormDatabaseService::OnWebDataServiceRequestDone(
106    WebDataServiceBase::Handle h,
107    const WDTypedResult* result) {
108
109  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB));
110  bool has_form_data = false;
111  if (result) {
112    DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType());
113    const WDResult<bool>* autofill_result =
114        static_cast<const WDResult<bool>*>(result);
115    has_form_data = autofill_result->GetValue();
116  }
117  QueryMap::const_iterator it = result_map_.find(h);
118  if (it == result_map_.end()) {
119    LOG(WARNING) << "Received unexpected callback from web data service";
120    return;
121  }
122  *(it->second.result) = has_form_data;
123  it->second.completion->Signal();
124  result_map_.erase(h);
125}
126
127}  // namespace android_webview
128