Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / history / android / sqlite_cursor.cc
1 // Copyright (c) 2012 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 "chrome/browser/history/android/sqlite_cursor.h"
6
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/bind.h"
11 #include "base/logging.h"
12 #include "chrome/browser/favicon/favicon_service.h"
13 #include "components/history/core/android/android_history_types.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "jni/SQLiteCursor_jni.h"
16 #include "sql/statement.h"
17
18 using base::android::ConvertUTF8ToJavaString;
19 using base::android::ScopedJavaLocalRef;
20 using content::BrowserThread;
21
22 namespace {
23
24 SQLiteCursor::JavaColumnType ToJavaColumnType(sql::ColType type) {
25   switch (type) {
26     case sql::COLUMN_TYPE_INTEGER:
27       return SQLiteCursor::NUMERIC;
28     case sql::COLUMN_TYPE_FLOAT:
29       return SQLiteCursor::DOUBLE;
30     case sql::COLUMN_TYPE_TEXT:
31       return SQLiteCursor::LONG_VAR_CHAR;
32     case sql::COLUMN_TYPE_BLOB:
33       return SQLiteCursor::BLOB;
34     case sql::COLUMN_TYPE_NULL:
35       return SQLiteCursor::NULL_TYPE;
36     default:
37       NOTREACHED();
38   }
39   return SQLiteCursor::NULL_TYPE;
40 }
41
42 }  // namespace.
43
44
45 SQLiteCursor::TestObserver::TestObserver() {
46 }
47
48 SQLiteCursor::TestObserver::~TestObserver() {
49 }
50
51 ScopedJavaLocalRef<jobject> SQLiteCursor::NewJavaSqliteCursor(
52     JNIEnv* env,
53     const std::vector<std::string>& column_names,
54     history::AndroidStatement* statement,
55     AndroidHistoryProviderService* service,
56     FaviconService* favicon_service) {
57   SQLiteCursor* cursor = new SQLiteCursor(column_names, statement, service,
58                                           favicon_service);
59   return Java_SQLiteCursor_create(env, reinterpret_cast<intptr_t>(cursor));
60 }
61
62 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
63   return RegisterNativesImpl(env);
64 }
65
66 jint SQLiteCursor::GetCount(JNIEnv* env, jobject obj) {
67   // Moves to maxium possible position so we will reach the last row, then finds
68   // out the total number of rows.
69   int current_position = position_;
70   int count = MoveTo(env, obj, std::numeric_limits<int>::max() - 1) + 1;
71   // Moves back to the previous position.
72   MoveTo(env, obj, current_position);
73   return count;
74 }
75
76 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
77                                                               jobject obj) {
78   return base::android::ToJavaArrayOfStrings(env, column_names_);
79 }
80
81 ScopedJavaLocalRef<jstring> SQLiteCursor::GetString(JNIEnv* env,
82                                                     jobject obj,
83                                                     jint column) {
84   base::string16 value = statement_->statement()->ColumnString16(column);
85   return ScopedJavaLocalRef<jstring>(env,
86       env->NewString(value.data(), value.size()));
87 }
88
89 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
90   return statement_->statement()->ColumnInt64(column);
91 }
92
93 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
94   return statement_->statement()->ColumnInt(column);
95 }
96
97 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
98   return statement_->statement()->ColumnDouble(column);
99 }
100
101 ScopedJavaLocalRef<jbyteArray> SQLiteCursor::GetBlob(JNIEnv* env,
102                                                      jobject obj,
103                                                      jint column) {
104   std::vector<unsigned char> blob;
105
106   // Assume the client will only get favicon using GetBlob.
107   if (statement_->favicon_index() == column) {
108     if (!GetFavicon(statement_->statement()->ColumnInt(column), &blob))
109       return ScopedJavaLocalRef<jbyteArray>();
110   } else {
111     statement_->statement()->ColumnBlobAsVector(column, &blob);
112   }
113   return base::android::ToJavaByteArray(env, &blob[0], blob.size());
114 }
115
116 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
117   return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
118 }
119
120 jint SQLiteCursor::MoveTo(JNIEnv* env, jobject obj, jint pos) {
121   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
122       base::Bind(&SQLiteCursor::RunMoveStatementOnUIThread,
123       base::Unretained(this), pos));
124   if (test_observer_)
125     test_observer_->OnPostMoveToTask();
126
127   event_.Wait();
128   return position_;
129 }
130
131 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
132   return GetColumnTypeInternal(column);
133 }
134
135 void SQLiteCursor::Destroy(JNIEnv* env, jobject obj) {
136   // We do our best to cleanup when Destroy() is called from Java's finalize()
137   // where the UI message loop might stop running or in the process of shutting
138   // down, as the whole process will be destroyed soon, it's fine to leave some
139   // objects out there.
140   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
141     DestroyOnUIThread();
142   } else if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
143                  base::Bind(&SQLiteCursor::DestroyOnUIThread,
144                      base::Unretained(this)))) {
145     delete this;
146   }
147 }
148
149 SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
150                            history::AndroidStatement* statement,
151                            AndroidHistoryProviderService* service,
152                            FaviconService* favicon_service)
153     : position_(-1),
154       event_(false, false),
155       statement_(statement),
156       column_names_(column_names),
157       service_(service),
158       favicon_service_(favicon_service),
159       count_(-1),
160       test_observer_(NULL) {
161 }
162
163 SQLiteCursor::~SQLiteCursor() {
164 }
165
166 void SQLiteCursor::DestroyOnUIThread() {
167   // Consumer requests were set in the UI thread. They must be cancelled
168   // using the same thread.
169   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
170   tracker_.reset();
171   service_->CloseStatement(statement_);
172   delete this;
173 }
174
175 bool SQLiteCursor::GetFavicon(favicon_base::FaviconID id,
176                               std::vector<unsigned char>* image_data) {
177   if (id) {
178     BrowserThread::PostTask(
179         BrowserThread::UI,
180         FROM_HERE,
181         base::Bind(&SQLiteCursor::GetFaviconForIDInUIThread,
182                    base::Unretained(this), id,
183                    base::Bind(&SQLiteCursor::OnFaviconData,
184                               base::Unretained(this))));
185
186     if (test_observer_)
187       test_observer_->OnPostGetFaviconTask();
188
189     event_.Wait();
190     if (!favicon_bitmap_result_.is_valid())
191       return false;
192
193     scoped_refptr<base::RefCountedMemory> bitmap_data =
194         favicon_bitmap_result_.bitmap_data;
195     image_data->assign(bitmap_data->front(),
196                        bitmap_data->front() + bitmap_data->size());
197     return true;
198   }
199
200   return false;
201 }
202
203 void SQLiteCursor::GetFaviconForIDInUIThread(
204     favicon_base::FaviconID id,
205     const favicon_base::FaviconRawBitmapCallback& callback) {
206   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
207   if (!tracker_.get())
208     tracker_.reset(new base::CancelableTaskTracker());
209   favicon_service_->GetLargestRawFaviconForID(id, callback, tracker_.get());
210 }
211
212 void SQLiteCursor::OnFaviconData(
213     const favicon_base::FaviconRawBitmapResult& bitmap_result) {
214   favicon_bitmap_result_ = bitmap_result;
215   event_.Signal();
216   if (test_observer_)
217     test_observer_->OnGetFaviconResult();
218 }
219
220 void SQLiteCursor::OnMoved(int pos) {
221   position_ = pos;
222   event_.Signal();
223   if (test_observer_)
224     // Notified test_observer on UI thread instead of the one it will wait.
225     test_observer_->OnGetMoveToResult();
226 }
227
228 SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) {
229   if (column == statement_->favicon_index())
230     return SQLiteCursor::BLOB;
231
232   return ToJavaColumnType(statement_->statement()->ColumnType(column));
233 }
234
235 void SQLiteCursor::RunMoveStatementOnUIThread(int pos) {
236   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
237   if (!tracker_.get())
238     tracker_.reset(new base::CancelableTaskTracker());
239   service_->MoveStatement(
240       statement_,
241       position_,
242       pos,
243       base::Bind(&SQLiteCursor::OnMoved, base::Unretained(this)),
244       tracker_.get());
245 }