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 #ifndef CHROME_BROWSER_HISTORY_ANDROID_SQLITE_CURSOR_H_ 6 #define CHROME_BROWSER_HISTORY_ANDROID_SQLITE_CURSOR_H_ 7 8 #include <jni.h> 9 #include <vector> 10 11 #include "base/android/scoped_java_ref.h" 12 #include "base/basictypes.h" 13 #include "base/gtest_prod_util.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/strings/string16.h" 16 #include "base/synchronization/waitable_event.h" 17 #include "chrome/browser/common/cancelable_request.h" 18 #include "chrome/browser/favicon/favicon_service.h" 19 #include "chrome/browser/history/android/android_history_provider_service.h" 20 #include "chrome/browser/history/history_types.h" 21 #include "chrome/common/cancelable_task_tracker.h" 22 23 // This class is JNI implementation of 24 // org.chromium.chrome.database.SqliteCursor, it uses the AndroidStatement to 25 // iterate among the result rows. This is not thread safe, all methods should 26 // be called from the same non-UI thread which typical is the Java thread. 27 // 28 // This class can not be in history namespace because the class name has to 29 // match to the generated sqlite_cursor_jni.h. 30 class SQLiteCursor { 31 public: 32 // Mapping to the column type definitions in java.sql.Types. 33 enum JavaColumnType { 34 BLOB = 2004, 35 LONG_VAR_CHAR = -1, 36 NULL_TYPE = 0, 37 NUMERIC = 2, 38 DOUBLE = 8, 39 }; 40 41 // This class is intended to be used only in unit tests. 42 // 43 // There are 2 threads in unit test, one is the UI thread, another is the DB 44 // thread, after the task posted into UI thread, the MessageLoop needs to run 45 // to execute the task. The OnPostMoveToTask() and the OnPostGetFaviconTask() 46 // give unit tests a chance to run the message loop before event_.Wait is 47 // invoked, The OnGetMoveToResult() and OnGetFaviconResult() is used to notify 48 // the test observer in the UI thread when the task's result comes back, it 49 // calls MessageLoop::Quit() to exit the loop, then the event.Wait() is 50 // called. Basically, Two threads are used to simulate 3 threads' behavior 51 // here. 52 // The whole observer design is only for test purpose and should only be used 53 // in unit test. 54 class TestObserver { 55 public: 56 TestObserver(); 57 58 // Notify the MoveTo task has been posted to UI thread. 59 virtual void OnPostMoveToTask() = 0; 60 // Notify the MoveTo result has been gotten in UI thread. 61 virtual void OnGetMoveToResult() = 0; 62 // Notify the GetFavicon task has been posted to UI thread. 63 virtual void OnPostGetFaviconTask() = 0; 64 // Notify the GetFavicon result has been gotten in UI thread. 65 virtual void OnGetFaviconResult() = 0; 66 67 protected: 68 virtual ~TestObserver(); 69 }; 70 71 // Returns org.chromium.chrome.SQLiteCursor java object by creating 72 // SQLitCursor native and java objects, then bind them together. 73 static base::android::ScopedJavaLocalRef<jobject> NewJavaSqliteCursor( 74 JNIEnv* env, 75 const std::vector<std::string>& column_names, 76 history::AndroidStatement* statement, 77 AndroidHistoryProviderService* service, 78 FaviconService* favicon_service); 79 80 static bool RegisterSqliteCursor(JNIEnv* env); 81 82 // JNI methods ----------------------------------------------------------- 83 84 // Returns the result row count. 85 jint GetCount(JNIEnv* env, jobject obj); 86 87 // Returns the result's columns' name. 88 base::android::ScopedJavaLocalRef<jobjectArray> GetColumnNames( 89 JNIEnv* env, 90 jobject obj); 91 92 // Returns the given column value as jstring. 93 base::android::ScopedJavaLocalRef<jstring> GetString(JNIEnv* env, 94 jobject obj, 95 jint column); 96 97 // Returns the given column value as jlong. 98 jlong GetLong(JNIEnv* env, jobject obj, jint column); 99 100 // Returns the given column value as int. 101 jint GetInt(JNIEnv* env, jobject obj, jint column); 102 103 // Returns the given column value as double. 104 jdouble GetDouble(JNIEnv* env, jobject obj, jint column); 105 106 // Returns the given column value as jbyteArray. 107 base::android::ScopedJavaLocalRef<jbyteArray> GetBlob(JNIEnv* env, 108 jobject obj, 109 jint column); 110 111 // Return JNI_TRUE if the give column value is NULL, JNI_FALSE otherwise. 112 jboolean IsNull(JNIEnv* env, jobject obj, jint column); 113 114 // Moves the cursor to |pos|, returns new position. 115 // If the returned position is not equal to |pos|, then the cursor points to 116 // the last row. 117 jint MoveTo(JNIEnv* env, jobject obj, jint pos); 118 119 // Returns the type of column. 120 jint GetColumnType(JNIEnv* env, jobject obj, jint column); 121 122 // Called from Java to relase this object. 123 void Destroy(JNIEnv* env, jobject obj); 124 125 private: 126 FRIEND_TEST_ALL_PREFIXES(SQLiteCursorTest, Run); 127 128 // |column_names| is the column names of this cursor, the sequence of name 129 // should match the sql query's projection name. 130 // |statement| is query's statement which bound the variables. This class 131 // take the ownership of |statement|. 132 SQLiteCursor(const std::vector<std::string>& column_names, 133 history::AndroidStatement* statement, 134 AndroidHistoryProviderService* service, 135 FaviconService* favicon_service); 136 137 virtual ~SQLiteCursor(); 138 139 // Destory SQLiteCursor object on UI thread. All cleanup need finish in UI 140 // thread. 141 void DestroyOnUIThread(); 142 143 // This method is for testing only. 144 void set_test_observer(TestObserver* test_observer) { 145 test_observer_ = test_observer; 146 } 147 148 // Get Favicon from history backend. 149 bool GetFavicon(chrome::FaviconID id, 150 std::vector<unsigned char>* image_data); 151 152 void GetFaviconForIDInUIThread( 153 chrome::FaviconID id, 154 const FaviconService::FaviconRawCallback& callback); 155 156 // The callback function of FaviconService::GetLargestRawFaviconForID(). 157 void OnFaviconData(const chrome::FaviconBitmapResult& bitmap_result); 158 159 // The callback function of MoveTo(). 160 void OnMoved(AndroidHistoryProviderService::Handle handle, int pos); 161 162 JavaColumnType GetColumnTypeInternal(int column); 163 164 // Runs the MoveStatement on UI thread. 165 void RunMoveStatementOnUIThread(int pos); 166 167 // The current row position, '-1' means the position before the first one. 168 int position_; 169 170 base::WaitableEvent event_; 171 172 // The wrapped history::AndroidStatement. 173 history::AndroidStatement* statement_; 174 175 // Result set columns' name 176 const std::vector<std::string> column_names_; 177 178 AndroidHistoryProviderService* service_; 179 180 FaviconService* favicon_service_; 181 182 // Live on UI thread. 183 scoped_ptr<CancelableRequestConsumer> consumer_; 184 scoped_ptr<CancelableTaskTracker> tracker_; 185 186 // The count of result rows. 187 int count_; 188 189 // The favicon image. 190 chrome::FaviconBitmapResult favicon_bitmap_result_; 191 192 TestObserver* test_observer_; 193 194 DISALLOW_COPY_AND_ASSIGN(SQLiteCursor); 195 }; 196 197 #endif // CHROME_BROWSER_HISTORY_ANDROID_SQLITE_CURSOR_H_ 198