Home | History | Annotate | Download | only in android
      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 
     18 using base::android::ConvertUTF8ToJavaString;
     19 using base::android::ScopedJavaLocalRef;
     20 using content::BrowserThread;
     21 
     22 namespace {
     23 
     24 SQLiteCursor::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 
     45 SQLiteCursor::TestObserver::TestObserver() {
     46 }
     47 
     48 SQLiteCursor::TestObserver::~TestObserver() {
     49 }
     50 
     51 ScopedJavaLocalRef<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 
     62 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
     63   return RegisterNativesImpl(env);
     64 }
     65 
     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);
     73   return count;
     74 }
     75 
     76 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
     77                                                               jobject obj) {
     78   return base::android::ToJavaArrayOfStrings(env, column_names_);
     79 }
     80 
     81 ScopedJavaLocalRef<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 
     89 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
     90   return statement_->statement()->ColumnInt64(column);
     91 }
     92 
     93 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
     94   return statement_->statement()->ColumnInt(column);
     95 }
     96 
     97 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
     98   return statement_->statement()->ColumnDouble(column);
     99 }
    100 
    101 ScopedJavaLocalRef<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 
    116 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
    117   return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
    118 }
    119 
    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));
    124   if (test_observer_)
    125     test_observer_->OnPostMoveToTask();
    126 
    127   event_.Wait();
    128   return position_;
    129 }
    130 
    131 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
    132   return GetColumnTypeInternal(column);
    133 }
    134 
    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)) {
    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 
    149 SQLiteCursor::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 
    163 SQLiteCursor::~SQLiteCursor() {
    164 }
    165 
    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));
    170   consumer_.reset();
    171   tracker_.reset();
    172   service_->CloseStatement(statement_);
    173   delete this;
    174 }
    175 
    176 bool 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 
    204 void SQLiteCursor::GetFaviconForIDInUIThread(
    205     favicon_base::FaviconID id,
    206     const favicon_base::FaviconRawBitmapCallback& 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 
    213 void SQLiteCursor::OnFaviconData(
    214     const favicon_base::FaviconRawBitmapResult& bitmap_result) {
    215   favicon_bitmap_result_ = bitmap_result;
    216   event_.Signal();
    217   if (test_observer_)
    218     test_observer_->OnGetFaviconResult();
    219 }
    220 
    221 void 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 
    230 SQLiteCursor::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 
    237 void 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