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/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 
     17 using base::android::ConvertUTF8ToJavaString;
     18 using base::android::ScopedJavaLocalRef;
     19 using content::BrowserThread;
     20 
     21 namespace {
     22 
     23 SQLiteCursor::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 
     44 SQLiteCursor::TestObserver::TestObserver() {
     45 }
     46 
     47 SQLiteCursor::TestObserver::~TestObserver() {
     48 }
     49 
     50 ScopedJavaLocalRef<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 
     61 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
     62   return RegisterNativesImpl(env);
     63 }
     64 
     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);
     72   return count;
     73 }
     74 
     75 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
     76                                                               jobject obj) {
     77   return base::android::ToJavaArrayOfStrings(env, column_names_);
     78 }
     79 
     80 ScopedJavaLocalRef<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 
     88 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
     89   return statement_->statement()->ColumnInt64(column);
     90 }
     91 
     92 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
     93   return statement_->statement()->ColumnInt(column);
     94 }
     95 
     96 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
     97   return statement_->statement()->ColumnDouble(column);
     98 }
     99 
    100 ScopedJavaLocalRef<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 
    115 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
    116   return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
    117 }
    118 
    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));
    123   if (test_observer_)
    124     test_observer_->OnPostMoveToTask();
    125 
    126   event_.Wait();
    127   return position_;
    128 }
    129 
    130 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
    131   return GetColumnTypeInternal(column);
    132 }
    133 
    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)) {
    140     DestroyOnUIThread();
    141   } else if (!BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
    142                  base::Bind(&SQLiteCursor::DestroyOnUIThread,
    143                      base::Unretained(this)))) {
    144     delete this;
    145   }
    146 }
    147 
    148 SQLiteCursor::SQLiteCursor(const std::vector<std::string>& column_names,
    149                            history::AndroidStatement* statement,
    150                            AndroidHistoryProviderService* service,
    151                            FaviconService* favicon_service)
    152     : position_(-1),
    153       event_(false, false),
    154       statement_(statement),
    155       column_names_(column_names),
    156       service_(service),
    157       favicon_service_(favicon_service),
    158       count_(-1),
    159       test_observer_(NULL) {
    160 }
    161 
    162 SQLiteCursor::~SQLiteCursor() {
    163 }
    164 
    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));
    169   consumer_.reset();
    170   tracker_.reset();
    171   service_->CloseStatement(statement_);
    172   delete this;
    173 }
    174 
    175 bool SQLiteCursor::GetFavicon(chrome::FaviconID id,
    176                               std::vector<unsigned char>* image_data) {
    177   if (id) {
    178     BrowserThread::PostTask(
    179         BrowserThread::UI,
    180         FROM_HERE,
    181         base::Bind(&SQLiteCursor::GetFaviconForIDInUIThread,
    182                    base::Unretained(this), id,
    183                    base::Bind(&SQLiteCursor::OnFaviconData,
    184                               base::Unretained(this))));
    185 
    186     if (test_observer_)
    187       test_observer_->OnPostGetFaviconTask();
    188 
    189     event_.Wait();
    190     if (!favicon_bitmap_result_.is_valid())
    191       return false;
    192 
    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());
    197     return true;
    198   }
    199 
    200   return false;
    201 }
    202 
    203 void SQLiteCursor::GetFaviconForIDInUIThread(
    204     chrome::FaviconID id,
    205     const FaviconService::FaviconRawCallback& callback) {
    206   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    207   if (!tracker_.get())
    208     tracker_.reset(new CancelableTaskTracker());
    209   favicon_service_->GetLargestRawFaviconForID(id, callback, tracker_.get());
    210 }
    211 
    212 
    213 void SQLiteCursor::OnFaviconData(
    214     const chrome::FaviconBitmapResult& 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