1
0
Fork 0

Settings in SharedPreferences (#36)

* moved all settings from SQLite to SharedPreferences. The database now contains only dictionaries.

* removed key remapping, dictionary backup and nuke functions along with a bunch of unused code and translations
This commit is contained in:
Dimo Karaivanov 2022-08-05 14:18:53 +03:00 committed by GitHub
parent 8a025297c3
commit 5d3894e403
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 645 additions and 1460 deletions

View file

@ -10,7 +10,9 @@ import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
import io.github.sspanak.tt9.db.DBException;
import io.github.sspanak.tt9.db.T9DB;
import io.github.sspanak.tt9.preferences.T9Preferences;
public class AddWordAct extends Activity {
@ -45,9 +47,8 @@ public class AddWordAct extends Activity {
}
public void doAddWord(String text) {
T9DB db = T9DB.getInstance(this);
try {
db.addWord(text, LangHelper.LANGUAGE.get(lang));
T9DB.getInstance(this).addWord(text, LangHelper.LANGUAGE.get(lang));
} catch (DBException e) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String msg = e.getMessage();
@ -62,7 +63,7 @@ public class AddWordAct extends Activity {
AlertDialog dialog = builder.create();
dialog.show();
}
db.storeSettingString(SETTING.LAST_WORD, text);
T9Preferences.getInstance(this).setLastWord(text);
}

View file

@ -163,7 +163,7 @@ public class CharMap {
protected static final int[] BGT9CAPSTART = { 0, 0, 4, 4, 4, 4, 4, 4, 3, 3, 0, 0, 0 };
protected static final int[][] T9CAPSTART = {ENT9CAPSTART, RUT9CAPSTART, DET9CAPSTART, FRT9CAPSTART, ITT9CAPSTART, UKT9CAPSTART, BGT9CAPSTART};
protected static String getStringSequence(String word, LANGUAGE lang) {
public static String getStringSequence(String word, LANGUAGE lang) {
StringBuilder seq = new StringBuilder();
String tword = word.toLowerCase(LangHelper.LOCALES[lang.index]);
for (int i = 0; i < word.length(); i++) {

View file

@ -1,60 +0,0 @@
package io.github.sspanak.tt9;
import android.os.Environment;
import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
public class KeyMap {
public static final String keymapfname = "keymap.txt";
public static Map<Integer, Integer> keyMapping = new HashMap<Integer, Integer>();
static {
setKeys();
}
public static int setKeys() {
int msg = 0;
keyMapping = new HashMap<Integer, Integer>();
// check storage
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())
|| Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
// check for file
if ((new File(new File(Environment.getExternalStorageDirectory(), TraditionalT9Settings.sddir),
keymapfname)).exists()) {
BufferedReader br = null;
Log.d("T9.KeyMap", "Attemping to load keys");
try {
br = new BufferedReader(new FileReader(new File(
new File(Environment.getExternalStorageDirectory(), TraditionalT9Settings.sddir), keymapfname)));
String line;
try {
while ((line = br.readLine()) != null) {
String[] ws = line.split(" ");
if (ws.length != 2) {continue;}
else if (line.startsWith("#")) {continue;}
try {
keyMapping.put(Integer.parseInt(ws[0]), Integer.parseInt(ws[1]));
} catch (NumberFormatException _ignore) {
Log.w("T9.KeyMap", "Invalid number found");
msg = R.string.pref_reloadKeysDoneWE;
}
}
Log.d("T9.KeyMap", "Done.");
} catch (IOException _ignore) {
Log.e("T9.KeyMap", "Error while reading line.");
try { br.close(); }
catch (IOException ignored) {}
}
} catch (FileNotFoundException ignored) { msg = R.string.pref_reloadKeysDone; }
} else { msg = R.string.pref_reloadKeysNoFile; }
} else { msg = R.string.pref_reloadKeysNoFile; }
return msg;
}
}

View file

@ -29,7 +29,7 @@ public class LangHelper {
public static LANGUAGE get(int i) { return lookup.get(i);}
}
protected static final Locale[] LOCALES = {Locale.ENGLISH, RUSSIAN, Locale.GERMAN, Locale.FRENCH, Locale.ITALIAN, UKRAINIAN, BULGARIAN};
public static final Locale[] LOCALES = {Locale.ENGLISH, RUSSIAN, Locale.GERMAN, Locale.FRENCH, Locale.ITALIAN, UKRAINIAN, BULGARIAN};
public static final int LANG_DEFAULT = LANGUAGE.EN.id;

View file

@ -1,561 +0,0 @@
package io.github.sspanak.tt9;
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;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.provider.BaseColumns;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
import io.github.sspanak.tt9.LangHelper.LANGUAGE;
import java.util.AbstractList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
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 = 4;
protected static final String WORD_TABLE_NAME = "word";
protected static final String SETTING_TABLE_NAME = "setting";
protected static final String FREQ_TRIGGER_NAME = "freqtrigger";
// 50k, 10k
private static final int FREQ_MAX = 50000;
private static final int FREQ_DIV = 10000;
// This seems to be pretty fast on my phone. 10 is pretty slow (Might be because > MAX_RESULTS (8).)
private static final int MINHITS = 4;
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 String UPDATEQ = "UPDATE " + WORD_TABLE_NAME +
" SET " + COLUMN_FREQUENCY + " = " + COLUMN_FREQUENCY + "+1" +
" WHERE " + COLUMN_ID + "=";
private static final int MAX_RESULTS = 8;
private static final int MAX_MAX_RESULTS = 30; // to make sure we don't exceed candidate view array.
private static final int CAPS_OFF = 0;
private static final int CAPS_SINGLE = 1;
private static final int CAPS_ALL = 2;
private DatabaseHelper mOpenHelper;
private SQLiteDatabase db;
private Context mContext;
public static class DBSettings {
public enum SETTING {
INPUT_MODE("pref_inputmode", 0, 0),
LANG_SUPPORT("pref_lang_support", 1, 1),
MODE_NOTIFY("pref_mode_notify", 0, 2), // no longer in use; delete in #7
LAST_LANG("set_last_lang", 1, 5),
LAST_WORD("set_last_word", null, 6),
SPACE_ZERO("pref_spaceOnZero", 0, 4), // no longer in use; delete in #7
KEY_REMAP("pref_keyMap", 0, 3); // no longer in use; delete in #7
public final String id;
public final Integer defvalue;
public final int sqOrder; // used for building SettingsUI
// lookup map
private static final Map<String, SETTING> lookup = new HashMap<String, SETTING>();
private static final SETTING[] settings = SETTING.values();
static { for (SETTING l : settings) lookup.put(l.id, l); }
private SETTING(String id, Integer defval, int sqOrder) {
this.id = id; this.defvalue = defval; this.sqOrder = sqOrder;
}
public static SETTING get(String i) { return lookup.get(i);}
public static StringBuilder join(SETTING[] settings, StringBuilder sb) {
for (int x=0; x<settings.length; x++) {
sb.append(settings[x].id);
if (x < settings.length-1)
sb.append(", ");
}
return sb;
}
}
protected static final String SETTINGQUERY = " FROM " + SETTING_TABLE_NAME +
" WHERE " + COLUMN_ID + "=1";
}
public T9DB(Context caller) {
// create db
mContext = caller;
mOpenHelper = new DatabaseHelper(caller);
}
public static T9DB getInstance(Context caller) {
if (instance == null) {
synchronized (T9DB.class){
if (instance == null) {
instance = new T9DB (caller);
instance.init();
}
}
}
return instance;
}
protected 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 ignored) { }
db = null;
}
Intent intent = new Intent(mContext, DBUpdateService.class);
Log.i("T9.init", "Invoking update service...");
mContext.startService(intent);
} else {
db = mOpenHelper.getWritableDatabase();
}
}
public 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;
}
}
protected void close() {
try { db.close(); }
catch (NullPointerException ignored) { }
db = null;
}
protected void nuke() {
Log.i("T9DB.nuke", "Deleting database...");
synchronized (T9DB.class){
String[] oldSettings = getSettings();
if (oldSettings == null) { Log.e("T9DB", "Couldn't get old settings"); }
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();
if (oldSettings != null) {
StringBuilder sb = new StringBuilder("INSERT OR REPLACE INTO ");
sb.append(SETTING_TABLE_NAME); sb.append(" ("); sb.append(COLUMN_ID); sb.append(",");
sb = DBSettings.SETTING.join(DBSettings.SETTING.settings, sb);
sb.append(") VALUES ("); sb.append(TextUtils.join(",", oldSettings)); sb.append(")");
db.execSQL(sb.toString());
}
}
Log.i("T9DB.nuke", "Done...");
}
public void showDBaccessError() {
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
}
public boolean storeSettingString(DBSettings.SETTING key, String value) {
ContentValues updatedata = new ContentValues();
updatedata.put(key.id, value);
return storeSetting(updatedata);
}
public boolean storeSettingInt(DBSettings.SETTING key, int value) {
ContentValues updatedata = new ContentValues();
updatedata.put(key.id, value);
return storeSetting(updatedata);
}
public boolean storeSetting(ContentValues updatedata) {
if (!checkReady()) {
Log.e("T9DB.storeSetting", "not ready");
return false;
}
db.update(SETTING_TABLE_NAME, updatedata, null, null);
return true;
}
// CHECK READY BEFORE CALLING THIS SO CAN SHOW USER MESSAGE IF NOT READY
public int getSettingInt(DBSettings.SETTING key) {
Cursor cur = db.rawQuery((new StringBuilder("SELECT ")).append(key.id)
.append(DBSettings.SETTINGQUERY).toString(), null);
if (cur.moveToFirst()) {
int value = cur.getInt(0);
cur.close();
return value;
}
return key.defvalue;
}
public String getSettingString(DBSettings.SETTING key) {
if (!checkReady()) {
return null;
}
Cursor cur = db.rawQuery((new StringBuilder("SELECT ")).append(key.id)
.append(DBSettings.SETTINGQUERY).toString(), null);
if (cur.moveToFirst()) {
String value = cur.getString(0);
cur.close();
return value;
}
return null;
}
public Object[] getSettings(DBSettings.SETTING[] keys) {
if (checkReady()) {
StringBuilder sb = new StringBuilder("SELECT ");
sb = DBSettings.SETTING.join(keys, sb);
Cursor cur = db.rawQuery(sb.append(DBSettings.SETTINGQUERY).toString(), null);
if (cur.moveToFirst()) {
Object[] values = new Object[keys.length];
for (int x=0;x<keys.length;x++){
if (keys[x] == DBSettings.SETTING.LAST_WORD)
values[x] = cur.getString(x);
else
values[x] = cur.getInt(x);
}
cur.close();
return values;
}
} else {
Log.e("T9DB.getSettings", "not ready");
Toast.makeText(mContext, R.string.database_settings_notready, Toast.LENGTH_SHORT).show();
}
Object[] values = new Object[keys.length];
for (int x=0;x<keys.length;x++) {
values[x] = keys[x].defvalue;
}
return values;
}
private String[] getSettings() {
if (!checkReady()) {
Log.e("T9DB.getSetting", "not ready");
return null;
}
int len = DBSettings.SETTING.settings.length+1;
String[] settings = new String[len];
StringBuilder sb = new StringBuilder("SELECT "); sb.append(COLUMN_ID); sb.append(",");
sb = DBSettings.SETTING.join(DBSettings.SETTING.settings, sb);
sb.append(" FROM "); sb.append(SETTING_TABLE_NAME); sb.append(" WHERE "); sb.append(COLUMN_ID);
sb.append("=1");
Cursor cur = null;
cur = db.rawQuery(sb.toString(),null);
try { cur = db.rawQuery(sb.toString(),null); }
catch (SQLiteException e) {
if (cur != null) { cur.close(); }
return null;
}
if (cur.moveToFirst()) {
for (int x = 0; x < len; x++)
settings[x] = cur.getString(x);
} else {
Log.w("T9DB.getSettings", "COULDN'T RETRIEVE SETTINGS?");
for (int x = 1; x < len; x++) {
settings[0] = "1"; // COLUMN_ID
if (DBSettings.SETTING.settings[x].defvalue == null)
settings[x] = null;
else
settings[x] = DBSettings.SETTING.settings[x].defvalue.toString();
}
}
cur.close();
return settings;
}
protected void addWord(String iword, LANGUAGE 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, lang);
} catch (NullPointerException e) {
throw new DBException(r.getString(R.string.add_word_badchar, lang.name(), iword));
}
// add int sequence into num table
ContentValues values = new ContentValues();
values.put(COLUMN_SEQ, seq);
values.put(COLUMN_LANG, lang.id);
// 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_exist2, iword, lang.name());
Log.w("T9DB.addWord", msg);
throw new DBException(msg);
}
}
protected 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(UPDATEQ + id);
// if id's freq is greater than FREQ_MAX, it gets normalized with trigger
}
protected void updateWords(String is, AbstractList<String> stringList, List<Integer> intList,
int capsMode, LANGUAGE lang) {
stringList.clear();
intList.clear();
// String[] sa = packInts(stringToInts(is), true);
int islen = is.length();
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.id), is });
int hits = 0;
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
stringList.add(cur.getString(1));
if (hits >= MAX_MAX_RESULTS) { break; } // to stop index error in candidate view
hits++;
}
cur.close();
if ((hits < MINHITS) && (islen >= 2)) {
char c = is.charAt(islen - 1);
c++;
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.id) });
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
stringList.add(cur.getString(1));
if (hits >= MAX_MAX_RESULTS) {
break;
}
hits++;
}
cur.close();
}
// Log.d("T9DB.updateWords", "pre: " + stringList);
if (capsMode == CAPS_OFF) {
return;
}
// Log.d("T9DB.updateWords", "filtering...");
// filter list
Iterator<String> iter = stringList.iterator();
String word;
String wordtemp;
int index = 0;
boolean removed = false;
while (iter.hasNext()) {
word = iter.next();
switch (capsMode) {
case CAPS_ALL:
wordtemp = word.toUpperCase(LangHelper.LOCALES[lang.index]);
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.index]) + word.substring(1);
} else {
wordtemp = word.toUpperCase(LangHelper.LOCALES[lang.index]);
}
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);
removed = false;
} else {
index++;
}
}
//Log.d("T9DB.updateWords", "i:" + is + " words:" + Arrays.toString(stringList.toArray()));
}
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();
return version < DATABASE_VERSION;
} else {
return false;
}
}
@Override
public void onCreate(SQLiteDatabase db) {
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 IF NOT EXISTS idx ON " + WORD_TABLE_NAME + "("
+ 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;");
createSettingsTable(db);
StringBuilder sb = new StringBuilder("INSERT OR IGNORE INTO "); sb.append(SETTING_TABLE_NAME);
sb.append(" ("); sb.append(COLUMN_ID); sb.append(", ");
sb = DBSettings.SETTING.join(DBSettings.SETTING.settings, sb);
sb.append(") VALUES (1,");
for (int x=0;x<DBSettings.SETTING.settings.length; x++) {
if (DBSettings.SETTING.settings[x].defvalue == null)
sb.append("NULL");
else
sb.append(DBSettings.SETTING.settings[x].defvalue);
if (x<DBSettings.SETTING.settings.length-1) sb.append(",");
}
sb.append(")");
db.execSQL(sb.toString());
}
private void createSettingsTable(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + SETTING_TABLE_NAME + " (" +
COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
DBSettings.SETTING.INPUT_MODE.id + " INTEGER, " +
DBSettings.SETTING.LANG_SUPPORT.id + " INTEGER, " +
DBSettings.SETTING.MODE_NOTIFY.id + " INTEGER, " + // no longer in use; delete in #7
DBSettings.SETTING.LAST_LANG.id + " INTEGER, " +
DBSettings.SETTING.KEY_REMAP.id + " INTEGER, " + // no longer in use; delete in #7
DBSettings.SETTING.SPACE_ZERO.id + " INTEGER, " + // no longer in use; delete in #7
DBSettings.SETTING.LAST_WORD.id + " TEXT )");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("T9DB.onUpgrade", "Upgrading database from version " + oldVersion + " to " + newVersion);
if (oldVersion <= 1) {
// ADDED LANG
db.execSQL("DROP INDEX IF EXISTS idx");
db.execSQL("ALTER TABLE " + WORD_TABLE_NAME + " ADD COLUMN " +
COLUMN_LANG + " INTEGER");
ContentValues updatedata = new ContentValues();
updatedata.put(COLUMN_LANG, 0);
db.update(WORD_TABLE_NAME, updatedata, null, null);
}
if (oldVersion <= 2) {
// ADDED SETTINGS, CHANGED LANG VALUE
db.execSQL("DROP INDEX IF EXISTS idx");
db.execSQL("UPDATE " + WORD_TABLE_NAME + " SET " + COLUMN_LANG + "=" + LANGUAGE.RU.id +
" WHERE " + COLUMN_LANG + "=1");
db.execSQL("UPDATE " + WORD_TABLE_NAME + " SET " + COLUMN_LANG + "=" + LANGUAGE.EN.id +
" WHERE " + COLUMN_LANG + "=0");
createSettingsTable(db);
}
if (oldVersion == 3) {
// ADDED REMAP OPTION and SPACEONZERO
db.execSQL("ALTER TABLE " + SETTING_TABLE_NAME + " ADD COLUMN " +
DBSettings.SETTING.KEY_REMAP.id + " INTEGER");
db.execSQL("ALTER TABLE " + SETTING_TABLE_NAME + " ADD COLUMN " +
DBSettings.SETTING.SPACE_ZERO.id + " INTEGER");
ContentValues updatedata = new ContentValues();
updatedata.put(DBSettings.SETTING.KEY_REMAP.id, 0);
updatedata.put(DBSettings.SETTING.SPACE_ZERO.id, 0);
db.update(SETTING_TABLE_NAME, updatedata, null, null);
}
onCreate(db);
Log.i("T9DB.onUpgrade", "Done.");
}
}
}

View file

@ -18,16 +18,15 @@ import android.view.inputmethod.InputConnection;
import android.widget.Toast;
import io.github.sspanak.tt9.LangHelper.LANGUAGE;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
import io.github.sspanak.tt9.Utils.SpecialInputType;
import io.github.sspanak.tt9.db.T9DB;
import io.github.sspanak.tt9.preferences.T9Preferences;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.List;
public class TraditionalT9 extends InputMethodService implements
KeyboardView.OnKeyboardActionListener {
public class TraditionalT9 extends InputMethodService implements KeyboardView.OnKeyboardActionListener {
private CandidateView mCandidateView;
private InterfaceHandler interfacehandler = null;
@ -67,10 +66,7 @@ public class TraditionalT9 extends InputMethodService implements
private LANGUAGE[] mLangsAvailable = null;
private static final int CAPS_OFF = 0;
private static final int CAPS_SINGLE = 1;
private static final int CAPS_ALL = 2;
private final static int[] CAPS_CYCLE = { CAPS_OFF, CAPS_SINGLE, CAPS_ALL };
private final static int[] CAPS_CYCLE = { T9Preferences.CASE_LOWER, T9Preferences.CASE_CAPITALIZE, T9Preferences.CASE_UPPER };
private final static int T9DELAY = 900;
final Handler t9releasehandler = new Handler();
@ -82,11 +78,9 @@ public class TraditionalT9 extends InputMethodService implements
};
private T9DB db;
private T9Preferences prefs;
public static final int MODE_LANG = 0;
public static final int MODE_TEXT = 1;
public static final int MODE_NUM = 2;
private static final int[] MODE_CYCLE = { MODE_LANG, MODE_TEXT, MODE_NUM };
private static final int[] MODE_CYCLE = { T9Preferences.MODE_PREDICTIVE, T9Preferences.MODE_ABC, T9Preferences.MODE_123 };
private int mKeyMode;
private InputConnection currentInputConnection = null;
@ -101,6 +95,7 @@ public class TraditionalT9 extends InputMethodService implements
mPrevious = -1;
mCharIndex = 0;
db = T9DB.getInstance(this);
prefs = new T9Preferences(this);
if (interfacehandler == null) {
interfacehandler = new InterfaceHandler(getLayoutInflater().inflate(R.layout.mainview,
@ -133,7 +128,7 @@ public class TraditionalT9 extends InputMethodService implements
//updateKeyMode();
View v = getLayoutInflater().inflate(R.layout.mainview, null);
interfacehandler.changeView(v);
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
interfacehandler.showHold(true);
} else {
interfacehandler.showHold(false);
@ -199,7 +194,7 @@ public class TraditionalT9 extends InputMethodService implements
}
protected void showAddWord() {
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
// decide if we are going to look for work to base on
String template = mComposing.toString();
if (template.length() == 0) {
@ -245,6 +240,7 @@ public class TraditionalT9 extends InputMethodService implements
@Override
public void onStartInput(EditorInfo inputField, boolean restarting) {
super.onStartInput(inputField, restarting);
currentInputConnection = getCurrentInputConnection();
//Log.d("T9.onStartInput", "INPUTTYPE: " + inputField.inputType + " FIELDID: " + inputField.fieldId +
// " FIELDNAME: " + inputField.fieldName + " PACKAGE NAME: " + inputField.packageName);
@ -272,24 +268,14 @@ public class TraditionalT9 extends InputMethodService implements
// way.
clearState();
// get settings
Object[] settings = db.getSettings(new SETTING[] {
// 0, 1, 2,
// "2" is no longer in use; delete in #7
SETTING.LANG_SUPPORT, SETTING.LAST_LANG, SETTING.MODE_NOTIFY,
// 3, 4, 5
// "5" is no longer in use; delete in #7
SETTING.INPUT_MODE, SETTING.LAST_WORD, SETTING.SPACE_ZERO
});
mLangsAvailable = LangHelper.buildLangs((Integer)settings[0]);
mLang = sanitizeLang(LANGUAGE.get((Integer)settings[1]));
mLangsAvailable = LangHelper.buildLangs(prefs.getEnabledLanguages());
mLang = sanitizeLang(LANGUAGE.get(prefs.getInputLanguage()));
updateCandidates();
//TODO: Check if "restarting" variable will make things faster/more effecient
mKeyMode = MODE_TEXT;
mKeyMode = T9Preferences.MODE_ABC;
// We are now going to initialize our state based on the type of
// text being edited.
@ -298,13 +284,13 @@ public class TraditionalT9 extends InputMethodService implements
case InputType.TYPE_CLASS_DATETIME:
// Numbers and dates default to the symbols keyboard, with
// no extra features.
mKeyMode = MODE_NUM;
mKeyMode = T9Preferences.MODE_123;
break;
case InputType.TYPE_CLASS_PHONE:
// Phones will also default to the symbols keyboard, though
// often you will want to have a dedicated phone keyboard.
mKeyMode = MODE_NUM;
mKeyMode = T9Preferences.MODE_123;
break;
case InputType.TYPE_CLASS_TEXT:
@ -312,7 +298,7 @@ public class TraditionalT9 extends InputMethodService implements
// normal alphabetic keyboard, and assume that we should
// be doing predictive text (showing candidates as the
// user types).
mKeyMode = (Integer)settings[3];
mKeyMode = prefs.getInputMode();
// We now look for a few special variations of text that will
// modify our behavior.
@ -321,7 +307,7 @@ public class TraditionalT9 extends InputMethodService implements
|| variation == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) {
// Do not display predictions / what the user is typing
// when they are entering a password.
mKeyMode = MODE_TEXT;
mKeyMode = T9Preferences.MODE_ABC;
}
if (variation == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
@ -329,7 +315,7 @@ public class TraditionalT9 extends InputMethodService implements
|| variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
// Our predictions are not useful for e-mail addresses
// or URIs.
mKeyMode = MODE_TEXT;
mKeyMode = T9Preferences.MODE_ABC;
}
if ((inputField.inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) != 0) {
@ -339,7 +325,7 @@ public class TraditionalT9 extends InputMethodService implements
// candidates when in fullscreen mode, otherwise relying
// own it displaying its own UI.
// ????
mKeyMode = (Integer)settings[3];
mKeyMode = prefs.getInputMode();
}
// handle filter list cases... do not hijack DPAD center and make
@ -361,22 +347,23 @@ public class TraditionalT9 extends InputMethodService implements
updateShiftKeyState(inputField);
}
if (inputField.inputType == SpecialInputType.TYPE_SHARP_007H_PHONE_BOOK) {
mKeyMode = MODE_TEXT;
mKeyMode = T9Preferences.MODE_ABC;
}
String prevword = null;
if (inputField.privateImeOptions != null
&& inputField.privateImeOptions.equals("io.github.sspanak.tt9.addword=true")) {
if (
inputField.privateImeOptions != null
&& inputField.privateImeOptions.equals("io.github.sspanak.tt9.addword=true")
) {
mAddingWord = true;
// mAddingSkipInput = true;
// Log.d("onStartInput", "ADDING WORD");
mKeyMode = MODE_TEXT;
mKeyMode = T9Preferences.MODE_ABC;
} else {
mAddingWord = false;
// Log.d("onStartInput", "not adding word");
prevword = (String)settings[4];
if (prevword != null) {
String prevword = prefs.getLastWord();
if (prevword != "") {
onText(prevword);
db.storeSettingString(SETTING.LAST_WORD, null);
prefs.setLastWord("");
}
}
@ -402,7 +389,7 @@ public class TraditionalT9 extends InputMethodService implements
super.onFinishInput();
// Log.d("onFinishInput", "When is this called?");
if (mEditing == EDITING || mEditing == EDITING_NOSHOW) {
db.storeSettingInt(SETTING.LAST_LANG, mLang.id);
prefs.setInputLanguage(mLang.id);
commitTyped();
finish();
}
@ -452,7 +439,7 @@ public class TraditionalT9 extends InputMethodService implements
int candidatesStart, int candidatesEnd) {
super.onUpdateSelection(oldSelStart, oldSelEnd, newSelStart, newSelEnd, candidatesStart,
candidatesEnd);
if (mKeyMode == MODE_TEXT) { return; } // stops the ghost fast-type commit
if (mKeyMode == T9Preferences.MODE_ABC) { return; } // stops the ghost fast-type commit
// If the current selection in the text view changes, we should
// clear whatever candidate text we have.
if ((mComposing.length() > 0 || mComposingI.length() > 0)
@ -477,17 +464,13 @@ public class TraditionalT9 extends InputMethodService implements
// ??????????????
}
private KeyEvent TranslateKey(int keyCode, KeyEvent event) {
KeyEvent key = event;
if (KeyMap.keyMapping.containsKey(keyCode)) {
key = new KeyEvent(event.getDownTime(), event.getEventTime(), event.getAction(),
KeyMap.keyMapping.get(keyCode), event.getRepeatCount(), event.getMetaState(),
event.getDeviceId(), 0, event.getFlags());
}
return key;
}
private boolean onKeyDown_(int keyCode, KeyEvent event) {
/**
* Use this to monitor key events being delivered to the application. We get
* first crack at them, and can either resume them or let them continue to
* the app.
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Log.d("onKeyDown", "Key: " + event + " repeat?: " +
// event.getRepeatCount() + " long-time: " + event.isLongPress());
if (mEditing == NON_EDIT) {
@ -516,7 +499,7 @@ public class TraditionalT9 extends InputMethodService implements
return super.onKeyDown(keyCode, event);
}
} else if (keyCode == KeyEvent.KEYCODE_DEL) {// Special handling of the delete key: if we currently are
} else if (keyCode == prefs.getKeyBackspace()) {// Special handling of the delete key: if we currently are
// composing text for the user, we want to modify that instead
// of let the application do the delete itself.
// if (mComposing.length() > 0) {
@ -530,7 +513,7 @@ public class TraditionalT9 extends InputMethodService implements
if (event.getRepeatCount() != 0) {
return true;
}
if (mKeyMode == MODE_TEXT) {
if (mKeyMode == T9Preferences.MODE_ABC) {
t9releasehandler.removeCallbacks(mt9release);
}
if (keyCode == KeyEvent.KEYCODE_BACK) {
@ -564,20 +547,6 @@ public class TraditionalT9 extends InputMethodService implements
commitReset();
return super.onKeyDown(keyCode, event);
}
/**
* Use this to monitor key events being delivered to the application. We get
* first crack at them, and can either resume them or let them continue to
* the app.
*/
@Override
public boolean onKeyDown(int inputKeyCode, KeyEvent inputEvent) {
KeyEvent event = TranslateKey(inputKeyCode, inputEvent);
if (event != null) {
return onKeyDown_(event.getKeyCode(), event);
}
return onKeyDown_(inputKeyCode, inputEvent);
}
protected void launchOptions() {
Intent awintent = new Intent(this, TraditionalT9Settings.class);
@ -607,7 +576,7 @@ public class TraditionalT9 extends InputMethodService implements
}
return true;
} else if (keyCode == KeyEvent.KEYCODE_STAR) {
if (mKeyMode != MODE_NUM) {
if (mKeyMode != T9Preferences.MODE_123) {
if (mLangsAvailable.length > 1) {
nextLang();
} else {
@ -620,7 +589,7 @@ public class TraditionalT9 extends InputMethodService implements
if (interfacehandler != null) {
interfacehandler.setPressed(keyCode, false);
}
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
if (mWordFound) {
showAddWord();
} else {
@ -637,13 +606,13 @@ public class TraditionalT9 extends InputMethodService implements
return true;
}
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
commitTyped();
onText(String.valueOf(keyCode - KeyEvent.KEYCODE_0));
} else if (mKeyMode == MODE_TEXT) {
} else if (mKeyMode == T9Preferences.MODE_ABC) {
commitReset();
onText(String.valueOf(keyCode - KeyEvent.KEYCODE_0));
} else if (mKeyMode == MODE_NUM) {
} else if (mKeyMode == T9Preferences.MODE_123) {
if (keyCode == KeyEvent.KEYCODE_0) {
onText("+");
}
@ -651,8 +620,13 @@ public class TraditionalT9 extends InputMethodService implements
}
return true;
}
private boolean onKeyUp_(int keyCode, KeyEvent event) {
/**
* Use this to monitor key events being delivered to the application. We get
* first crack at them, and can either resume them or let them continue to
* the app.
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// Log.d("onKeyUp", "Key: " + keyCode + " repeat?: " +
// event.getRepeatCount());
if (mEditing == NON_EDIT) {
@ -700,7 +674,7 @@ public class TraditionalT9 extends InputMethodService implements
}
return false;
} else if (keyCode == KeyEvent.KEYCODE_DEL) {
} else if (keyCode == prefs.getKeyBackspace()) {
return true;
} else if (keyCode == KeyEvent.KEYCODE_ENTER) {
return false;
@ -743,20 +717,6 @@ public class TraditionalT9 extends InputMethodService implements
commitReset();
return super.onKeyUp(keyCode, event);
}
/**
* Use this to monitor key events being delivered to the application. We get
* first crack at them, and can either resume them or let them continue to
* the app.
*/
@Override
public boolean onKeyUp(int inputKeyCode, KeyEvent inputEvent) {
KeyEvent event = TranslateKey(inputKeyCode, inputEvent);
if (event != null) {
return onKeyUp_(event.getKeyCode(), event);
}
return onKeyUp_(inputKeyCode, inputEvent);
}
/**
* Helper function to commit any text being composed in to the editor.
@ -780,7 +740,7 @@ public class TraditionalT9 extends InputMethodService implements
*/
private void updateShiftKeyState(EditorInfo attr) {
// Log.d("updateShift", "CM start: " + mCapsMode);
if (attr != null && mCapsMode != CAPS_ALL) {
if (attr != null && mCapsMode != T9Preferences.CASE_UPPER) {
int caps = 0;
if (attr.inputType != InputType.TYPE_NULL) {
caps = currentInputConnection.getCursorCapsMode(attr.inputType);
@ -788,13 +748,13 @@ public class TraditionalT9 extends InputMethodService implements
// mInputView.setShifted(mCapsLock || caps != 0);
// Log.d("updateShift", "caps: " + caps);
if ((caps & TextUtils.CAP_MODE_CHARACTERS) == TextUtils.CAP_MODE_CHARACTERS) {
mCapsMode = CAPS_ALL;
mCapsMode = T9Preferences.CASE_UPPER;
} else if ((caps & TextUtils.CAP_MODE_SENTENCES) == TextUtils.CAP_MODE_SENTENCES) {
mCapsMode = CAPS_SINGLE;
mCapsMode = T9Preferences.CASE_CAPITALIZE;
} else if ((caps & TextUtils.CAP_MODE_WORDS) == TextUtils.CAP_MODE_WORDS) {
mCapsMode = CAPS_SINGLE;
mCapsMode = T9Preferences.CASE_CAPITALIZE;
} else {
mCapsMode = CAPS_OFF;
mCapsMode = T9Preferences.CASE_LOWER;
}
updateKeyMode();
}
@ -820,11 +780,11 @@ public class TraditionalT9 extends InputMethodService implements
// Log.d("OnKey", "pri: " + keyCode);
// Log.d("onKey", "START Cm: " + mCapsMode);
// HANDLE SPECIAL KEYS
if (keyCode == KeyEvent.KEYCODE_DEL) {
if (keyCode == prefs.getKeyBackspace()) {
handleBackspace();
} else if (keyCode == KeyEvent.KEYCODE_STAR) {
// change case
if (mKeyMode == MODE_NUM) {
if (mKeyMode == T9Preferences.MODE_123) {
handleCharacter(KeyEvent.KEYCODE_STAR);
} else {
handleShift();
@ -878,14 +838,14 @@ public class TraditionalT9 extends InputMethodService implements
}
if (mComposing.length() > 0) {
switch (mKeyMode) {
case MODE_LANG:
case T9Preferences.MODE_PREDICTIVE:
commitTyped();
break;
case MODE_TEXT:
case T9Preferences.MODE_ABC:
commitTyped();
charReset();
break;
case MODE_NUM:
case T9Preferences.MODE_123:
// shouldn't happen
break;
}
@ -902,7 +862,7 @@ public class TraditionalT9 extends InputMethodService implements
updateCandidates(false);
}
private void updateCandidates(boolean backspace) {
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
int len = mComposingI.length();
if (len > 0) {
if (mComposingI.charAt(len - 1) == '1') {
@ -964,7 +924,7 @@ public class TraditionalT9 extends InputMethodService implements
interfacehandler.showNotFound(false);
}
}
} else if (mKeyMode == MODE_TEXT) {
} else if (mKeyMode == T9Preferences.MODE_ABC) {
if (mComposing.length() > 0) {
//Log.d("updateCandidates", "Previous: " + mComposing.toString());
mSuggestionStrings.clear();
@ -993,7 +953,7 @@ public class TraditionalT9 extends InputMethodService implements
private void handleBackspace() {
final int length = mComposing.length();
final int length2 = mComposingI.length();
if (mKeyMode == MODE_TEXT) {
if (mKeyMode == T9Preferences.MODE_ABC) {
charReset();
setCandidatesViewShown(false);
}
@ -1028,7 +988,7 @@ public class TraditionalT9 extends InputMethodService implements
updateCandidates();
} else {
mPreviousWord = "";
keyDownUp(KeyEvent.KEYCODE_DEL);
keyDownUp(prefs.getKeyBackspace());
}
updateShiftKeyState(getCurrentInputEditorInfo());
// Log.d("handleBS", "Cm: " + mCapsMode);
@ -1044,7 +1004,7 @@ public class TraditionalT9 extends InputMethodService implements
mCapsMode++;
}
if (mKeyMode == MODE_LANG && mComposing.length() > 0) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE && mComposing.length() > 0) {
updateCandidates();
currentInputConnection.setComposingText(mComposing, 1);
}
@ -1058,7 +1018,7 @@ public class TraditionalT9 extends InputMethodService implements
*/
private void handleCharacter(int keyCode) {
switch (mKeyMode) {
case MODE_LANG:
case T9Preferences.MODE_PREDICTIVE:
// it begins
if (keyCode == KeyEvent.KEYCODE_POUND || keyCode == KeyEvent.KEYCODE_0) {
if (mComposing.length() > 0) {
@ -1074,7 +1034,7 @@ public class TraditionalT9 extends InputMethodService implements
}
break;
case MODE_TEXT:
case T9Preferences.MODE_ABC:
t9releasehandler.removeCallbacks(mt9release);
if (keyCode == KeyEvent.KEYCODE_POUND) {
keyCode = 10;
@ -1102,7 +1062,7 @@ public class TraditionalT9 extends InputMethodService implements
// start at caps if CapMode
// Log.d("handleChar", "Cm: " + mCapsMode);
if (mCharIndex == 0 && mCapsMode != CAPS_OFF) {
if (mCharIndex == 0 && mCapsMode != T9Preferences.CASE_LOWER) {
mCharIndex = CharMap.T9CAPSTART[mLang.index][keyCode];
}
@ -1120,15 +1080,15 @@ public class TraditionalT9 extends InputMethodService implements
t9releasehandler.postDelayed(mt9release, T9DELAY);
if (newChar) {
// consume single caps
if (mCapsMode == CAPS_SINGLE) {
mCapsMode = CAPS_OFF;
if (mCapsMode == T9Preferences.CASE_CAPITALIZE) {
mCapsMode = T9Preferences.CASE_LOWER;
}
}
updateCandidates();
updateShiftKeyState(getCurrentInputEditorInfo());
break;
case MODE_NUM:
case T9Preferences.MODE_123:
if (keyCode == KeyEvent.KEYCODE_POUND) {
onText("#");
} else if (keyCode == KeyEvent.KEYCODE_STAR) {
@ -1173,7 +1133,7 @@ public class TraditionalT9 extends InputMethodService implements
mIgnoreDPADKeyUp = false;
return super.onKeyUp(keyCode, event);
} else {
if (mKeyMode != MODE_NUM && mComposing.length() > 0) {
if (mKeyMode != T9Preferences.MODE_123 && mComposing.length() > 0) {
if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
mCandidateView.scrollToSuggestion(1);
if (mSuggestionStrings.size() > mCandidateView.mSelectedIndex)
@ -1185,9 +1145,9 @@ public class TraditionalT9 extends InputMethodService implements
currentInputConnection.setComposingText(mSuggestionStrings.get(mCandidateView.mSelectedIndex), 1);
return true;
} else if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT || keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
commitTyped();
} else if (mKeyMode == MODE_TEXT) {
} else if (mKeyMode == T9Preferences.MODE_ABC) {
commitReset();
}
// getCurrentInputConnection().sendKeyEvent(mDPADkeyEvent);
@ -1219,8 +1179,8 @@ public class TraditionalT9 extends InputMethodService implements
private void commitReset() {
commitTyped();
charReset();
if (mCapsMode == CAPS_SINGLE) {
mCapsMode = CAPS_OFF;
if (mCapsMode == T9Preferences.CASE_CAPITALIZE) {
mCapsMode = T9Preferences.CASE_LOWER;
}
// Log.d("commitReset", "CM pre: " + mCapsMode);
updateShiftKeyState(getCurrentInputEditorInfo());
@ -1260,7 +1220,7 @@ public class TraditionalT9 extends InputMethodService implements
private void resetKeyMode() {
charReset();
if (mKeyMode != MODE_NUM) {
if (mKeyMode != T9Preferences.MODE_123) {
commitTyped();
}
mComposing.setLength(0);
@ -1276,12 +1236,12 @@ public class TraditionalT9 extends InputMethodService implements
int icon = 0;
switch (mKeyMode) {
case MODE_TEXT:
case T9Preferences.MODE_ABC:
interfacehandler.showHold(false);
icon = LangHelper.ICONMAP[mLang.index][mKeyMode][mCapsMode];
break;
case MODE_LANG:
if (!db.ready) {
case T9Preferences.MODE_PREDICTIVE:
if (!db.isReady()) {
if (!mGaveUpdateWarn) {
Toast.makeText(this, getText(R.string.updating_database_unavailable), Toast.LENGTH_LONG).show();
mGaveUpdateWarn = true;
@ -1302,7 +1262,7 @@ public class TraditionalT9 extends InputMethodService implements
// + mCapsMode);
icon = LangHelper.ICONMAP[mLang.index][mKeyMode][mCapsMode];
break;
case MODE_NUM:
case T9Preferences.MODE_123:
interfacehandler.showHold(false);
icon = R.drawable.ime_number;
break;
@ -1329,14 +1289,14 @@ public class TraditionalT9 extends InputMethodService implements
// mSuggestionStrings.get(mCandidateView.mSelectedIndex));
// get and commit selected suggestion
ic.commitText(mSuggestionStrings.get(mCandidateView.mSelectedIndex), 1);
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
// update freq
db.incrementWord(mSuggestionInts.get(mCandidateView.mSelectedIndex));
}
} else {
// commit suggestion index
ic.commitText(mSuggestionStrings.get(index), 1);
if (mKeyMode == MODE_LANG) {
if (mKeyMode == T9Preferences.MODE_PREDICTIVE) {
db.incrementWord(mSuggestionInts.get(index));
}
}

View file

@ -7,15 +7,12 @@ import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.database.Cursor;
import android.database.DatabaseUtils.InsertHelper;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Log;
@ -27,39 +24,32 @@ import android.widget.Toast;
import com.stackoverflow.answer.UnicodeBOMInputStream;
import io.github.sspanak.tt9.LangHelper.LANGUAGE;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
import io.github.sspanak.tt9.db.T9DB;
import io.github.sspanak.tt9.preferences.T9Preferences;
import io.github.sspanak.tt9.settings.CustomInflater;
import io.github.sspanak.tt9.settings.Setting;
import io.github.sspanak.tt9.settings.SettingAdapter;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Properties;
public class TraditionalT9Settings extends ListActivity implements
DialogInterface.OnCancelListener {
public class TraditionalT9Settings extends ListActivity implements DialogInterface.OnCancelListener {
AsyncTask<String, Integer, Reply> task = null;
final static String dictname = "%s-utf8.txt";
final static String userdictname = "user.%s.dict";
final static String backupname = "t9backup.txt";
final static String sddir = "tt9";
final int BACKUP_Q_LIMIT = 1000;
@ -136,13 +126,11 @@ public class TraditionalT9Settings extends ListActivity implements
long size;
long pos;
boolean internal;
boolean restore;
String[] dicts;
LANGUAGE[] mSupportedLanguages;
LoadDictTask(int msgid, boolean intern, boolean restorebackup, LANGUAGE[] supportedLanguages) {
LoadDictTask(int msgid, boolean intern, LANGUAGE[] supportedLanguages) {
internal = intern;
restore = restorebackup;
int suplanglen = supportedLanguages.length;
dicts = new String[suplanglen];
@ -160,7 +148,7 @@ public class TraditionalT9Settings extends ListActivity implements
pd.setOnCancelListener(TraditionalT9Settings.this);
}
private long getDictSizes(boolean internal, boolean restore, String[] dicts) {
private long getDictSizes(boolean internal, String[] dicts) {
if (internal) {
InputStream input;
Properties props = new Properties();
@ -183,32 +171,22 @@ public class TraditionalT9Settings extends ListActivity implements
}
} else {
File backupfile = new File(Environment.getExternalStorageDirectory(), sddir);
if (restore) {
// using external backup
backupfile = new File(backupfile, backupname);
if (backupfile.exists() && backupfile.isFile()) {
return backupfile.length();
long total = 0;
File f;
for (String dict : dicts) {
f = new File(backupfile, dict);
if (f.exists() && f.isFile()) {
total = total + f.length();
} else {
return -1;
total = total + 0;
}
} else {
long total = 0;
File f;
for (String dict : dicts) {
f = new File(backupfile, dict);
if (f.exists() && f.isFile()) {
total = total + f.length();
} else {
total = total + 0;
}
}
return total;
}
return total;
}
}
@Override protected void onPreExecute() {
size = getDictSizes(internal, restore, dicts);
size = getDictSizes(internal, dicts);
pos = 0;
if ( size >= 0 ) {
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
@ -247,64 +225,45 @@ public class TraditionalT9Settings extends ListActivity implements
InputStream dictstream = null;
try {
if (restore) {
try {
dictstream = new FileInputStream(new File(
new File(Environment.getExternalStorageDirectory(), sddir), backupname));
reply = processFile(dictstream, reply, db, LANGUAGE.NONE, backupname);
} catch (FileNotFoundException e) {
reply.status = false;
reply.forceMsg("Backup file not found: " + e.getMessage());
closeStream(dictstream, reply); // this is silly but it
return reply; // stops IDE nagging at me.
} catch (IOException e) {
reply.status = false;
reply.forceMsg("IO Error: " + e.getMessage());
closeStream(dictstream, reply); // this is silly but it
return reply; // stops IDE nagging at me.
for (int x=0; x<dicts.length; x++) {
if (internal) {
try {
dictstream = getAssets().open(dicts[x]);
reply = processFile(dictstream, reply, db, mSupportedLanguages[x], dicts[x]);
} catch (IOException e) {
e.printStackTrace();
reply.status = false;
reply.forceMsg("IO Error: " + e.getMessage());
}
} else {
try {
dictstream = new FileInputStream(new File(
new File(Environment.getExternalStorageDirectory(), sddir), dicts[x]));
reply = processFile(dictstream, reply, db, mSupportedLanguages[x], dicts[x]);
} catch (FileNotFoundException e) {
reply.status = false;
reply.forceMsg("File not found: " + e.getMessage());
final String msg = mContext.getString(R.string.pref_loaduser_notfound, dicts[x]);
//Log.d("T9Setting.load", "Built string. Calling Toast.");
((Activity) mContext).runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext,
msg,
Toast.LENGTH_SHORT).show();
}
});
closeStream(dictstream, reply); // this is silly but it
// stops IDE nagging at me.
} catch (IOException e) {
reply.status = false;
reply.forceMsg("IO Error: " + e.getMessage());
closeStream(dictstream, reply); // this is silly but it
return reply; // stops IDE nagging at me.
}
}
closeStream(dictstream, reply);
} else {
for (int x=0; x<dicts.length; x++) {
if (internal) {
try {
dictstream = getAssets().open(dicts[x]);
reply = processFile(dictstream, reply, db, mSupportedLanguages[x], dicts[x]);
} catch (IOException e) {
e.printStackTrace();
reply.status = false;
reply.forceMsg("IO Error: " + e.getMessage());
}
} else {
try {
dictstream = new FileInputStream(new File(
new File(Environment.getExternalStorageDirectory(), sddir), dicts[x]));
reply = processFile(dictstream, reply, db, mSupportedLanguages[x], dicts[x]);
} catch (FileNotFoundException e) {
reply.status = false;
reply.forceMsg("File not found: " + e.getMessage());
final String msg = mContext.getString(R.string.pref_loaduser_notfound, dicts[x]);
//Log.d("T9Setting.load", "Built string. Calling Toast.");
((Activity) mContext).runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(mContext,
msg,
Toast.LENGTH_SHORT).show();
}
});
closeStream(dictstream, reply); // this is silly but it
// stops IDE nagging at me.
} catch (IOException e) {
reply.status = false;
reply.forceMsg("IO Error: " + e.getMessage());
closeStream(dictstream, reply); // this is silly but it
return reply; // stops IDE nagging at me.
}
}
closeStream(dictstream, reply);
}
}
} catch (LoadException e) {
// too many errors, bail
@ -489,190 +448,7 @@ public class TraditionalT9Settings extends ListActivity implements
@Override
protected void onPostExecute(Reply result) {
if (restore) {
finishAndShowError(pd, result, R.string.pref_restore_title);
} else {
finishAndShowError(pd, result, R.string.pref_load_title);
}
}
}
private class DumpDictTask extends AsyncTask<String, Integer, Reply> {
ProgressDialog pd;
DumpDictTask(int msgid) {
pd = new ProgressDialog(TraditionalT9Settings.this);
pd.setMessage(getResources().getString(msgid));
pd.setOnCancelListener(TraditionalT9Settings.this);
}
@Override protected void onPreExecute() {
pd.show();
}
@Override
protected Reply doInBackground(String... ignore) {
Reply reply = new Reply();
SQLiteDatabase db;
db = T9DB.getSQLDB(mContext);
if (db == null) {
reply.forceMsg("Database unavailable at this time. (May be updating)");
reply.status = false;
return reply;
}
long entries;
int current = 0;
int pos = 0;
int last = 0;
File backupfile = new File(new File(Environment.getExternalStorageDirectory(),
sddir), backupname);
db.setLockingEnabled(false);
Log.d("doInBackground", "Dumping dict...");
BufferedWriter bw;
OutputStream dictstream = null;
try {
dictstream = new FileOutputStream(backupfile);
} catch (FileNotFoundException e) {
reply.status = false;
reply.forceMsg("Backup file error: " + e.getMessage());
return reply;
}
try {
bw = new BufferedWriter(new OutputStreamWriter(dictstream, "UTF-8"));
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
reply.status = false;
reply.forceMsg("Encoding Error (backupfile): " + e.getMessage());
closeStream(dictstream, reply);
return reply;
}
long startnow, endnow;
startnow = SystemClock.uptimeMillis();
String q = "SELECT count(*) FROM " + T9DB.WORD_TABLE_NAME;
Cursor cur = db.rawQuery(q, null);
cur.moveToFirst();
entries = cur.getInt(0);
// pd.setMax((int)entries);
cur.close();
try {
while (pos < entries) {
q = "SELECT " + T9DB.COLUMN_ID + ", " + T9DB.COLUMN_LANG + ", " +
T9DB.COLUMN_WORD + ", " + T9DB.COLUMN_FREQUENCY +
" FROM " + T9DB.WORD_TABLE_NAME +
" WHERE " + T9DB.COLUMN_ID + ">" + current +
" ORDER BY " + T9DB.COLUMN_ID + " LIMIT " + BACKUP_Q_LIMIT;
cur = db.rawQuery(q, null);
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
if (isCancelled()) {
reply.status = false;
reply.forceMsg("User cancelled.");
break;
}
current = cur.getInt(0);
pos++;
try {
bw.write(cur.getString(2)); // write word
bw.write(" ");
bw.write(Integer.toString(cur.getInt(3))); // then freq
bw.write(" ");
bw.write(Integer.toString(cur.getInt(1))); // then lang
bw.newLine();
} catch (Exception e) {
e.printStackTrace();
reply.status = false;
reply.forceMsg("Error: " + e.getMessage());
closeStream(dictstream, reply);
}
if ((pos - last) > 80) {
publishProgress((int) ((float) pos / entries * 10000));
last = pos;
}
}
cur.close();
}
} finally {
cur.close();
}
publishProgress(10000);
endnow = SystemClock.uptimeMillis();
Log.d("TIMING", "Execution time: " + (endnow - startnow) + " ms");
Log.d("doInBackground", "entries: " + entries + " last: " + pos);
try {
bw.flush();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
closeStream(dictstream, reply);
return reply;
}
@Override
protected void onProgressUpdate(Integer... progress) {
if (pd.isShowing()) {
pd.setProgress(progress[0]);
}
}
/**
* The system calls this to perform work in the UI thread and delivers
* the result from doInBackground()
*/
@Override
protected void onPostExecute(Reply result) {
finishAndShowError(pd, result, R.string.pref_backup_title);
}
}
private class NukeDictTask extends AsyncTask<String, Integer, Reply> {
ProgressDialog pd;
NukeDictTask(int msgid) {
pd = new ProgressDialog(TraditionalT9Settings.this);
pd.setMessage(getResources().getString(msgid));
pd.setCancelable(false);
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
}
@Override protected void onPreExecute() {
pd.show();
}
@Override
protected Reply doInBackground(String... ignore) {
Reply reply = new Reply();
Log.d("doInBackground", "Nuking dict...");
long startnow, endnow;
startnow = SystemClock.uptimeMillis();
T9DB t9db = T9DB.getInstance(mContext);
t9db.nuke();
endnow = SystemClock.uptimeMillis();
Log.d("TIMING", "Execution time: " + (endnow - startnow) + " ms");
return reply;
}
@Override
protected void onCancelled() {
// Pointless callback. Thanks android.
}
/**
* The system calls this to perform work in the UI thread and delivers
* the result from doInBackground()
*/
@Override
protected void onPostExecute(Reply result) {
finishAndShowError(pd, result, R.string.pref_nuke_title);
finishAndShowError(pd, result, R.string.pref_load_title);
}
}
@ -684,10 +460,14 @@ public class TraditionalT9Settings extends ListActivity implements
// http://stackoverflow.com/questions/7645880/listview-with-onitemclicklistener-android
// get settings
Object[] settings = T9DB.getInstance(this).getSettings(new SETTING[]
// Order should be based on SETTING.sqOrder
// "MODE_NOTIFY", "SPACE_ZERO" and "KEY_REMAP" are no longer in use; delete in #7
{SETTING.INPUT_MODE, SETTING.LANG_SUPPORT, SETTING.MODE_NOTIFY, SETTING.KEY_REMAP, SETTING.SPACE_ZERO});
T9Preferences prefs = new T9Preferences(this);
Object[] settings = {
prefs.getInputMode(),
prefs.getEnabledLanguages(),
null, // MODE_NOTIFY; not used, remove in #29
false, // KEY_REMAP; not used, remove in #29
true, // SPACE_ZERO; not used, remove in #29
};
ListAdapter settingitems;
try {
settingitems = new SettingAdapter(this, CustomInflater.inflate(this, R.xml.prefs, settings));
@ -707,21 +487,9 @@ public class TraditionalT9Settings extends ListActivity implements
if (s.id.equals("help"))
openHelp();
else if (s.id.equals("loaddict"))
preloader(R.string.pref_loadingdict, true, false);
preloader(R.string.pref_loadingdict, true);
else if (s.id.equals("loaduserdict"))
preloader(R.string.pref_loadinguserdict, false, false);
else if (s.id.equals("nukedict"))
nukeDict();
else if (s.id.equals("backupdict"))
backupDict();
else if (s.id.equals("restoredict"))
restoreDict();
else if (s.id.equals("reloadKeys")) {
int msg = KeyMap.setKeys();
if (msg != 0) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
preloader(R.string.pref_loadinguserdict, false);
else
s.clicked(mContext);
}
@ -732,81 +500,17 @@ public class TraditionalT9Settings extends ListActivity implements
startActivity(i);
}
// LoadDictTask(int msgid, boolean intern, boolean restorebackup, CheckBoxPreference setting)
private void preloader(int msgid, boolean internal, boolean restorebackup) {
private void preloader(int msgid, boolean internal) {
task = new LoadDictTask(msgid, internal, restorebackup,
LangHelper.buildLangs(T9DB.getInstance(mContext).getSettingInt(SETTING.LANG_SUPPORT)));
task = new LoadDictTask(
msgid,
internal,
LangHelper.buildLangs(T9Preferences.getInstance(mContext).getEnabledLanguages())
);
task.execute();
}
private void predumper(int msgid) {
task = new DumpDictTask(msgid);
task.execute();
}
private void nukeDict() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(R.string.pref_nuke_warn).setTitle(R.string.pref_nuke_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
task = new NukeDictTask(R.string.pref_nukingdict);
task.execute();
// restart settings to get fresh settings.
TraditionalT9Settings.this.finish();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
startActivity(new Intent(TraditionalT9Settings.this, TraditionalT9Settings.class));
}}, 1000);
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void backupDict() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
File saveloc = new File(Environment.getExternalStorageDirectory(), sddir);
saveloc.mkdirs();
if (!saveloc.canWrite()) {
Log.e("backupDict", "can't write : " + saveloc.getAbsolutePath());
showErrorDialogID(builder, R.string.pref_backup_title, R.string.pref_backup_noext);
return;
}
saveloc = new File(saveloc, backupname);
if (saveloc.exists()) {
builder.setMessage(R.string.pref_backup_warn).setTitle(R.string.pref_backup_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
predumper(R.string.pref_savingbackup);
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
predumper(R.string.pref_savingbackup);
}
} else {
showErrorDialogID(builder, R.string.pref_backup_title, R.string.pref_backup_noext);
}
}
private void showErrorDialog(CharSequence title, CharSequence msg) {
showErrorDialog(new AlertDialog.Builder(this), title, msg);
@ -836,125 +540,6 @@ public class TraditionalT9Settings extends ListActivity implements
dialog.show();
}
private void restoreDict() {
// Environment.MEDIA_MOUNTED_READ_ONLY;
// Environment.MEDIA_MOUNTED;
AlertDialog.Builder builder = new AlertDialog.Builder(this);
if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(Environment.getExternalStorageState())
|| Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())) {
if ((new File(new File(Environment.getExternalStorageDirectory(), sddir),
backupname)).exists()) {
Resources res = getResources();
builder
.setMessage(
res.getString(R.string.pref_restore_warn,
res.getString(R.string.pref_nukedict)))
.setTitle(R.string.pref_restore_title)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
preloader(R.string.pref_loadingbackup, false, true);
}
}).setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
} else {
showErrorDialogID(builder, R.string.pref_restore_title,
R.string.pref_restore_nofile);
}
} else {
showErrorDialogID(builder, R.string.pref_restore_title, R.string.pref_restore_noext);
}
}
@SuppressWarnings("unused")
private void queryTestDebug() {
long startnow, endnow;
AbstractList<String> words = new ArrayList<String>();
List<Integer> ids = new ArrayList<Integer>();
startnow = SystemClock.uptimeMillis();
T9DB tdb = T9DB.getInstance(this);
Log.d("queryTestDebug", "Testing...");
tdb.updateWords("123", words, ids, 0, LangHelper.LANGUAGE.EN);
Log.d("queryTestDebug", "123->" + words.toString());
Log.d("queryTestDebug", "269->");
tdb.updateWords("269", words, ids, 0, LangHelper.LANGUAGE.EN);
Iterator<String> i = words.iterator();
while (i.hasNext()) {
Log.d("queryTestDebug", "word: " + i.next());
}
Log.d("queryTestDebug", "228->");
tdb.updateWords("228", words, ids, 0, LangHelper.LANGUAGE.EN);
i = words.iterator();
while (i.hasNext()) {
Log.d("queryTestDebug", "word: " + i.next());
}
endnow = SystemClock.uptimeMillis();
Log.d("TIMING", "Execution time: " + (endnow - startnow) + " ms");
}
@SuppressWarnings("unused")
private void queryTest() {
long startnow, endnow;
startnow = SystemClock.uptimeMillis();
T9DB tdb = T9DB.getInstance(this);
// tdb.getWords("123").iterator();
// tdb.getWords("269").iterator();
// tdb.getWords("228").iterator();
// tdb.getWords("24371").iterator();
// tdb.getWords("22376284").iterator();
// tdb.getWords("68372667367283").iterator();
// tdb.getWords("22637").iterator();
endnow = SystemClock.uptimeMillis();
Log.d("TIMING", "Execution time: " + (endnow - startnow) + " ms");
}
@SuppressWarnings("unused")
private void queryTestSingle() {
long startnow, endnow;
int size;
AbstractList<String> words = new ArrayList<String>(8);
ArrayList<Integer> ids = new ArrayList<Integer>(8);
startnow = SystemClock.uptimeMillis();
T9DB tdb = T9DB.getInstance(this);
tdb.updateWords("222", words, ids, 0, LangHelper.LANGUAGE.EN);
size = ids.size();
if (size > 0) {
tdb.incrementWord(ids.get(0));
tdb.incrementWord(ids.get(0));
tdb.incrementWord(ids.get(0));
}
for (int x = 0; x < size; x++) {
tdb.incrementWord(ids.get(x));
}
endnow = SystemClock.uptimeMillis();
Log.d("TIMING", "Execution time: " + (endnow - startnow) + " ms");
List<Integer> freqs = new ArrayList<Integer>(8);
//tdb.updateWordsW("222", words, ids, freqs, LangHelper.EN);
Log.d("VALUES", "...");
size = freqs.size();
for (int x = 0; x < size; x++) {
Log.d("VALUES",
"Word: " + words.get(x) + " id: " + ids.get(x) + " freq: " + freqs.get(x));
}
Log.d("queryTestSingle", "done.");
}
@Override
public void onCancel(DialogInterface dint) {

View file

@ -1,4 +1,4 @@
package io.github.sspanak.tt9;
package io.github.sspanak.tt9.db;
public class DBException extends Exception {
private static final long serialVersionUID = 376752656441823823L;

View file

@ -1,4 +1,4 @@
package io.github.sspanak.tt9;
package io.github.sspanak.tt9.db;
import android.app.IntentService;
import android.app.Notification;
@ -11,6 +11,8 @@ import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
import io.github.sspanak.tt9.R;
public class DBUpdateService extends IntentService {
private static final int UPDATING_NOTIFICATION_ID = 9640142;

View file

@ -0,0 +1,56 @@
package io.github.sspanak.tt9.db;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
public class DatabaseHelper extends SQLiteOpenHelper {
Context mContext = null;
DatabaseHelper(Context context) {
super(context, T9DB.DATABASE_NAME, null, T9DB.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(T9DB.DATABASE_NAME, 0, null);
int version = db.getVersion();
db.close();
return version < T9DB.DATABASE_VERSION;
} else {
return false;
}
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("CREATE TABLE IF NOT EXISTS " + T9DB.WORD_TABLE_NAME + " (" +
T9DB.COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
T9DB.COLUMN_LANG + " INTEGER, " +
T9DB.COLUMN_SEQ + " TEXT, " +
T9DB.COLUMN_WORD + " TEXT, " +
T9DB.COLUMN_FREQUENCY + " INTEGER, " +
"UNIQUE(" + T9DB.COLUMN_LANG + ", " + T9DB.COLUMN_WORD + ") )");
db.execSQL("CREATE INDEX IF NOT EXISTS idx ON " + T9DB.WORD_TABLE_NAME + "("
+ T9DB.COLUMN_LANG + ", " + T9DB.COLUMN_SEQ + " ASC, " + T9DB.COLUMN_FREQUENCY + " DESC )");
db.execSQL("CREATE TRIGGER IF NOT EXISTS " + T9DB.FREQ_TRIGGER_NAME +
" AFTER UPDATE ON " + T9DB.WORD_TABLE_NAME +
" WHEN NEW." + T9DB.COLUMN_FREQUENCY + " > " + T9DB.FREQ_MAX +
" BEGIN" +
" UPDATE " + T9DB.WORD_TABLE_NAME + " SET " + T9DB.COLUMN_FREQUENCY + " = "
+ T9DB.COLUMN_FREQUENCY + " / " + T9DB.FREQ_DIV +
" WHERE " + T9DB.COLUMN_SEQ + " = NEW." + T9DB.COLUMN_SEQ + ";" +
" END;");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("T9DB.onUpgrade", "Upgrading database from version " + oldVersion + " to " + newVersion);
onCreate(db);
// subsequent database migrations go here
Log.i("T9DB.onUpgrade", "Done.");
}
}

View file

@ -0,0 +1,299 @@
package io.github.sspanak.tt9.db;
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;
import android.database.sqlite.SQLiteDatabase;
import android.provider.BaseColumns;
import android.util.Log;
import android.widget.Toast;
import io.github.sspanak.tt9.CharMap;
import io.github.sspanak.tt9.LangHelper;
import io.github.sspanak.tt9.LangHelper.LANGUAGE;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.preferences.T9Preferences;
import java.util.AbstractList;
import java.util.Iterator;
import java.util.List;
public class T9DB {
private static volatile T9DB instance = null;
protected boolean ready = true;
public static final String DATABASE_NAME = "t9dict.db";
public static final int DATABASE_VERSION = 5; // Versions < 5 belong to the original project. We don't care about
// them and we don't migrate them, because the APP ID used to be
// different. This means the TT9 must be installed as a new application
// since version 5, which eliminates the possibility of reusing any
// legacy data.
public static final String WORD_TABLE_NAME = "word";
public static final String FREQ_TRIGGER_NAME = "freqtrigger";
// 50k, 10k
public static final int FREQ_MAX = 50000;
public static final int FREQ_DIV = 10000;
// This seems to be pretty fast on my phone. 10 is pretty slow (Might be because > MAX_RESULTS (8).)
private static final int MINHITS = 4;
public static final String COLUMN_ID = BaseColumns._ID;
public static final String COLUMN_LANG = "lang";
public static final String COLUMN_SEQ = "seq";
public static final String COLUMN_WORD = "word";
public 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 String UPDATEQ =
"UPDATE " + WORD_TABLE_NAME +
" SET " + COLUMN_FREQUENCY + " = " + COLUMN_FREQUENCY + "+1" +
" WHERE " + COLUMN_ID + "=";
private static final int MAX_RESULTS = 8;
private static final int MAX_MAX_RESULTS = 30; // to make sure we don't exceed candidate view array.
private DatabaseHelper mOpenHelper;
private SQLiteDatabase db;
private Context mContext;
public T9DB(Context caller) {
// create db
mContext = caller;
mOpenHelper = new DatabaseHelper(caller);
}
public static T9DB getInstance(Context caller) {
if (instance == null) {
synchronized (T9DB.class){
if (instance == null) {
instance = new T9DB (caller);
instance.init();
}
}
}
return instance;
}
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 ignored) { }
db = null;
}
Intent intent = new Intent(mContext, DBUpdateService.class);
Log.i("T9.init", "Invoking update service...");
mContext.startService(intent);
} else {
db = mOpenHelper.getWritableDatabase();
}
}
private boolean ensureDb() {
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 boolean isReady() {
return this.ready;
}
public void close() {
try { db.close(); }
catch (NullPointerException ignored) { }
db = null;
}
public void truncate() {
Log.i("T9DB.truncate", "Truncating words table...");
synchronized (T9DB.class) {
ready = false;
db = getWritableDatabase();
db.delete(WORD_TABLE_NAME, null, null);
ready = true;
}
Log.i("T9DB.truncate", "Done...");
}
public void showDBaccessError() {
Toast.makeText(mContext, R.string.database_notready, Toast.LENGTH_SHORT).show();
}
public void addWord(String iword, LANGUAGE 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, lang);
} catch (NullPointerException e) {
throw new DBException(r.getString(R.string.add_word_badchar, lang.name(), iword));
}
// add int sequence into num table
ContentValues values = new ContentValues();
values.put(COLUMN_SEQ, seq);
values.put(COLUMN_LANG, lang.id);
// add word into word
values.put(COLUMN_WORD, iword);
values.put(COLUMN_FREQUENCY, 1);
if (!ensureDb()) {
Log.e("T9DB.addWord", "not ready");
this.showDBaccessError();
return;
}
try {
db.insertOrThrow(WORD_TABLE_NAME, null, values);
} catch (SQLiteConstraintException e) {
String msg = r.getString(R.string.add_word_exist2, iword, lang.name());
Log.w("T9DB.addWord", msg);
throw new DBException(msg);
}
}
public void incrementWord(int id) {
if (!ensureDb()) {
Log.e("T9DB.incrementWord", "not ready");
this.showDBaccessError();
return;
}
db.execSQL(UPDATEQ + id);
// if id's freq is greater than FREQ_MAX, it gets normalized with trigger
}
public void updateWords(String is, AbstractList<String> stringList, List<Integer> intList,
int capsMode, LANGUAGE lang) {
stringList.clear();
intList.clear();
// String[] sa = packInts(stringToInts(is), true);
int islen = is.length();
if (!ensureDb()) {
Log.e("T9DB.updateWords", "not ready");
this.showDBaccessError();
return;
}
Cursor cur = db.rawQuery(QUERY1, new String[] { String.valueOf(lang.id), is });
int hits = 0;
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
stringList.add(cur.getString(1));
if (hits >= MAX_MAX_RESULTS) { break; } // to stop index error in candidate view
hits++;
}
cur.close();
if ((hits < MINHITS) && (islen >= 2)) {
char c = is.charAt(islen - 1);
c++;
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.id) });
for (cur.moveToFirst(); !cur.isAfterLast(); cur.moveToNext()) {
intList.add(cur.getInt(0));
stringList.add(cur.getString(1));
if (hits >= MAX_MAX_RESULTS) {
break;
}
hits++;
}
cur.close();
}
// Log.d("T9DB.updateWords", "pre: " + stringList);
if (capsMode == T9Preferences.CASE_LOWER) {
return;
}
// Log.d("T9DB.updateWords", "filtering...");
// filter list
Iterator<String> iter = stringList.iterator();
String word;
String wordtemp;
int index = 0;
boolean removed = false;
while (iter.hasNext()) {
word = iter.next();
switch (capsMode) {
case T9Preferences.CASE_UPPER:
wordtemp = word.toUpperCase(LangHelper.LOCALES[lang.index]);
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 T9Preferences.CASE_CAPITALIZE:
if (word.length() > 1) {
wordtemp = word.substring(0, 1).toUpperCase(LangHelper.LOCALES[lang.index]) + word.substring(1);
} else {
wordtemp = word.toUpperCase(LangHelper.LOCALES[lang.index]);
}
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);
removed = false;
} else {
index++;
}
}
//Log.d("T9DB.updateWords", "i:" + is + " words:" + Arrays.toString(stringList.toArray()));
}
}

View file

@ -0,0 +1,109 @@
package io.github.sspanak.tt9.preferences;
import android.content.Context;
import android.content.SharedPreferences;
import androidx.preference.PreferenceManager;
import android.view.KeyEvent;
public class T9Preferences {
private static T9Preferences self;
private SharedPreferences prefs;
private SharedPreferences.Editor prefsEditor;
public static final int CASE_LOWER = 0;
public static final int CASE_CAPITALIZE = 1;
public static final int CASE_UPPER = 2;
public static final int MODE_PREDICTIVE = 0;
public static final int MODE_ABC = 1;
public static final int MODE_123 = 2;
public T9Preferences (Context context) {
prefs = PreferenceManager.getDefaultSharedPreferences(context.getApplicationContext());
prefsEditor = prefs.edit();
}
public static T9Preferences getInstance(Context context) {
if (self == null) {
self = new T9Preferences(context);
}
return self;
}
public int getEnabledLanguages() {
return prefs.getInt("pref_enabled_languages", 1);
}
public T9Preferences setEnabledLanguages(int languageMask) {
prefsEditor.putInt("pref_enabled_languages", languageMask);
prefsEditor.apply();
return this;
}
// public int getInputCase() {
// return prefs.getInt("pref_input_case", CASE_CAPITALIZE);
// }
public int getInputLanguage() {
return prefs.getInt("pref_input_language", 1);
}
public T9Preferences setInputLanguage(int language) {
prefsEditor.putInt("pref_input_language", language);
prefsEditor.apply();
return this;
}
public int getInputMode() {
return prefs.getInt("pref_input_mode", MODE_PREDICTIVE);
}
public T9Preferences setInputMode(int mode) throws Exception {
if (mode != MODE_PREDICTIVE && mode != MODE_ABC && mode != MODE_123) {
throw new Exception("Invalid input mode: '" + mode + "'");
}
prefsEditor.putInt("pref_input_mode", mode);
prefsEditor.apply();
return this;
}
public int getKeyBackspace() {
return prefs.getInt("pref_key_backspace", KeyEvent.KEYCODE_DEL);
}
// public int getKeyInputMode() {
// return prefs.getInt("pref_key_inputmode", KeyEvent.KEYCODE_POUND);
// }
// public int getKeyOtherActions() {
// return prefs.getInt("pref_key_other_actions", KeyEvent.KEYCODE_CALL);
// }
// public boolean getSoftBackspaceEnabled() {
// return prefs.getBoolean("pref_softkey_backspace", true);
// }
// public boolean getSoftPrefsEnabled() {
// return prefs.getBoolean("pref_softkey_prefs", true);
// }
public String getLastWord() {
return prefs.getString("last_word", "");
}
public T9Preferences setLastWord(String lastWord) {
// "last_word" was part of the original Preferences implementation.
// It is weird, but it is simple and it works, so I decided to keep it.
prefsEditor.putString("last_word", lastWord);
prefsEditor.apply();
return this;
}
}

View file

@ -1,49 +0,0 @@
package io.github.sspanak.tt9.settings;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.CheckBox;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.T9DB;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
public class SettingCheck extends Setting {
boolean value;
boolean defaultValue;
public SettingCheck (Context context, AttributeSet attrs, Object[] isettings) {
super(context, attrs, isettings);
// http://stackoverflow.com/a/8488691
for (int i = 0; i < attrs.getAttributeCount(); i++) {
String attr = attrs.getAttributeName(i);
if ("defaultValue".equals(attr)) {
defaultValue = attrs.getAttributeBooleanValue(i, false);
}
}
SETTING s = SETTING.get(id);
if (s != null) {
Object o = isettings[s.sqOrder];
if (o == null)
value = defaultValue;
else
value = o.equals(1);
}
widgetID = R.layout.checkbox;
layout = R.layout.setting_widget;
}
@Override
public void clicked(Context context) {
value = !value;
T9DB.getInstance(context).storeSettingInt(SETTING.get(id), value ? 1 : 0);
((CheckBox)view.findViewById(R.id.checkbox)).setChecked(value);
}
@Override
public void init(){
((CheckBox)view.findViewById(R.id.checkbox)).setChecked(value);
}
}

View file

@ -4,10 +4,10 @@ import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import android.util.Log;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.T9DB;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
import io.github.sspanak.tt9.preferences.T9Preferences;
public class SettingList extends Setting {
String[] entries;
@ -56,7 +56,13 @@ public class SettingList extends Setting {
@Override
public void onClick(DialogInterface dialog, int which) {
T9DB.getInstance(context).storeSettingInt(SETTING.get(id), entryValues[which]);
if (id.equals("pref_inputmode")) {
try {
T9Preferences.getInstance(context).setInputMode(entryValues[which]);
} catch (Exception e) {
Log.e("SettingsList", e.getMessage());
}
}
value = entryValues[which];
dialog.dismiss();
}

View file

@ -8,8 +8,7 @@ import android.widget.TextView;
import io.github.sspanak.tt9.LangHelper;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.T9DB;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
import io.github.sspanak.tt9.preferences.T9Preferences;
public class SettingMultiList extends SettingList {
boolean[] selectedEntries = new boolean[0];
@ -38,7 +37,9 @@ public class SettingMultiList extends SettingList {
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
T9DB.getInstance(context).storeSettingInt(SETTING.get(id), LangHelper.shrinkLangs(buildSelection()));
if (id.equals("pref_lang_support")) {
T9Preferences.getInstance(context).setEnabledLanguages(LangHelper.shrinkLangs(buildSelection()));
}
summary = buildItems();
dialog.dismiss();
((TextView)view.findViewById(R.id.summary)).setText(summary);