sqlite_cursor.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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 17using base::android::ConvertUTF8ToJavaString; 18using base::android::ScopedJavaLocalRef; 19using content::BrowserThread; 20 21namespace { 22 23SQLiteCursor::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 44SQLiteCursor::TestObserver::TestObserver() { 45} 46 47SQLiteCursor::TestObserver::~TestObserver() { 48} 49 50ScopedJavaLocalRef<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<jint>(cursor)); 59} 60 61bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) { 62 return RegisterNativesImpl(env); 63} 64 65jint 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 75ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env, 76 jobject obj) { 77 return base::android::ToJavaArrayOfStrings(env, column_names_); 78} 79 80ScopedJavaLocalRef<jstring> SQLiteCursor::GetString(JNIEnv* env, 81 jobject obj, 82 jint column) { 83 string16 value = statement_->statement()->ColumnString16(column); 84 return ScopedJavaLocalRef<jstring>(env, 85 env->NewString(value.data(), value.size())); 86} 87 88jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) { 89 return statement_->statement()->ColumnInt64(column); 90} 91 92jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) { 93 return statement_->statement()->ColumnInt(column); 94} 95 96jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) { 97 return statement_->statement()->ColumnDouble(column); 98} 99 100ScopedJavaLocalRef<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 115jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) { 116 return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE; 117} 118 119jint 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 130jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) { 131 return GetColumnTypeInternal(column); 132} 133 134void SQLiteCursor::Destroy(JNIEnv* env, jobject obj) { 135 delete this; 136} 137 138SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names, 139 history::AndroidStatement* statement, 140 AndroidHistoryProviderService* service, 141 FaviconService* favicon_service) 142 : position_(-1), 143 event_(false, false), 144 statement_(statement), 145 column_names_(column_names), 146 service_(service), 147 favicon_service_(favicon_service), 148 count_(-1), 149 test_observer_(NULL) { 150} 151 152SQLiteCursor::~SQLiteCursor() { 153 // Consumer requests were set in the UI thread. They must be cancelled 154 // using the same thread. 155 if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { 156 CancelAllRequests(NULL); 157 } else { 158 base::WaitableEvent event(false, false); 159 BrowserThread::PostTask( 160 BrowserThread::UI, 161 FROM_HERE, 162 base::Bind(&SQLiteCursor::CancelAllRequests, base::Unretained(this), 163 &event)); 164 event.Wait(); 165 } 166 167 BrowserThread::PostTask( 168 BrowserThread::UI, 169 FROM_HERE, 170 base::Bind(&AndroidHistoryProviderService::CloseStatement, 171 base::Unretained(service_), statement_)); 172} 173 174bool SQLiteCursor::GetFavicon(chrome::FaviconID id, 175 std::vector<unsigned char>* image_data) { 176 if (id) { 177 BrowserThread::PostTask( 178 BrowserThread::UI, 179 FROM_HERE, 180 base::Bind(&SQLiteCursor::GetFaviconForIDInUIThread, 181 base::Unretained(this), id, 182 base::Bind(&SQLiteCursor::OnFaviconData, 183 base::Unretained(this)))); 184 185 if (test_observer_) 186 test_observer_->OnPostGetFaviconTask(); 187 188 event_.Wait(); 189 if (!favicon_bitmap_result_.is_valid()) 190 return false; 191 192 scoped_refptr<base::RefCountedMemory> bitmap_data = 193 favicon_bitmap_result_.bitmap_data; 194 image_data->assign(bitmap_data->front(), 195 bitmap_data->front() + bitmap_data->size()); 196 return true; 197 } 198 199 return false; 200} 201 202void SQLiteCursor::GetFaviconForIDInUIThread( 203 chrome::FaviconID id, 204 const FaviconService::FaviconRawCallback& callback) { 205 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 206 if (!tracker_.get()) 207 tracker_.reset(new CancelableTaskTracker()); 208 favicon_service_->GetLargestRawFaviconForID(id, callback, tracker_.get()); 209} 210 211 212void SQLiteCursor::OnFaviconData( 213 const chrome::FaviconBitmapResult& bitmap_result) { 214 favicon_bitmap_result_ = bitmap_result; 215 event_.Signal(); 216 if (test_observer_) 217 test_observer_->OnGetFaviconResult(); 218} 219 220void 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 229void SQLiteCursor::CancelAllRequests(base::WaitableEvent* finished) { 230 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 231 232 // Destruction will cancel all pending tasks. 233 consumer_.reset(); 234 tracker_.reset(); 235 236 if (finished) 237 finished->Signal(); 238} 239 240SQLiteCursor::JavaColumnType SQLiteCursor::GetColumnTypeInternal(int column) { 241 if (column == statement_->favicon_index()) 242 return SQLiteCursor::BLOB; 243 244 return ToJavaColumnType(statement_->statement()->ColumnType(column)); 245} 246 247void SQLiteCursor::RunMoveStatementOnUIThread(int pos) { 248 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 249 if (!consumer_.get()) 250 consumer_.reset(new CancelableRequestConsumer()); 251 service_->MoveStatement( 252 statement_, position_, pos, consumer_.get(), 253 base::Bind(&SQLiteCursor::OnMoved, base::Unretained(this))); 254} 255