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/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"
18 using base::android::ConvertUTF8ToJavaString;
19 using base::android::ScopedJavaLocalRef;
20 using content::BrowserThread;
24 SQLiteCursor::JavaColumnType ToJavaColumnType(sql::ColType 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;
39 return SQLiteCursor::NULL_TYPE;
45 SQLiteCursor::TestObserver::TestObserver() {
48 SQLiteCursor::TestObserver::~TestObserver() {
51 ScopedJavaLocalRef<jobject> SQLiteCursor::NewJavaSqliteCursor(
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,
59 return Java_SQLiteCursor_create(env, reinterpret_cast<intptr_t>(cursor));
62 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
63 return RegisterNativesImpl(env);
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);
76 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
78 return base::android::ToJavaArrayOfStrings(env, column_names_);
81 ScopedJavaLocalRef<jstring> SQLiteCursor::GetString(JNIEnv* env,
84 base::string16 value = statement_->statement()->ColumnString16(column);
85 return ScopedJavaLocalRef<jstring>(env,
86 env->NewString(value.data(), value.size()));
89 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
90 return statement_->statement()->ColumnInt64(column);
93 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
94 return statement_->statement()->ColumnInt(column);
97 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
98 return statement_->statement()->ColumnDouble(column);
101 ScopedJavaLocalRef<jbyteArray> SQLiteCursor::GetBlob(JNIEnv* env,
104 std::vector<unsigned char> blob;
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>();
111 statement_->statement()->ColumnBlobAsVector(column, &blob);
113 return base::android::ToJavaByteArray(env, &blob[0], blob.size());
116 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
117 return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
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));
125 test_observer_->OnPostMoveToTask();
131 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
132 return GetColumnTypeInternal(column);
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)) {
142 } else if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
143 base::Bind(&SQLiteCursor::DestroyOnUIThread,
144 base::Unretained(this)))) {
149 SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
150 history::AndroidStatement* statement,
151 AndroidHistoryProviderService* service,
152 FaviconService* favicon_service)
154 event_(false, false),
155 statement_(statement),
156 column_names_(column_names),
158 favicon_service_(favicon_service),
160 test_observer_(NULL) {
163 SQLiteCursor::~SQLiteCursor() {
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));
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 favicon_base::FaviconRawBitmapCallback& 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::FaviconRawBitmapResult& bitmap_result) {
214 favicon_bitmap_result_ = bitmap_result;
217 test_observer_->OnGetFaviconResult();
220 void SQLiteCursor::OnMoved(int pos) {
224 // Notified test_observer on UI thread instead of the one it will wait.
225 test_observer_->OnGetMoveToResult();
228 SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) {
229 if (column == statement_->favicon_index())
230 return SQLiteCursor::BLOB;
232 return ToJavaColumnType(statement_->statement()->ColumnType(column));
235 void SQLiteCursor::RunMoveStatementOnUIThread(int pos) {
236 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
238 tracker_.reset(new base::CancelableTaskTracker());
239 service_->MoveStatement(
243 base::Bind(&SQLiteCursor::OnMoved, base::Unretained(this)),