/* 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; import org.mozilla.gecko.db.BrowserContract.SearchHistory; import android.content.ContentUris; import android.content.ContentValues; import android.database.Cursor; import android.database.SQLException; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.text.TextUtils; import android.util.Log; public class SearchHistoryProvider extends SharedBrowserDatabaseProvider { private static final String LOG_TAG = "GeckoSearchProvider"; private static final boolean DEBUG_ENABLED = false; /** * 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); long id = -1; /* * Attempt to insert the query. The catch block handles the case when * the query already exists in the DB. */ try { cv.put(SearchHistory.QUERY, query); cv.put(SearchHistory.VISITS, 1); cv.put(SearchHistory.DATE_LAST_VISITED, System.currentTimeMillis()); id = db.insertOrThrow(SearchHistory.TABLE_NAME, null, cv); if (id > 0) { return ContentUris.withAppendedId(uri, id); } } catch (SQLException e) { // This happens when the column already exists for this term. if (DEBUG_ENABLED) { Log.w(LOG_TAG, String.format("Query `%s` already in db", query)); } } /* * Increment the VISITS counter and update 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(); } return null; } @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) { final String groupBy = null; final String having = null; final String limit = uri.getQueryParameter(BrowserContract.PARAM_LIMIT); final Cursor cursor = getReadableDatabase(uri).query(SearchHistory.TABLE_NAME, projection, selection, selectionArgs, groupBy, having, sortOrder, limit); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } @Override public String getType(Uri uri) { return SearchHistory.CONTENT_TYPE; } }