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.
5 #include "chrome/browser/history/android/sqlite_cursor.h"
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"
17 using base::android::ConvertUTF8ToJavaString;
18 using base::android::ScopedJavaLocalRef;
19 using content::BrowserThread;
23 SQLiteCursor::JavaColumnType ToJavaColumnType(sql::ColType 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;
38 return SQLiteCursor::NULL_TYPE;
44 SQLiteCursor::TestObserver::TestObserver() {
47 SQLiteCursor::TestObserver::~TestObserver() {
50 ScopedJavaLocalRef<jobject> SQLiteCursor::NewJavaSqliteCursor(
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,
58 return Java_SQLiteCursor_create(env, reinterpret_cast<intptr_t>(cursor));
61 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
62 return RegisterNativesImpl(env);
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);
75 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
77 return base::android::ToJavaArrayOfStrings(env, column_names_);
80 ScopedJavaLocalRef<jstring> SQLiteCursor::GetString(JNIEnv* env,
83 base::string16 value = statement_->statement()->ColumnString16(column);
84 return ScopedJavaLocalRef<jstring>(env,
85 env->NewString(value.data(), value.size()));
88 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
89 return statement_->statement()->ColumnInt64(column);
92 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
93 return statement_->statement()->ColumnInt(column);
96 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
97 return statement_->statement()->ColumnDouble(column);
100 ScopedJavaLocalRef<jbyteArray> SQLiteCursor::GetBlob(JNIEnv* env,
103 std::vector<unsigned char> blob;
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>();
110 statement_->statement()->ColumnBlobAsVector(column, &blob);
112 return base::android::ToJavaByteArray(env, &blob[0], blob.size());
115 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
116 return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
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));
124 test_observer_->OnPostMoveToTask();
130 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
131 return GetColumnTypeInternal(column);
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)) {
141 } else if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
142 base::Bind(&SQLiteCursor::DestroyOnUIThread,
143 base::Unretained(this)))) {
148 SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
149 history::AndroidStatement* statement,
150 AndroidHistoryProviderService* service,
151 FaviconService* favicon_service)
153 event_(false, false),
154 statement_(statement),
155 column_names_(column_names),
157 favicon_service_(favicon_service),
159 test_observer_(NULL) {
162 SQLiteCursor::~SQLiteCursor() {
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));
171 service_->CloseStatement(statement_);
175 bool SQLiteCursor::GetFavicon(favicon_base::FaviconID id,
176 std::vector<unsigned char>* image_data) {
178 BrowserThread::PostTask(
181 base::Bind(&SQLiteCursor::GetFaviconForIDInUIThread,
182 base::Unretained(this), id,
183 base::Bind(&SQLiteCursor::OnFaviconData,
184 base::Unretained(this))));
187 test_observer_->OnPostGetFaviconTask();
190 if (!favicon_bitmap_result_.is_valid())
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());
203 void SQLiteCursor::GetFaviconForIDInUIThread(
204 favicon_base::FaviconID id,
205 const FaviconService::FaviconRawCallback& callback) {
206 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
208 tracker_.reset(new base::CancelableTaskTracker());
209 favicon_service_->GetLargestRawFaviconForID(id, callback, tracker_.get());
212 void SQLiteCursor::OnFaviconData(
213 const favicon_base::FaviconBitmapResult& bitmap_result) {
214 favicon_bitmap_result_ = bitmap_result;
217 test_observer_->OnGetFaviconResult();
220 void SQLiteCursor::OnMoved(AndroidHistoryProviderService::Handle handle,
225 // Notified test_observer on UI thread instead of the one it will wait.
226 test_observer_->OnGetMoveToResult();
229 SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) {
230 if (column == statement_->favicon_index())
231 return SQLiteCursor::BLOB;
233 return ToJavaColumnType(statement_->statement()->ColumnType(column));
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)));