1
0
Fork 0

Big changes: Multilingual, dbupdating, bugfixes:

* Multilingual backend support with initial Russian language support
* Updater service to update the database in the background, and overhauled
backend access
* Fixed long pressing numbers in Lang mode would not input digit
* Fixed Add Word not behaving as you would expect
* Some other minor fixes
This commit is contained in:
Clam 2014-02-17 00:03:14 +11:00
parent 878a8e594a
commit b0d403257b
64 changed files with 3040 additions and 1704 deletions

View file

@ -1,11 +1,16 @@
package org.nyanya.android.traditionalt9;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Locale;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.sqlite.SQLiteConstraintException;
@ -13,11 +18,15 @@ import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.util.Log;
import android.widget.Toast;
public class T9DB {
private static volatile T9DB instance = null;
protected boolean ready = true;
protected static final String DATABASE_NAME = "t9dict.db";
protected static final int DATABASE_VERSION = 1;
protected static final int DATABASE_VERSION = 2;
protected static final String WORD_TABLE_NAME = "word";
protected static final String FREQ_TRIGGER_NAME = "freqtrigger";
// 50k, 10k
@ -25,11 +34,15 @@ public class T9DB {
private static final int FREQ_DIV = 10000;
protected static final String COLUMN_ID = BaseColumns._ID;
protected static final String COLUMN_LANG = "lang";
protected static final String COLUMN_SEQ = "seq";
protected static final String COLUMN_WORD = "word";
protected static final String COLUMN_FREQUENCY = "freq";
private static final String QUERY1 = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD + " FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_LANG + "=? AND " + COLUMN_SEQ + "=?" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC";
private static final int MAX_RESULTS = 8;
private static final int CAPS_OFF = 0;
@ -39,78 +52,157 @@ public class T9DB {
private DatabaseHelper mOpenHelper;
private SQLiteDatabase db;
private Context parent;
private Context mContext;
public T9DB(Context caller) {
// create db
parent = caller;
mContext = caller;
mOpenHelper = new DatabaseHelper(caller);
}
public static SQLiteDatabase getSQLDB(Context caller) {
return new DatabaseHelper(caller).getWritableDatabase();
public static T9DB getInstance(Context caller) {
if (instance == null) {
synchronized (T9DB.class){
if (instance == null) {
instance = new T9DB (caller);
instance.init();
}
}
}
return instance;
}
public void init() {
db = mOpenHelper.getWritableDatabase();
// mOpenHelper.onUpgrade(db, 0, DATABASE_VERSION);
public static SQLiteDatabase getSQLDB(Context caller) {
T9DB t9dbhelper = getInstance(caller);
//Log.d("T9DB.getSQLDB", "db:" + t9dbhelper.db.isOpen());
return t9dbhelper.db;
}
private void init() {
if (mOpenHelper.needsUpgrading() ) {
ready = false;
Log.i("T9.init", "needsUpgrading");
// start updating service
if (db != null) {
try {
db.close();
} catch (NullPointerException e) { }
db = null;
}
Intent intent = new Intent(mContext, DBUpdateService.class);
Log.i("T9.init", "Invoking update service...");
mContext.startService(intent);
} else {
db = mOpenHelper.getWritableDatabase();
}
}
protected boolean checkReady() {
if (ready) {
if (db == null) {
db = getWritableDatabase();
}
return true;
} else {
return false;
}
}
protected SQLiteDatabase getWritableDatabase() {
return mOpenHelper.getWritableDatabase();
}
protected void setSQLDB(SQLiteDatabase tdb) {
synchronized (T9DB.class){
db = tdb;
ready = true;
}
}
public void close() {
db.close();
}
public void nuke() {
init();
mOpenHelper.onUpgrade(db, 0, DATABASE_VERSION);
db.close();
try { db.close(); }
catch (NullPointerException e) { }
db = null;
}
public void addWord(String iword) throws DBException {
Resources r = parent.getResources();
public void nuke() {
Log.i("T9DB.nuke", "Deleting database...");
synchronized (T9DB.class){
if (db != null) {
db.close();
}
if (!mContext.deleteDatabase(DATABASE_NAME)) {
Log.e("T9DB", "Couldn't delete database.");
}
Log.i("T9DB.nuke", "Preparing database...");
getWritableDatabase().close();
db = null;
ready = true;
init();
}
Log.i("T9DB.nuke", "Done...");
}
public void addWord(String iword, int lang) throws DBException {
Resources r = mContext.getResources();
if (iword.equals("")) {
throw new DBException(r.getString(R.string.add_word_blank));
}
// get int sequence
String seq;
try {
seq = CharMap.getStringSequence(iword);
seq = CharMap.getStringSequence(iword, lang);
} catch (NullPointerException e) {
throw new DBException(r.getString(R.string.add_word_badchar));
throw new DBException(r.getString(R.string.add_word_badchar, LangHelper.LANGS[lang]));
}
// add int sequence into num table
ContentValues values = new ContentValues();
values.put(COLUMN_SEQ, seq);
values.put(COLUMN_LANG, lang);
// add word into word
values.put(COLUMN_WORD, iword);
values.put(COLUMN_FREQUENCY, 1);
if (!checkReady()) {
Log.e("T9DB.addWord", "not ready");
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
return;
}
try {
db.insertOrThrow(WORD_TABLE_NAME, null, values);
} catch (SQLiteConstraintException e) {
String msg = r.getString(R.string.add_word_exist1) + iword
+ r.getString(R.string.add_word_exist2);
String msg = r.getString(R.string.add_word_exist2, iword, LangHelper.LANGS[lang]);
Log.w("T9DB.addWord", msg);
throw new DBException(msg);
}
}
public void incrementWord(int id) {
if (!checkReady()) {
Log.e("T9DB.incrementWord", "not ready");
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
return;
}
db.execSQL(
"UPDATE " + WORD_TABLE_NAME +
" SET " + COLUMN_FREQUENCY + " = " + COLUMN_FREQUENCY + "+ 1" +
" WHERE " + COLUMN_ID + " = \"" + id + "\"");
// if id's freq is greater than X we should normalise those with the
// same seq
"UPDATE " + WORD_TABLE_NAME +
" SET " + COLUMN_FREQUENCY + " = " + COLUMN_FREQUENCY + "+ 1" +
" WHERE " + COLUMN_ID + " = \"" + id + "\"");
// if id's freq is greater than FREQ_MAX, it gets normalized with trigger
}
protected String getWord(String is) {
protected String getWord(String is, int lang) {
String result = null;
String q =
"SELECT " + COLUMN_WORD + " FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_SEQ + "=?" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC";
Cursor cur = db.rawQuery(q, new String[] { is });
String q =
"SELECT " + COLUMN_WORD + " FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_LANG + "=? AND " + COLUMN_SEQ + "=?" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC";
if (!checkReady()) {
Log.e("T9DB.getWord", "not ready");
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
return "";
}
Cursor cur = db.rawQuery(q, new String[] { is, String.valueOf(lang) });
int hits = 0;
if (cur.moveToFirst()) {
result = cur.getString(0);
@ -122,15 +214,15 @@ public class T9DB {
int islen = is.length();
char c = is.charAt(islen - 1);
c++;
q = "SELECT " + COLUMN_WORD + " FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_SEQ + " >= '" + is + "1" + "' AND " + COLUMN_SEQ + " < '"
+ is.substring(0, islen - 1) + c + "'" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC, " + COLUMN_SEQ + " ASC" +
" LIMIT " + (MAX_RESULTS - hits);
cur = db.rawQuery(q, null);
q = "SELECT " + COLUMN_WORD + " FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_LANG + "=? AND " + COLUMN_SEQ + " >= '" + is + "1" +
"' AND " + COLUMN_SEQ + " < '" + is.substring(0, islen - 1) + c + "'" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC, " + COLUMN_SEQ + " ASC" +
" LIMIT " + (MAX_RESULTS - hits);
cur = db.rawQuery(q, new String[] { String.valueOf(lang) });
if (cur.moveToFirst()) {
result = cur.getString(1);
result = cur.getString(0);
}
if (result == null) {
result = "";
@ -139,50 +231,48 @@ public class T9DB {
}
return result;
}
public void updateWords(String is, ArrayList<String> stringList, ArrayList<Integer> intList,
int capsMode) {
int capsMode, int lang) {
stringList.clear();
intList.clear();
// String[] sa = packInts(stringToInts(is), true);
int islen = is.length();
String q =
"SELECT " + COLUMN_ID + ", " + COLUMN_WORD + " FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_SEQ + "=?" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC";
Cursor cur = db.rawQuery(q, new String[] { is });
if (!checkReady()) {
Log.e("T9DB.updateWords", "not ready");
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
return;
}
Cursor cur = db.rawQuery(QUERY1, new String[] { String.valueOf(lang), is });
int hits = 0;
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
stringList.add(cur.getString(1));
if (hits >= 15) {
break;
}
// if (hits >= 15) {
// break;
// }
hits++;
}
cur.close();
if (hits < 4) {
// TODO: profile this and if it takes too long to only do it when hits is super low...
if (hits < 10) {
char c = is.charAt(islen - 1);
c++;
// q = "SELECT " + COLUMN_WORD +", " + COLUMN_FREQUENCY +
// " FROM " + WORD_TABLE_NAME +
// " WHERE " + COLUMN_SEQ + " LIKE ?" +
// " ORDER BY " + COLUMN_SEQ + " ASC, " + COLUMN_FREQUENCY +
// " DESC;";
// c = db.rawQuery(q, new String[] {is + "_%"});
// above is hella slow below is gotta query fast
q = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD +
" FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_SEQ + " >= '" + is + "1" + "' AND " + COLUMN_SEQ + " < '"
+ is.substring(0, islen - 1) + c + "'" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC, " + COLUMN_SEQ + " ASC" +
" LIMIT " + (MAX_RESULTS - hits);
cur = db.rawQuery(q, null);
String q = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD +
" FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_LANG + "=? AND " + COLUMN_SEQ + " >= '" + is + "1" +
"' AND " + COLUMN_SEQ + " < '" + is.substring(0, islen - 1) + c + "'" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC, " + COLUMN_SEQ + " ASC" +
" LIMIT " + (MAX_RESULTS - hits);
cur = db.rawQuery(q, new String[] { String.valueOf(lang) });
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
stringList.add(cur.getString(1));
if (hits >= 10) {
if (hits >= 20) {
break;
}
hits++;
@ -203,36 +293,36 @@ public class T9DB {
while (iter.hasNext()) {
word = iter.next();
switch (capsMode) {
case CAPS_ALL:
wordtemp = word.toUpperCase(Locale.US);
if (wordtemp.equals(word)) {
index++;
continue;
} else if (stringList.contains(wordtemp)) {
// remove this entry
iter.remove();
removed = true;
} else {
stringList.set(index, wordtemp);
}
break;
case CAPS_SINGLE:
if (word.length() > 1) {
wordtemp = word.substring(0, 1).toUpperCase(Locale.US) + word.substring(1);
} else {
wordtemp = word.toUpperCase(Locale.US);
}
if (wordtemp.equals(word)) {
index++;
continue;
} else if (stringList.contains(wordtemp)) {
// remove this entry
iter.remove();
removed = true;
} else {
stringList.set(index, wordtemp);
}
break;
case CAPS_ALL:
wordtemp = word.toUpperCase(LangHelper.LOCALES[lang]);
if (wordtemp.equals(word)) {
index++;
continue;
} else if (stringList.contains(wordtemp)) {
// remove this entry
iter.remove();
removed = true;
} else {
stringList.set(index, wordtemp);
}
break;
case CAPS_SINGLE:
if (word.length() > 1) {
wordtemp = word.substring(0, 1).toUpperCase(LangHelper.LOCALES[lang]) + word.substring(1);
} else {
wordtemp = word.toUpperCase(LangHelper.LOCALES[lang]);
}
if (wordtemp.equals(word)) {
index++;
continue;
} else if (stringList.contains(wordtemp)) {
// remove this entry
iter.remove();
removed = true;
} else {
stringList.set(index, wordtemp);
}
break;
}
if (removed) {
intList.remove(index);
@ -241,21 +331,27 @@ public class T9DB {
index++;
}
}
//Log.d("T9DB.updateWords", "i:" + is + " words:" + Arrays.toString(stringList.toArray()));
return;
}
protected void updateWordsW(String is, ArrayList<String> stringList,
ArrayList<Integer> intList, ArrayList<Integer> freq) {
ArrayList<Integer> intList, ArrayList<Integer> freq, int lang) {
stringList.clear();
intList.clear();
freq.clear();
// String[] sa = packInts(stringToInts(is), true);
int islen = is.length();
String q = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD + ", " + COLUMN_FREQUENCY +
" FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_SEQ + "=?" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC";
Cursor cur = db.rawQuery(q, new String[] { is });
String q = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD + ", " + COLUMN_FREQUENCY +
" FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_LANG + "=? AND " + COLUMN_SEQ + "=?" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC";
if (!checkReady()) {
Log.e("T9DB.updateWordsW", "not ready");
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
return;
}
Cursor cur = db.rawQuery(q, new String[] { is, String.valueOf(lang) });
int hits = 0;
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
@ -270,20 +366,13 @@ public class T9DB {
if (hits < 4) {
char c = is.charAt(islen - 1);
c++;
// q = "SELECT " + COLUMN_WORD +", " + COLUMN_FREQUENCY +
// " FROM " + WORD_TABLE_NAME +
// " WHERE " + COLUMN_SEQ + " LIKE ?" +
// " ORDER BY " + COLUMN_SEQ + " ASC, " + COLUMN_FREQUENCY +
// " DESC;";
// c = db.rawQuery(q, new String[] {is + "_%"});
// above is hella slow
q = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD + ", " + COLUMN_FREQUENCY +
" FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_SEQ + " >= '" + is + "' AND " + COLUMN_SEQ
+ " < '" + is.substring(0, islen - 1) + c + "'" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC, " + COLUMN_SEQ + " ASC" +
" LIMIT " + (MAX_RESULTS - hits);
cur = db.rawQuery(q, null);
q = "SELECT " + COLUMN_ID + ", " + COLUMN_WORD + ", " + COLUMN_FREQUENCY +
" FROM " + WORD_TABLE_NAME +
" WHERE " + COLUMN_LANG + "=? AND " + COLUMN_SEQ + " >= '" + is +
"' AND " + COLUMN_SEQ + " < '" + is.substring(0, islen - 1) + c + "'" +
" ORDER BY " + COLUMN_FREQUENCY + " DESC, " + COLUMN_SEQ + " ASC" +
" LIMIT " + (MAX_RESULTS - hits);
cur = db.rawQuery(q, new String[] { String.valueOf(lang) });
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
@ -301,37 +390,64 @@ public class T9DB {
private static class DatabaseHelper extends SQLiteOpenHelper {
Context mContext = null;
DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
}
// partial code from parent class SQLiteOpenHelper
protected boolean needsUpgrading() {
//quick and dirty check to see if an existing database exists.
if (mContext.databaseList().length > 0) {
SQLiteDatabase db = mContext.openOrCreateDatabase(DATABASE_NAME, 0, null);
int version = db.getVersion();
db.close();
if (version < DATABASE_VERSION) {
return true;
}
else {
return false;
}
} else {
return false;
}
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE " + WORD_TABLE_NAME + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_SEQ + " TEXT, " +
COLUMN_WORD + " TEXT UNIQUE, " +
COLUMN_FREQUENCY + " INTEGER" + ")");
db.execSQL("CREATE TABLE IF NOT EXISTS " + WORD_TABLE_NAME + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COLUMN_LANG + " INTEGER, " +
COLUMN_SEQ + " TEXT, " +
COLUMN_WORD + " TEXT, " +
COLUMN_FREQUENCY + " INTEGER, " +
"UNIQUE(" + COLUMN_LANG + ", " + COLUMN_WORD + ") )");
db.execSQL("CREATE INDEX idx ON " + WORD_TABLE_NAME + "("
+ COLUMN_SEQ + " ASC, " + COLUMN_FREQUENCY + " DESC )");
db.execSQL("CREATE TRIGGER " + FREQ_TRIGGER_NAME +
" AFTER UPDATE ON " + WORD_TABLE_NAME +
" WHEN NEW." + COLUMN_FREQUENCY + " > " + FREQ_MAX +
" BEGIN" +
+ COLUMN_LANG + ", " + COLUMN_SEQ + " ASC, " + COLUMN_FREQUENCY + " DESC )");
db.execSQL("CREATE TRIGGER IF NOT EXISTS " + FREQ_TRIGGER_NAME +
" AFTER UPDATE ON " + WORD_TABLE_NAME +
" WHEN NEW." + COLUMN_FREQUENCY + " > " + FREQ_MAX +
" BEGIN" +
" UPDATE " + WORD_TABLE_NAME + " SET " + COLUMN_FREQUENCY + " = "
+ COLUMN_FREQUENCY + " / " + FREQ_DIV +
" WHERE " + COLUMN_SEQ + " = NEW." + COLUMN_SEQ + ";" +
" END;");
+ COLUMN_FREQUENCY + " / " + FREQ_DIV +
" WHERE " + COLUMN_SEQ + " = NEW." + COLUMN_SEQ + ";" +
" END;");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.w("T9DB", "Upgrading database from version " + oldVersion + " to " + newVersion
+ ", which will destroy all old data");
db.execSQL("DROP TABLE IF EXISTS " + WORD_TABLE_NAME);
db.execSQL("DROP INDEX IF EXISTS idx");
onCreate(db);
Log.w("T9DB", "Done.");
Log.i("T9DB.onUpgrade", "Upgrading database from version " + oldVersion + " to " + newVersion);
if (oldVersion == 1) {
db.execSQL("ALTER TABLE " + WORD_TABLE_NAME + " ADD COLUMN " +
COLUMN_LANG + " INTEGER");
db.execSQL("DROP INDEX IF EXISTS idx");
onCreate(db);
ContentValues updatedata = new ContentValues();
updatedata.put(COLUMN_LANG, 0);
db.update(WORD_TABLE_NAME, updatedata, null, null);
}
Log.i("T9DB.onUpgrade", "Done.");
}
}
}