sqlite_cursor.cc revision cedac228d2dd51db4b79ea1e72c7f249408ee061
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 "chrome/browser/history/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 18using base::android::ConvertUTF8ToJavaString; 19using base::android::ScopedJavaLocalRef; 20using content::BrowserThread; 21 22namespace { 23 24SQLiteCursor::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 45SQLiteCursor::TestObserver::TestObserver() { 46} 47 48SQLiteCursor::TestObserver::~TestObserver() { 49} 50 51ScopedJavaLocalRef<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 62bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) { 63 return RegisterNativesImpl(env); 64} 65 66jint 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 76ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env, 77 jobject obj) { 78 return base::android::ToJavaArrayOfStrings(env, column_names_); 79} 80 81ScopedJavaLocalRef<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 89jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) { 90 return statement_->statement()->ColumnInt64(column); 91} 92 93jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) { 94 return statement_->statement()->ColumnInt(column); 95} 96 97jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) { 98 return statement_->statement()->ColumnDouble(column); 99} 100 101ScopedJavaLocalRef<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 116jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) { 117 return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE; 118} 119 120jint 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 131jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) { 132 return GetColumnTypeInternal(column); 133} 134 135void 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 149SQLiteCursor::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 163SQLiteCursor::~SQLiteCursor() { 164} 165 166void 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 consumer_.reset(); 171 tracker_.reset(); 172 service_->CloseStatement(statement_); 173 delete this; 174} 175 176bool SQLiteCursor::GetFavicon(favicon_base::FaviconID id, 177 std::vector<unsigned char>* image_data) { 178 if (id) { 179 BrowserThread::PostTask( 180 BrowserThread::UI, 181 FROM_HERE, 182 base::Bind(&SQLiteCursor::GetFaviconForIDInUIThread, 183 base::Unretained(this), id, 184 base::Bind(&SQLiteCursor::OnFaviconData, 185 base::Unretained(this)))); 186 187 if (test_observer_) 188 test_observer_->OnPostGetFaviconTask(); 189 190 event_.Wait(); 191 if (!favicon_bitmap_result_.is_valid()) 192 return false; 193 194 scoped_refptr<base::RefCountedMemory> bitmap_data = 195 favicon_bitmap_result_.bitmap_data; 196 image_data->assign(bitmap_data->front(), 197 bitmap_data->front() + bitmap_data->size()); 198 return true; 199 } 200 201 return false; 202} 203 204void SQLiteCursor::GetFaviconForIDInUIThread( 205 favicon_base::FaviconID id, 206 const favicon_base::FaviconRawCallback& callback) { 207 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 208 if (!tracker_.get()) 209 tracker_.reset(new base::CancelableTaskTracker()); 210 favicon_service_->GetLargestRawFaviconForID(id, callback, tracker_.get()); 211} 212 213void SQLiteCursor::OnFaviconData( 214 const favicon_base::FaviconBitmapResult& bitmap_result) { 215 favicon_bitmap_result_ = bitmap_result; 216 event_.Signal(); 217 if (test_observer_) 218 test_observer_->OnGetFaviconResult(); 219} 220 221void SQLiteCursor::OnMoved(AndroidHistoryProviderService::Handle handle, 222 int pos) { 223 position_ = pos; 224 event_.Signal(); 225 if (test_observer_) 226 // Notified test_observer on UI thread instead of the one it will wait. 227 test_observer_->OnGetMoveToResult(); 228} 229 230SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) { 231 if (column == statement_->favicon_index()) 232 return SQLiteCursor::BLOB; 233 234 return ToJavaColumnType(statement_->statement()->ColumnType(column)); 235} 236 237void SQLiteCursor::RunMoveStatementOnUIThread(int pos) { 238 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 239 if (!consumer_.get()) 240 consumer_.reset(new CancelableRequestConsumer()); 241 service_->MoveStatement( 242 statement_, position_, pos, consumer_.get(), 243 base::Bind(&SQLiteCursor::OnMoved, base::Unretained(this))); 244} 245