mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1030277 - new content provider for search history. r=rnewman
This commit is contained in:
parent
f1d01a44f9
commit
94230d4bf4
@ -33,6 +33,9 @@ public class BrowserContract {
|
||||
public static final String READING_LIST_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.readinglist";
|
||||
public static final Uri READING_LIST_AUTHORITY_URI = Uri.parse("content://" + READING_LIST_AUTHORITY);
|
||||
|
||||
public static final String SEARCH_HISTORY_AUTHORITY = AppConstants.ANDROID_PACKAGE_NAME + ".db.searchhistory";
|
||||
public static final Uri SEARCH_HISTORY_AUTHORITY_URI = Uri.parse("content://" + SEARCH_HISTORY_AUTHORITY);
|
||||
|
||||
public static final String PARAM_PROFILE = "profile";
|
||||
public static final String PARAM_PROFILE_PATH = "profilePath";
|
||||
public static final String PARAM_LIMIT = "limit";
|
||||
@ -433,6 +436,17 @@ public class BrowserContract {
|
||||
public static final String TYPE = "type";
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
public static final class SearchHistory implements CommonColumns, HistoryColumns {
|
||||
private SearchHistory() {}
|
||||
|
||||
public static final String CONTENT_TYPE = "vnd.android.cursor.dir/searchhistory";
|
||||
public static final String QUERY = "query";
|
||||
public static final String TABLE_NAME = "searchhistory";
|
||||
|
||||
public static final Uri CONTENT_URI = Uri.withAppendedPath(SEARCH_HISTORY_AUTHORITY_URI, "searchhistory");
|
||||
}
|
||||
|
||||
@RobocopTarget
|
||||
public static final class SuggestedSites implements CommonColumns, URLColumns {
|
||||
private SuggestedSites() {}
|
||||
|
@ -16,6 +16,7 @@ import org.mozilla.gecko.db.BrowserContract.Favicons;
|
||||
import org.mozilla.gecko.db.BrowserContract.History;
|
||||
import org.mozilla.gecko.db.BrowserContract.Obsolete;
|
||||
import org.mozilla.gecko.db.BrowserContract.ReadingListItems;
|
||||
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
|
||||
import org.mozilla.gecko.db.BrowserContract.Thumbnails;
|
||||
import org.mozilla.gecko.sync.Utils;
|
||||
|
||||
@ -34,7 +35,7 @@ import android.util.Log;
|
||||
final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String LOGTAG = "GeckoBrowserDBHelper";
|
||||
public static final int DATABASE_VERSION = 18;
|
||||
public static final int DATABASE_VERSION = 19;
|
||||
public static final String DATABASE_NAME = "browser.db";
|
||||
|
||||
final protected Context mContext;
|
||||
@ -749,6 +750,20 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
|
||||
createOrUpdateAllSpecialFolders(db);
|
||||
createReadingListTable(db);
|
||||
createSearchHistoryTable(db);
|
||||
}
|
||||
|
||||
private void createSearchHistoryTable(SQLiteDatabase db) {
|
||||
debug("Creating " + SearchHistory.TABLE_NAME + " table");
|
||||
|
||||
db.execSQL("CREATE TABLE " + SearchHistory.TABLE_NAME + "(" +
|
||||
SearchHistory._ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
|
||||
SearchHistory.QUERY + " TEXT UNIQUE NOT NULL, " +
|
||||
SearchHistory.DATE_LAST_VISITED + " INTEGER, " +
|
||||
SearchHistory.VISITS + " INTEGER ) ");
|
||||
|
||||
db.execSQL("CREATE INDEX idx_search_history_last_visited ON " +
|
||||
SearchHistory.TABLE_NAME + "(" + SearchHistory.DATE_LAST_VISITED + ")");
|
||||
}
|
||||
|
||||
private void createReadingListTable(SQLiteDatabase db) {
|
||||
@ -1378,6 +1393,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
}
|
||||
|
||||
private void upgradeDatabaseFrom18to19(SQLiteDatabase db) {
|
||||
createSearchHistoryTable(db);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
|
||||
debug("Upgrading browser.db: " + db.getPath() + " from " +
|
||||
@ -1454,6 +1473,10 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
case 18:
|
||||
upgradeDatabaseFrom17to18(db);
|
||||
break;
|
||||
|
||||
case 19:
|
||||
upgradeDatabaseFrom18to19(db);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1566,4 +1589,4 @@ final class BrowserDatabaseHelper extends SQLiteOpenHelper {
|
||||
bookmark.remove("folder");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
112
mobile/android/base/db/SearchHistoryProvider.java
Normal file
112
mobile/android/base/db/SearchHistoryProvider.java
Normal file
@ -0,0 +1,112 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.db;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
|
||||
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
import android.database.sqlite.SQLiteDatabase;
|
||||
import android.net.Uri;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class SearchHistoryProvider extends SharedBrowserDatabaseProvider {
|
||||
|
||||
/**
|
||||
* Collapse whitespace.
|
||||
*/
|
||||
private String stripWhitespace(String query) {
|
||||
if (TextUtils.isEmpty(query)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
// Collapse whitespace
|
||||
return query.trim().replaceAll("\\s+", " ");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Uri insertInTransaction(Uri uri, ContentValues cv) {
|
||||
final String query = stripWhitespace(cv.getAsString(SearchHistory.QUERY));
|
||||
|
||||
// We don't support inserting empty search queries.
|
||||
if (TextUtils.isEmpty(query)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
final SQLiteDatabase db = getWritableDatabase(uri);
|
||||
|
||||
/*
|
||||
* FIRST: Try incrementing the VISITS counter and updating the DATE_LAST_VISITED.
|
||||
*/
|
||||
final String sql = "UPDATE " + SearchHistory.TABLE_NAME + " SET " +
|
||||
SearchHistory.VISITS + " = " + SearchHistory.VISITS + " + 1, " +
|
||||
SearchHistory.DATE_LAST_VISITED + " = " + System.currentTimeMillis() +
|
||||
" WHERE " + SearchHistory.QUERY + " = ?";
|
||||
final Cursor c = db.rawQuery(sql, new String[] { query });
|
||||
|
||||
try {
|
||||
if (c.getCount() > 1) {
|
||||
// There is a UNIQUE constraint on the QUERY column,
|
||||
// so there should only be one match.
|
||||
return null;
|
||||
}
|
||||
if (c.moveToFirst()) {
|
||||
return ContentUris
|
||||
.withAppendedId(uri, c.getInt(c.getColumnIndex(SearchHistory._ID)));
|
||||
}
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
/*
|
||||
* SECOND: If the update failed, then insert a new record.
|
||||
*/
|
||||
cv.put(SearchHistory.QUERY, query);
|
||||
cv.put(SearchHistory.VISITS, 1);
|
||||
cv.put(SearchHistory.DATE_LAST_VISITED, System.currentTimeMillis());
|
||||
|
||||
long id = db.insert(SearchHistory.TABLE_NAME, null, cv);
|
||||
|
||||
if (id < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ContentUris.withAppendedId(uri, id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int deleteInTransaction(Uri uri, String selection, String[] selectionArgs) {
|
||||
return getWritableDatabase(uri)
|
||||
.delete(SearchHistory.TABLE_NAME, selection, selectionArgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* Since we are managing counts and the full-text db, an update
|
||||
* could mangle the internal state. So we disable it.
|
||||
*/
|
||||
@Override
|
||||
public int updateInTransaction(Uri uri, ContentValues values, String selection,
|
||||
String[] selectionArgs) {
|
||||
throw new UnsupportedOperationException(
|
||||
"This content provider does not support updating items");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Cursor query(Uri uri, String[] projection, String selection,
|
||||
String[] selectionArgs, String sortOrder) {
|
||||
String groupBy = null;
|
||||
String having = null;
|
||||
return getReadableDatabase(uri)
|
||||
.query(SearchHistory.TABLE_NAME, projection, selection, selectionArgs,
|
||||
groupBy, having, sortOrder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getType(Uri uri) {
|
||||
return SearchHistory.CONTENT_TYPE;
|
||||
}
|
||||
}
|
@ -150,6 +150,7 @@ gbjar.sources += [
|
||||
'db/PerProfileDatabaseProvider.java',
|
||||
'db/PerProfileDatabases.java',
|
||||
'db/ReadingListProvider.java',
|
||||
'db/SearchHistoryProvider.java',
|
||||
'db/SharedBrowserDatabaseProvider.java',
|
||||
'db/SQLiteBridgeContentProvider.java',
|
||||
'db/SuggestedSites.java',
|
||||
|
@ -80,6 +80,7 @@ skip-if = processor == "x86"
|
||||
skip-if = processor == "x86"
|
||||
# [testReaderMode] # see bug 913254, 936224
|
||||
[testReadingListProvider]
|
||||
[testSearchHistoryProvider]
|
||||
[testSearchSuggestions]
|
||||
# disabled on x86; bug 907768
|
||||
skip-if = processor == "x86"
|
||||
|
269
mobile/android/base/tests/testSearchHistoryProvider.java
Normal file
269
mobile/android/base/tests/testSearchHistoryProvider.java
Normal file
@ -0,0 +1,269 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
package org.mozilla.gecko.tests;
|
||||
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import org.mozilla.gecko.db.BrowserContract;
|
||||
import org.mozilla.gecko.db.BrowserContract.SearchHistory;
|
||||
import org.mozilla.gecko.db.SearchHistoryProvider;
|
||||
|
||||
import android.content.ContentProvider;
|
||||
import android.content.ContentValues;
|
||||
import android.database.Cursor;
|
||||
|
||||
public class testSearchHistoryProvider extends ContentProviderTest {
|
||||
|
||||
// Translations of "United Kingdom" in several different languages
|
||||
private static final String[] testStrings = {"An Ríocht Aontaithe", // Irish
|
||||
"Angli", // Albanian
|
||||
"Britanniarum Regnum", // Latin
|
||||
"Britio", // Esperanto
|
||||
"Büyük Britanya", // Turkish
|
||||
"Egyesült Királyság", // Hungarian
|
||||
"Erresuma Batua", // Basque
|
||||
"Inggris Raya", // Indonesian
|
||||
"Ir-Renju Unit", // Maltese
|
||||
"Iso-Britannia", // Finnish
|
||||
"Jungtinė Karalystė", // Lithuanian
|
||||
"Lielbritānija", // Latvian
|
||||
"Regatul Unit", // Romanian
|
||||
"Regne Unit", // Catalan, Valencian
|
||||
"Regno Unito", // Italian
|
||||
"Royaume-Uni", // French
|
||||
"Spojené království", // Czech
|
||||
"Spojené kráľovstvo", // Slovak
|
||||
"Storbritannia", // Norwegian
|
||||
"Storbritannien", // Danish
|
||||
"Suurbritannia", // Estonian
|
||||
"Ujedinjeno Kraljevstvo", // Bosnian
|
||||
"United Alaeze", // Igbo
|
||||
"United Kingdom", // English
|
||||
"Vereinigtes Königreich", // German
|
||||
"Verenigd Koninkrijk", // Dutch
|
||||
"Verenigde Koninkryk", // Afrikaans
|
||||
"Vương quốc Anh", // Vietnamese
|
||||
"Wayòm Ini", // Haitian, Haitian Creole
|
||||
"Y Deyrnas Unedig", // Welsh
|
||||
"Združeno kraljestvo", // Slovene
|
||||
"Zjednoczone Królestwo", // Polish
|
||||
"Ηνωμένο Βασίλειο", // Greek (modern)
|
||||
"Великобритания", // Russian
|
||||
"Нэгдсэн Вант Улс", // Mongolian
|
||||
"Обединетото Кралство", // Macedonian
|
||||
"Уједињено Краљевство", // Serbian
|
||||
"Միացյալ Թագավորություն", // Armenian
|
||||
"בריטניה", // Hebrew (modern)
|
||||
"פֿאַראייניקטע מלכות", // Yiddish
|
||||
"المملكة المتحدة", // Arabic
|
||||
"برطانیہ", // Urdu
|
||||
"پادشاهی متحده", // Persian (Farsi)
|
||||
"यूनाइटेड किंगडम", // Hindi
|
||||
"संयुक्त राज्य", // Nepali
|
||||
"যুক্তরাজ্য", // Bengali, Bangla
|
||||
"યુનાઇટેડ કિંગડમ", // Gujarati
|
||||
"ஐக்கிய ராஜ்யம்", // Tamil
|
||||
"สหราชอาณาจักร", // Thai
|
||||
"ສະຫະປະຊາຊະອານາຈັກ", // Lao
|
||||
"გაერთიანებული სამეფო", // Georgian
|
||||
"イギリス", // Japanese
|
||||
"联合王国" // Chinese
|
||||
};
|
||||
|
||||
|
||||
private static final String DB_NAME = "searchhistory.db";
|
||||
|
||||
/**
|
||||
* Boilerplate alert.
|
||||
* <p/>
|
||||
* Make sure this method is present and that it returns a new
|
||||
* instance of your class.
|
||||
*/
|
||||
private static Callable<ContentProvider> sProviderFactory =
|
||||
new Callable<ContentProvider>() {
|
||||
@Override
|
||||
public ContentProvider call() {
|
||||
return new SearchHistoryProvider();
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp(sProviderFactory, BrowserContract.SEARCH_HISTORY_AUTHORITY, DB_NAME);
|
||||
mTests.add(new TestInsert());
|
||||
mTests.add(new TestUnicodeQuery());
|
||||
mTests.add(new TestTimestamp());
|
||||
mTests.add(new TestDelete());
|
||||
mTests.add(new TestIncrement());
|
||||
}
|
||||
|
||||
public void testSearchHistory() throws Exception {
|
||||
for (Runnable test : mTests) {
|
||||
String testName = test.getClass().getSimpleName();
|
||||
setTestName(testName);
|
||||
mAsserter.dumpLog(
|
||||
"testBrowserProvider: Database empty - Starting " + testName + ".");
|
||||
// Clear the db
|
||||
mProvider.delete(SearchHistory.CONTENT_URI, null, null);
|
||||
test.run();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we can insert values into the DB, including unicode.
|
||||
*/
|
||||
private class TestInsert extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ContentValues cv;
|
||||
for (int i = 0; i < testStrings.length; i++) {
|
||||
cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, testStrings[i]);
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
}
|
||||
|
||||
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
mAsserter.is(c.getCount(), testStrings.length,
|
||||
"Should have one row for each insert");
|
||||
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that we can insert values into the DB, including unicode.
|
||||
*/
|
||||
private class TestUnicodeQuery extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ContentValues cv;
|
||||
Cursor c = null;
|
||||
String selection = SearchHistory.QUERY + " = ?";
|
||||
|
||||
for (int i = 0; i < testStrings.length; i++) {
|
||||
cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, testStrings[i]);
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
|
||||
c = mProvider.query(SearchHistory.CONTENT_URI, null, selection,
|
||||
new String[]{ testStrings[i] }, null);
|
||||
mAsserter.is(c.getCount(), 1,
|
||||
"Should have one row for insert of " + testStrings[i]);
|
||||
}
|
||||
|
||||
if (c != null) {
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that timestamps are updated on insert.
|
||||
*/
|
||||
private class TestTimestamp extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
String insertedTerm = "Courtside Seats";
|
||||
long insertStart;
|
||||
long insertFinish;
|
||||
long t1Db;
|
||||
long t2Db;
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, insertedTerm);
|
||||
|
||||
// First check that the DB has a value that is close to the
|
||||
// system time.
|
||||
insertStart = System.currentTimeMillis();
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
c.moveToFirst();
|
||||
t1Db = c.getLong(c.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
|
||||
c.close();
|
||||
insertFinish = System.currentTimeMillis();
|
||||
mAsserter.ok(t1Db >= insertStart, "DATE_LAST_VISITED",
|
||||
"Date last visited should be set on insert.");
|
||||
mAsserter.ok(t1Db <= insertFinish, "DATE_LAST_VISITED",
|
||||
"Date last visited should be set on insert.");
|
||||
|
||||
cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, insertedTerm);
|
||||
|
||||
insertStart = System.currentTimeMillis();
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
c.moveToFirst();
|
||||
t2Db = c.getLong(c.getColumnIndex(SearchHistory.DATE_LAST_VISITED));
|
||||
c.close();
|
||||
insertFinish = System.currentTimeMillis();
|
||||
|
||||
mAsserter.ok(t2Db >= insertStart, "DATE_LAST_VISITED",
|
||||
"Date last visited should be set on insert.");
|
||||
mAsserter.ok(t2Db <= insertFinish, "DATE_LAST_VISITED",
|
||||
"Date last visited should be set on insert.");
|
||||
mAsserter.ok(t2Db > t1Db, "DATE_LAST_VISITED",
|
||||
"Date last visited should be updated on key increment.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that sending a delete command empties the database.
|
||||
*/
|
||||
private class TestDelete extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
String insertedTerm = "Courtside Seats";
|
||||
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, insertedTerm);
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
|
||||
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
mAsserter.is(c.getCount(), 1, "Should have one value");
|
||||
mProvider.delete(SearchHistory.CONTENT_URI, null, null);
|
||||
c.close();
|
||||
|
||||
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
mAsserter.is(c.getCount(), 0, "Should be empty");
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
c.close();
|
||||
|
||||
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
mAsserter.is(c.getCount(), 1, "Should have one value");
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure that we only increment when the case matches.
|
||||
*/
|
||||
private class TestIncrement extends TestCase {
|
||||
@Override
|
||||
public void test() throws Exception {
|
||||
ContentValues cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, "omaha");
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
|
||||
cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, "omaha");
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
|
||||
Cursor c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
c.moveToFirst();
|
||||
mAsserter.is(c.getCount(), 1, "Should have one result");
|
||||
mAsserter.is(c.getInt(c.getColumnIndex(SearchHistory.VISITS)), 2,
|
||||
"Counter should be 2");
|
||||
c.close();
|
||||
|
||||
cv = new ContentValues();
|
||||
cv.put(SearchHistory.QUERY, "Omaha");
|
||||
mProvider.insert(SearchHistory.CONTENT_URI, cv);
|
||||
c = mProvider.query(SearchHistory.CONTENT_URI, null, null, null, null);
|
||||
mAsserter.is(c.getCount(), 2, "Should have two results");
|
||||
c.close();
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user