Upstream version 7.36.149.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/history/android/android_history_types.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "jni/SQLiteCursor_jni.h"
15 #include "sql/statement.h"
16
17 using base::android::ConvertUTF8ToJavaString;
18 using base::android::ScopedJavaLocalRef;
19 using content::BrowserThread;
20
21 namespace {
22
23 SQLiteCursor::JavaColumnType ToJavaColumnType(sql::ColType type) {
24   switch (type) {
25     case sql::COLUMN_TYPE_INTEGER:
26       return SQLiteCursor::NUMERIC;
27     case sql::COLUMN_TYPE_FLOAT:
28       return SQLiteCursor::DOUBLE;
29     case sql::COLUMN_TYPE_TEXT:
30       return SQLiteCursor::LONG_VAR_CHAR;
31     case sql::COLUMN_TYPE_BLOB:
32       return SQLiteCursor::BLOB;
33     case sql::COLUMN_TYPE_NULL:
34       return SQLiteCursor::NULL_TYPE;
35     default:
36       NOTREACHED();
37   }
38   return SQLiteCursor::NULL_TYPE;
39 }
40
41 }  // namespace.
42
43
44 SQLiteCursor::TestObserver::TestObserver() {
45 }
46
47 SQLiteCursor::TestObserver::~TestObserver() {
48 }
49
50 ScopedJavaLocalRef<jobject> SQLiteCursor::NewJavaSqliteCursor(
51     JNIEnv* env,
52     const std::vector<std::string>& column_names,
53     history::AndroidStatement* statement,
54     AndroidHistoryProviderService* service,
55     FaviconService* favicon_service) {
56   SQLiteCursor* cursor = new SQLiteCursor(column_names, statement, service,
57                                           favicon_service);
58   return Java_SQLiteCursor_create(env, reinterpret_cast<intptr_t>(cursor));
59 }
60
61 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
62   return RegisterNativesImpl(env);
63 }
64
65 jint SQLiteCursor::GetCount(JNIEnv* env, jobject obj) {
66   // Moves to maxium possible position so we will reach the last row, then finds
67   // out the total number of rows.
68   int current_position = position_;
69   int count = MoveTo(env, obj, std::numeric_limits<int>::max() - 1) + 1;
70   // Moves back to the previous position.
71   MoveTo(env, obj, current_position);
72   return count;
73 }
74
75 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
76                                                               jobject obj) {
77   return base::android::ToJavaArrayOfStrings(env, column_names_);
78 }
79
80 ScopedJavaLocalRef<jstring> SQLiteCursor::GetString(JNIEnv* env,
81                                                     jobject obj,
82                                                     jint column) {
83   base::string16 value = statement_->statement()->ColumnString16(column);
84   return ScopedJavaLocalRef<jstring>(env,
85       env->NewString(value.data(), value.size()));
86 }
87
88 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
89   return statement_->statement()->ColumnInt64(column);
90 }
91
92 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
93   return statement_->statement()->ColumnInt(column);
94 }
95
96 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
97   return statement_->statement()->ColumnDouble(column);
98 }
99
100 ScopedJavaLocalRef<jbyteArray> SQLiteCursor::GetBlob(JNIEnv* env,
101                                                      jobject obj,
102                                                      jint column) {
103   std::vector<unsigned char> blob;
104
105   // Assume the client will only get favicon using GetBlob.
106   if (statement_->favicon_index() == column) {
107     if (!GetFavicon(statement_->statement()->ColumnInt(column), &blob))
108       return ScopedJavaLocalRef<jbyteArray>();
109   } else {
110     statement_->statement()->ColumnBlobAsVector(column, &blob);
111   }
112   return base::android::ToJavaByteArray(env, &blob[0], blob.size());
113 }
114
115 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
116   return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
117 }
118
119 jint SQLiteCursor::MoveTo(JNIEnv* env, jobject obj, jint pos) {
120   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
121       base::Bind(&SQLiteCursor::RunMoveStatementOnUIThread,
122       base::Unretained(this), pos));
123   if (test_observer_)
124     test_observer_->OnPostMoveToTask();
125
126   event_.Wait();
127   return position_;
128 }
129
130 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
131   return GetColumnTypeInternal(column);
132 }
133
134 void SQLiteCursor::Destroy(JNIEnv* env, jobject obj) {
135   // We do our best to cleanup when Destroy() is called from Java's finalize()
136   // where the UI message loop might stop running or in the process of shutting
137   // down, as the whole process will be destroyed soon, it's fine to leave some
138   // objects out there.
139   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
140     DestroyOnUIThread();
141   } else if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
142                  base::Bind(&SQLiteCursor::DestroyOnUIThread,
143                      base::Unretained(this)))) {
144     delete this;
145   }
146 }
147
148 SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
149                            history::AndroidStatement* statement,
150                            AndroidHistoryProviderService* service,
151                            FaviconService* favicon_service)
152     : position_(-1),
153       event_(false, false),
154       statement_(statement),
155       column_names_(column_names),
156       service_(service),
157       favicon_service_(favicon_service),
158       count_(-1),
159       test_observer_(NULL) {
160 }
161
162 SQLiteCursor::~SQLiteCursor() {
163 }
164
165 void SQLiteCursor::DestroyOnUIThread() {
166   // Consumer requests were set in the UI thread. They must be cancelled
167   // using the same thread.
168   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
169   consumer_.reset();
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 FaviconService::FaviconRawCallback& 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::FaviconBitmapResult& 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(AndroidHistoryProviderService::Handle handle,
221                            int pos) {
222   position_ = pos;
223   event_.Signal();
224   if (test_observer_)
225     // Notified test_observer on UI thread instead of the one it will wait.
226     test_observer_->OnGetMoveToResult();
227 }
228
229 SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) {
230   if (column == statement_->favicon_index())
231     return SQLiteCursor::BLOB;
232
233   return ToJavaColumnType(statement_->statement()->ColumnType(column));
234 }
235
236 void SQLiteCursor::RunMoveStatementOnUIThread(int pos) {
237   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
238   if (!consumer_.get())
239     consumer_.reset(new CancelableRequestConsumer());
240   service_->MoveStatement(
241       statement_, position_, pos, consumer_.get(),
242       base::Bind(&SQLiteCursor::OnMoved, base::Unretained(this)));
243 }