• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
ToJavaColumnType(sql::ColType type)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 
TestObserver()45 SQLiteCursor::TestObserver::TestObserver() {
46 }
47 
~TestObserver()48 SQLiteCursor::TestObserver::~TestObserver() {
49 }
50 
NewJavaSqliteCursor(JNIEnv * env,const std::vector<std::string> & column_names,history::AndroidStatement * statement,AndroidHistoryProviderService * service,FaviconService * favicon_service)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 
RegisterSqliteCursor(JNIEnv * env)62 bool SQLiteCursor::RegisterSqliteCursor(JNIEnv* env) {
63   return RegisterNativesImpl(env);
64 }
65 
GetCount(JNIEnv * env,jobject obj)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 
GetColumnNames(JNIEnv * env,jobject obj)76 ScopedJavaLocalRef<jobjectArray> SQLiteCursor::GetColumnNames(JNIEnv* env,
77                                                               jobject obj) {
78   return base::android::ToJavaArrayOfStrings(env, column_names_);
79 }
80 
GetString(JNIEnv * env,jobject obj,jint column)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 
GetLong(JNIEnv * env,jobject obj,jint column)89 jlong SQLiteCursor::GetLong(JNIEnv* env, jobject obj, jint column) {
90   return statement_->statement()->ColumnInt64(column);
91 }
92 
GetInt(JNIEnv * env,jobject obj,jint column)93 jint SQLiteCursor::GetInt(JNIEnv* env, jobject obj, jint column) {
94   return statement_->statement()->ColumnInt(column);
95 }
96 
GetDouble(JNIEnv * env,jobject obj,jint column)97 jdouble SQLiteCursor::GetDouble(JNIEnv* env, jobject obj, jint column) {
98   return statement_->statement()->ColumnDouble(column);
99 }
100 
GetBlob(JNIEnv * env,jobject obj,jint column)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 
IsNull(JNIEnv * env,jobject obj,jint column)116 jboolean SQLiteCursor::IsNull(JNIEnv* env, jobject obj, jint column) {
117   return NULL_TYPE == GetColumnTypeInternal(column) ? JNI_TRUE : JNI_FALSE;
118 }
119 
MoveTo(JNIEnv * env,jobject obj,jint pos)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 
GetColumnType(JNIEnv * env,jobject obj,jint column)131 jint SQLiteCursor::GetColumnType(JNIEnv* env, jobject obj, jint column) {
132   return GetColumnTypeInternal(column);
133 }
134 
Destroy(JNIEnv * env,jobject obj)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 
SQLiteCursor(const std::vector<std::string> & column_names,history::AndroidStatement * statement,AndroidHistoryProviderService * service,FaviconService * favicon_service)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 
~SQLiteCursor()163 SQLiteCursor::~SQLiteCursor() {
164 }
165 
DestroyOnUIThread()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 
GetFavicon(favicon_base::FaviconID id,std::vector<unsigned char> * image_data)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 
GetFaviconForIDInUIThread(favicon_base::FaviconID id,const favicon_base::FaviconRawBitmapCallback & callback)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 
OnFaviconData(const favicon_base::FaviconRawBitmapResult & bitmap_result)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 
OnMoved(AndroidHistoryProviderService::Handle handle,int pos)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 
GetColumnTypeInternal(int column)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 
RunMoveStatementOnUIThread(int pos)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