package com.madeinhk.model; import android.app.SearchManager; import android.content.ContentProvider; import android.content.ContentValues; import android.content.UriMatcher; import android.database.Cursor; import android.database.MatrixCursor; import android.database.sqlite.SQLiteDatabase; import android.net.Uri; import android.text.TextUtils; import android.util.SparseArray; import com.madeinhk.utils.ArrayUtils; import com.madeinhk.utils.ChineseUtils; import com.madeinhk.utils.EditDistanceCalculator; import com.madeinhk.utils.SimilarWordGenerator; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; /** * Created by tonymak on 10/9/14. */ public class DictionaryContentProvider extends ContentProvider { private DictionaryDatabaseHelper mDbHelper; public static final String AUTHORITY = "com.madeinhk.dictionary"; private static final int BY_ID = 1; private static final int BY_WORD = 2; private static final int WORD_SUGGESTION = 3; private static final int FAVOURITE = 4; private static final int FAVOURITE_WORDS = 5; private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); static { sUriMatcher.addURI(AUTHORITY, "by_word/*", BY_WORD); sUriMatcher.addURI(AUTHORITY, "by_id/#", BY_ID); sUriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY, WORD_SUGGESTION); sUriMatcher.addURI(AUTHORITY, SearchManager.SUGGEST_URI_PATH_QUERY + "/*", WORD_SUGGESTION); sUriMatcher.addURI(AUTHORITY, "favourite", FAVOURITE); sUriMatcher.addURI(AUTHORITY, "favourite_words", FAVOURITE_WORDS); } private static final SparseArray<String> TABLE_NAMES; static { SparseArray<String> array = new SparseArray<String>(11); array.put(BY_WORD, ECDictionary.TABLE_NAME); array.put(BY_ID, ECDictionary.TABLE_NAME); array.put(WORD_SUGGESTION, ECDictionary.TABLE_NAME); array.put(FAVOURITE, Favourite.TABLE_NAME); array.put(FAVOURITE_WORDS, "favourite_word"); TABLE_NAMES = array; } @Override public boolean onCreate() { mDbHelper = new DictionaryDatabaseHelper(getContext()); return true; } @Override public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { int code = sUriMatcher.match(uri); SQLiteDatabase db = mDbHelper.getReadableDatabase(); String table = TABLE_NAMES.get(code); switch (code) { case BY_WORD: { String word = uri.getLastPathSegment(); return db.query(table, projection, ECDictionary.COLUMNS.WORD + "=?", new String[]{word}, null, null, sortOrder); } case BY_ID: { String id = uri.getLastPathSegment(); return db .query(table, projection, ECDictionary.COLUMNS._ID + "=?", new String[]{id}, null, null, sortOrder); } case FAVOURITE: { return db.query(table, projection, selection, selectionArgs, null, null, sortOrder); } case WORD_SUGGESTION: { // Ignore the limit parameter and hardcode to be five. String query = selectionArgs[0]; MatrixCursor mc = new MatrixCursor( new String[]{"_id", "suggest_intent_data_id", "suggest_text_1", "suggest_text_2"}); if (TextUtils.isEmpty(query)) { return mc; } SimilarWordGenerator generator = new SimilarWordGenerator(); Set<String> stringList = generator.generate(query); String similarWordQuery = QueryBuilderUtil.buildWhereClauseWithIn("word", stringList.size()); String[] likeArgs = new String[]{query + "%"}; String[] args = ArrayUtils.concatenate(likeArgs, stringList.toArray(new String[0])); final String limit = "20"; Cursor cursor = db.query(table, new String[]{"_id", "word", "meaning"}, "word LIKE ? OR " + similarWordQuery, args, null, null, sortOrder, limit); try { List<Suggestion> suggestions = new ArrayList<>(); EditDistanceCalculator calculator = new EditDistanceCalculator(); while (cursor.moveToNext()) { String meaningString = cursor.getString(2); if (!TextUtils.isEmpty(meaningString)) { String id = cursor.getString(0); String word = cursor.getString(1); String strippedMeaning = ChineseUtils.convertChineseIfNeeded (meaningString.split("\\|")[1]); int editDistance = calculator.getEditDistance(query, word); Suggestion suggestion = new Suggestion(id, word, strippedMeaning, editDistance); suggestions.add(suggestion); } } Collections.sort(suggestions); for (Suggestion suggestion : suggestions) { mc.addRow(new Object[]{suggestion.id, suggestion.id, suggestion.word, suggestion.meaning}); if (mc.getCount() >= 10) { break; } } } finally { cursor.close(); } return mc; } case FAVOURITE_WORDS: { return db.query(table, projection, selection, selectionArgs, null, null, sortOrder); } } throw new IllegalArgumentException("Do not support uri: " + uri); } static class Suggestion implements Comparable<Suggestion> { String id; String word; String meaning; int editDistance; public Suggestion(String id, String word, String meaning, int editDistance) { this.id = id; this.word = word; this.meaning = meaning; this.editDistance = editDistance; } @Override public int compareTo(Suggestion another) { return this.editDistance - another.editDistance; } } @Override public String getType(Uri uri) { return null; } @Override public Uri insert(Uri uri, ContentValues contentValues) { int code = sUriMatcher.match(uri); SQLiteDatabase db = mDbHelper.getReadableDatabase(); String table = TABLE_NAMES.get(code); switch (code) { case FAVOURITE: long id = db.insertWithOnConflict(table, null, contentValues, SQLiteDatabase.CONFLICT_REPLACE); if (id != -1) { Uri ret = Favourite.CONTENT_URI.buildUpon().appendPath(String.valueOf(id)) .build(); return ret; } } throw new IllegalArgumentException("Do not support uri: " + uri); } @Override public int delete(Uri uri, String s, String[] strings) { int code = sUriMatcher.match(uri); SQLiteDatabase db = mDbHelper.getReadableDatabase(); String table = TABLE_NAMES.get(code); switch (code) { case FAVOURITE: return db.delete(table, s, strings); } throw new IllegalArgumentException("Do not support uri: " + uri); } @Override public int update(Uri uri, ContentValues contentValues, String s, String[] strings) { return 0; } private static class QueryBuilderUtil { public static String buildWhereClauseWithIn(String column, int numberOfParameters) { StringBuilder sb = new StringBuilder(); sb.append(column); sb.append(" IN ("); boolean firstItem = true; for (int i = 0; i < numberOfParameters; i++) { if (!firstItem) { sb.append(","); } else { firstItem = false; } sb.append("?"); } sb.append(")"); return sb.toString(); } } }