1
0
Fork 0

New logo and updated documentation (#33)

* new logo

* updated license and readme files

* renamed the Java package name again
This commit is contained in:
Dimo Karaivanov 2022-07-23 15:13:18 +03:00 committed by GitHub
parent 004b06d694
commit 24ec816681
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
46 changed files with 163 additions and 88 deletions

View file

@ -0,0 +1,301 @@
package io.github.sspanak.tt9;
import android.app.Dialog;
import android.content.Context;
import android.inputmethodservice.KeyboardView;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;
import java.util.Arrays;
public abstract class AbsSymDialog extends Dialog implements
View.OnClickListener {
protected Context context;
private View mainview;
private int pagenum = 1;
private int pageoffset = (pagenum - 1) * 10;
private int MAX_PAGE;
private boolean started;
private static final int[] buttons = {
R.id.text_keyone, R.id.text_keytwo,
R.id.text_keythree, R.id.text_keyfour, R.id.text_keyfive,
R.id.text_keysix, R.id.text_keyseven, R.id.text_keyeight,
R.id.text_keynine, R.id.text_keyzero
};
private static final int[] buttons2 = {
R.id.text_keystar,
R.id.text_keypound
};
public AbsSymDialog(Context c, View mv) {
super(c);
context = c;
mainview = mv;
started = true;
setContentView(mv);
View button;
for (int butt : buttons) {
button = mv.findViewById(butt);
button.setOnClickListener(this);
}
for (int butt : buttons2) {
button = mv.findViewById(butt);
button.setOnClickListener(this);
}
MAX_PAGE = getMaxPage();
}
// must return a string array the same size as the length of the button string array.
abstract String[] getContentDescription();
@Override
public void onClick(View v) {
// Log.d("SymbolPopup - onClick", "click happen: " + v);
switch (v.getId()) {
case R.id.text_keyone:
sendChar(pageoffset);
break;
case R.id.text_keytwo:
sendChar(pageoffset + 1);
break;
case R.id.text_keythree:
sendChar(pageoffset + 2);
break;
case R.id.text_keyfour:
sendChar(pageoffset + 3);
break;
case R.id.text_keyfive:
sendChar(pageoffset + 4);
break;
case R.id.text_keysix:
sendChar(pageoffset + 5);
break;
case R.id.text_keyseven:
sendChar(pageoffset + 6);
break;
case R.id.text_keyeight:
sendChar(pageoffset + 7);
break;
case R.id.text_keynine:
sendChar(pageoffset + 8);
break;
case R.id.text_keyzero:
sendChar(pageoffset + 9);
break;
case R.id.text_keypound:
pageChange(1);
break;
case R.id.text_keystar:
pageChange(-1);
break;
}
}
protected abstract String getSymbol(int index);
protected abstract String getTitleText();
protected abstract int getSymbolSize();
protected abstract int getMaxPage();
private void sendChar(int index) {
// Log.d("SymbolDialog - sendChar", "Sending index: " + index);
if (index < getSymbolSize()) {
((KeyboardView.OnKeyboardActionListener) context).onText(getSymbol(index));
// then close
pagenum = 1;
pageoffset = (pagenum - 1) * 10;
this.dismiss();
}
}
private void pageChange(int amt) {
pagenum = pagenum + amt;
if (pagenum > MAX_PAGE) {
pagenum = 1;
} else if (pagenum < 1) {
pagenum = MAX_PAGE;
}
pageoffset = (pagenum - 1) * 10;
updateButtons();
}
private void updateButtons() {
// set page number text
setTitle(String.format("%s\t\t%s", getTitleText(),
context.getResources().getString(R.string.symbol_page, pagenum, MAX_PAGE)));
// update button labels
int symbx = pageoffset;
int stop = symbx + 9;
int nomore = stop;
int symsize = getSymbolSize();
if (nomore >= symsize - 1) {
nomore = symsize - 1;
}
TextView tv;
String[] cd = getContentDescription();
for (int buttx = 0; symbx <= stop; symbx++) {
// Log.d("SymbolDialog - updateButtons", "buttx: " + buttx +
// " symbx: " + symbx);
if (symbx > nomore) {
((TextView) mainview.findViewById(buttons[buttx])).setText("");
} else {
tv = (TextView) mainview.findViewById(buttons[buttx]);
tv.setText(String.valueOf(getSymbol(symbx)));
if (cd != null) {
tv.setContentDescription(cd[symbx]);
}
}
buttx++;
}
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (event.getRepeatCount() != 0) {
return true;
}
if (started) {
started = false;
}
// TODO: remove emulator special keys
switch (keyCode) {
case 75:
keyCode = KeyEvent.KEYCODE_POUND;
break;
case 74:
keyCode = KeyEvent.KEYCODE_STAR;
break;
}
// Log.d("AbsSymDialog.onKeyDown", "bootan pres: " + keyCode);
switch (keyCode) {
case KeyEvent.KEYCODE_0:
case KeyEvent.KEYCODE_1:
case KeyEvent.KEYCODE_2:
case KeyEvent.KEYCODE_3:
case KeyEvent.KEYCODE_4:
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_6:
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_8:
case KeyEvent.KEYCODE_9:
case KeyEvent.KEYCODE_POUND:
case KeyEvent.KEYCODE_STAR:
event.startTracking();
return true;
}
return super.onKeyDown(keyCode, event);
}
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// Log.d("AbsSymDialog.onKeyUp", "Key: " + keyCode);
if (started) {
started = false;
return true;
}
// TODO: remove emulator special keys
switch (keyCode) {
case 75:
keyCode = KeyEvent.KEYCODE_POUND;
break;
case 74:
keyCode = KeyEvent.KEYCODE_STAR;
break;
}
switch (keyCode) {
// pass-through
case KeyEvent.KEYCODE_0:
case KeyEvent.KEYCODE_1:
case KeyEvent.KEYCODE_2:
case KeyEvent.KEYCODE_3:
case KeyEvent.KEYCODE_4:
case KeyEvent.KEYCODE_5:
case KeyEvent.KEYCODE_6:
case KeyEvent.KEYCODE_7:
case KeyEvent.KEYCODE_8:
case KeyEvent.KEYCODE_9:
case KeyEvent.KEYCODE_POUND:
case KeyEvent.KEYCODE_STAR:
onKey(keyCode);
return true;
default:
// KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD).getNumber(keyCode)
// Log.w("onKeyUp", "Unhandled Key: " + keyCode + "(" +
// event.toString() + ")");
}
return super.onKeyUp(keyCode, event);
}
private void onKey(int keyCode) {
// Log.d("OnKey", "pri: " + keyCode);
// Log.d("onKey", "START Cm: " + mCapsMode);
// HANDLE SPECIAL KEYS
switch (keyCode) {
case KeyEvent.KEYCODE_1:
sendChar(pageoffset);
break;
case KeyEvent.KEYCODE_2:
sendChar(pageoffset + 1);
break;
case KeyEvent.KEYCODE_3:
sendChar(pageoffset + 2);
break;
case KeyEvent.KEYCODE_4:
sendChar(pageoffset + 3);
break;
case KeyEvent.KEYCODE_5:
sendChar(pageoffset + 4);
break;
case KeyEvent.KEYCODE_6:
sendChar(pageoffset + 5);
break;
case KeyEvent.KEYCODE_7:
sendChar(pageoffset + 6);
break;
case KeyEvent.KEYCODE_8:
sendChar(pageoffset + 7);
break;
case KeyEvent.KEYCODE_9:
sendChar(pageoffset + 8);
break;
case KeyEvent.KEYCODE_0:
sendChar(pageoffset + 9);
break;
case KeyEvent.KEYCODE_STAR:
pageChange(-1);
break;
case KeyEvent.KEYCODE_POUND:
pageChange(1);
break;
}
}
protected void doShow(View v) {
// based on http://stackoverflow.com/a/13962770
started = true;
Window win = getWindow();
WindowManager.LayoutParams lp = win.getAttributes();
lp.token = v.getWindowToken();
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
win.setAttributes(lp);
win.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
updateButtons();
try {
show();
} catch (Exception e) {
Log.e("AbsSymDialog", "Cannot create Dialog:");
Log.e("AbsSymDialog", Arrays.toString(e.getStackTrace()));
}
}
}

View file

@ -0,0 +1,81 @@
package io.github.sspanak.tt9;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
public class AddWordAct extends Activity {
View main;
int lang;
String origword;
@Override
protected void onCreate(Bundle savedData) {
super.onCreate(savedData);
View v = getLayoutInflater().inflate(R.layout.addwordview, null);
EditText et = (EditText) v.findViewById(R.id.add_word_text);
Intent i = getIntent();
origword = i.getStringExtra("io.github.sspanak.tt9.word");
lang = i.getIntExtra("io.github.sspanak.tt9.lang", -1);
if (lang == -1) {
Log.e("AddWordAct.onCreate", "lang is invalid. How?");
}
// Log.d("AddWord", "data.get: " + word);
et.setText(origword);
et.setSelection(origword.length());
setContentView(v);
main = v;
}
public void addWordButton(View v) {
EditText et = (EditText) main.findViewById(R.id.add_word_text);
// Log.d("AddWordAct", "adding word: " + et.getText());
doAddWord(et.getText().toString());
this.finish();
}
public void doAddWord(String text) {
T9DB db = T9DB.getInstance(this);
try {
db.addWord(text, LangHelper.LANGUAGE.get(lang));
} catch (DBException e) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
String msg = e.getMessage();
//Log.e("AddWord.doAddWord", msg);
builder.setMessage(msg).setTitle(R.string.add_word)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
db.storeSettingString(SETTING.LAST_WORD, text);
}
public void cancelButton(View v) {
// Log.d("AddWordAct", "Cancelled...");
this.finish();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.add_word, menu);
return true;
}
}

View file

@ -0,0 +1,221 @@
package io.github.sspanak.tt9;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import java.util.ArrayList;
import java.util.List;
public class CandidateView extends View {
private List<String> mSuggestions;
protected int mSelectedIndex;
private Drawable mSelectionHighlight;
private Rect mBgPadding;
private static final int MAX_SUGGESTIONS = 32;
private static final int SCROLL_PIXELS = 20;
private int[] mWordWidth = new int[MAX_SUGGESTIONS];
private int[] mWordX = new int[MAX_SUGGESTIONS];
private static final int X_GAP = 10;
private static final List<String> EMPTY_LIST = new ArrayList<String>();
private int mColorNormal;
private int mColorRecommended;
private int mColorOther;
private int mVerticalPadding;
private Paint mPaint;
private int mTargetScrollX;
private int mTotalWidth;
Rect mPadding;
/**
* Construct a CandidateView for showing suggested words for completion.
*
* @param context
*/
public CandidateView(Context context) {
super(context);
mSelectionHighlight = context.getResources().getDrawable(
android.R.drawable.list_selector_background);
mSelectionHighlight.setState(new int[] {
android.R.attr.state_enabled, android.R.attr.state_focused,
android.R.attr.state_window_focused, android.R.attr.state_pressed });
Resources r = context.getResources();
setBackgroundColor(r.getColor(R.color.candidate_background));
mColorNormal = r.getColor(R.color.candidate_normal);
mColorRecommended = r.getColor(R.color.candidate_recommended);
mColorOther = r.getColor(R.color.candidate_other);
mVerticalPadding = r.getDimensionPixelSize(R.dimen.candidate_vertical_padding);
mPaint = new Paint();
mPaint.setColor(mColorNormal);
mPaint.setAntiAlias(true);
mPaint.setTextSize(r.getDimensionPixelSize(R.dimen.candidate_font_height));
mPaint.setStrokeWidth(0);
mPadding = new Rect();
setHorizontalFadingEdgeEnabled(true);
setWillNotDraw(false);
setHorizontalScrollBarEnabled(false);
setVerticalScrollBarEnabled(false);
}
@Override
public int computeHorizontalScrollRange() {
return mTotalWidth;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int measuredWidth = resolveSize(50, widthMeasureSpec);
// Get the desired height of the icon menu view (last row of items does
// not have a divider below)
mSelectionHighlight.getPadding(mPadding);
final int desiredHeight = ((int) mPaint.getTextSize()) + mVerticalPadding + mPadding.top
+ mPadding.bottom;
// Maximum possible width and desired height
setMeasuredDimension(measuredWidth, resolveSize(desiredHeight, heightMeasureSpec));
}
/**
* If the canvas is null, then only touch calculations are performed to pick
* the target candidate.
*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mTotalWidth = 0;
if (mSuggestions == null)
return;
if (mBgPadding == null) {
mBgPadding = new Rect(0, 0, 0, 0);
if (getBackground() != null) {
getBackground().getPadding(mBgPadding);
}
}
int x = 0;
final int count = mSuggestions.size();
final int height = getHeight();
final Rect bgPadding = mBgPadding;
final Paint paint = mPaint;
final int y = (int) (((height - mPaint.getTextSize()) / 2) - mPaint.ascent());
for (int i = 0; i < count; i++) {
String suggestion = mSuggestions.get(i);
float textWidth = paint.measureText(suggestion);
final int wordWidth = (int) textWidth + X_GAP * 2;
mWordX[i] = x;
mWordWidth[i] = wordWidth;
paint.setColor(mColorNormal);
// if (touchX + scrollX >= x && touchX + scrollX < x + wordWidth &&
// !scrolled) {
if (i == mSelectedIndex) {
canvas.translate(x, 0);
mSelectionHighlight.setBounds(0, bgPadding.top, wordWidth, height);
mSelectionHighlight.draw(canvas);
canvas.translate(-x, 0);
paint.setFakeBoldText(true);
paint.setColor(mColorRecommended);
} else {
paint.setColor(mColorOther);
}
canvas.drawText(suggestion, x + X_GAP, y, paint);
paint.setColor(mColorOther);
canvas.drawLine(x + wordWidth + 0.5f, bgPadding.top, x + wordWidth + 0.5f, height + 1,
paint);
paint.setFakeBoldText(false);
x += wordWidth;
}
mTotalWidth = x;
if (mTargetScrollX != getScrollX()) {
scrollToTarget();
}
}
private void scrollToTarget() {
int sx = getScrollX();
if (mTargetScrollX > sx) {
sx += SCROLL_PIXELS;
if (sx >= mTargetScrollX) {
sx = mTargetScrollX;
requestLayout();
}
} else {
sx -= SCROLL_PIXELS;
if (sx <= mTargetScrollX) {
sx = mTargetScrollX;
requestLayout();
}
}
scrollTo(sx, getScrollY());
invalidate();
}
protected void setSuggestions(List<String> suggestions, int initialSel) {
clear();
if (suggestions != null) {
mSuggestions = suggestions;
mSelectedIndex = initialSel;
}
scrollTo(0, 0);
mTargetScrollX = 0;
// Compute the total width
// onDraw(null);
invalidate();
requestLayout();
}
protected void clear() {
mSuggestions = EMPTY_LIST;
mSelectedIndex = -1;
invalidate();
}
protected void scrollSuggestion(int increment) {
if (mSuggestions != null && mSuggestions.size() > 1) {
mSelectedIndex = mSelectedIndex + increment;
if (mSelectedIndex == mSuggestions.size()) {
mSelectedIndex = 0;
} else if (mSelectedIndex < 0) {
mSelectedIndex = mSuggestions.size() - 1;
}
int fullsize = getWidth();
int halfsize = fullsize / 2;
mTargetScrollX = mWordX[mSelectedIndex] + (mWordWidth[mSelectedIndex] / 2) - halfsize;
if (mTargetScrollX < 0) {
mTargetScrollX = 0;
} else if (mTargetScrollX > (mTotalWidth - fullsize)) {
mTargetScrollX = mTotalWidth - fullsize;
}
invalidate();
}
}
}

View file

@ -0,0 +1,181 @@
package io.github.sspanak.tt9;
import android.util.Log;
import io.github.sspanak.tt9.LangHelper.LANGUAGE;
import java.util.AbstractList;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class CharMap {
protected static final AbstractList<Map<Character, Integer>> CHARTABLE = new ArrayList<Map<Character, Integer>>(LangHelper.NLANGS);
static {
// Punctuation
Map<Character, Integer> commonMap = new HashMap<Character, Integer>();
commonMap.put('.', 1); commonMap.put(',', 1); commonMap.put('!', 1); commonMap.put('?', 1);
commonMap.put('-', 1); commonMap.put('"', 1); commonMap.put('\'', 1); commonMap.put('@', 1);
commonMap.put('#', 1); commonMap.put('$', 1); commonMap.put('%', 1); commonMap.put('&', 1);
commonMap.put('*', 1); commonMap.put('(', 1); commonMap.put(')', 1); commonMap.put(':', 1);
commonMap.put(';', 1); commonMap.put('/', 1); commonMap.put('+', 1); commonMap.put('=', 1);
commonMap.put('<', 1); commonMap.put('>', 1); commonMap.put('^', 1); commonMap.put('_', 1);
commonMap.put('~', 1);
commonMap.put('1', 1); commonMap.put('2', 2); commonMap.put('3', 3);
commonMap.put('4', 4); commonMap.put('5', 5); commonMap.put('6', 6);
commonMap.put('7', 7); commonMap.put('8', 8); commonMap.put('9', 9);
commonMap.put('+', 0); commonMap.put('0', 0); // not sure why "+" is both on 1 on 0, but kept it anyway
/*** Latin Scripts ***/
// English
// the English dictionary contains foreign words with their original spelling,
// so non-English characters must be inside the map
Map<Character, Integer> enMap = new HashMap<Character, Integer>(commonMap);
enMap.put('a', 2); enMap.put('á', 2); enMap.put('ä', 2); enMap.put('â', 2);
enMap.put('à', 2); enMap.put('å', 2); enMap.put('b', 2); enMap.put('c', 2);
enMap.put('ç', 2);
enMap.put('d', 3); enMap.put('e', 3); enMap.put('é', 3); enMap.put('ë', 3);
enMap.put('è', 3); enMap.put('ê', 3); enMap.put('f', 3);
enMap.put('g', 4); enMap.put('h', 4); enMap.put('i', 4); enMap.put('í', 4);
enMap.put('ï', 4);
enMap.put('j', 5); enMap.put('k', 5); enMap.put('l', 5); enMap.put('5', 5);
enMap.put('m', 6); enMap.put('n', 6); enMap.put('ñ', 6); enMap.put('o', 6);
enMap.put('ó', 6); enMap.put('ö', 6); enMap.put('ô', 6);
enMap.put('p', 7); enMap.put('q', 7); enMap.put('r', 7); enMap.put('s', 7);
enMap.put('t', 8); enMap.put('u', 8); enMap.put('û', 6); enMap.put('ü', 8);
enMap.put('v', 8);
enMap.put('w', 9); enMap.put('x', 9); enMap.put('y', 9); enMap.put('z', 9);
// add extra characters for German and French maps.
enMap.put('€', 1); enMap.put('ß', 7); // German chars
enMap.put('æ', 1); enMap.put('î', 4); enMap.put('ù', 8); enMap.put('œ', 6); // French chars
enMap.put('ì', 4); enMap.put('ò', 8); // Italian chars
/*** Cyrillic Scripts ***/
Map<Character, Integer> cyrillicMap = new HashMap<Character, Integer>(commonMap);
cyrillicMap.put('а', 2); cyrillicMap.put('б', 2); cyrillicMap.put('в', 2); cyrillicMap.put('г', 2);
cyrillicMap.put('д', 3); cyrillicMap.put('е', 3); cyrillicMap.put('ж', 3); cyrillicMap.put('з', 3);
cyrillicMap.put('и', 4); cyrillicMap.put('й', 4); cyrillicMap.put('к', 4); cyrillicMap.put('л', 4);
cyrillicMap.put('м', 5); cyrillicMap.put('н', 5); cyrillicMap.put('о', 5); cyrillicMap.put('п', 5);
cyrillicMap.put('р', 6); cyrillicMap.put('с', 6); cyrillicMap.put('т', 6); cyrillicMap.put('у', 6);
cyrillicMap.put('ф', 7); cyrillicMap.put('х', 7); cyrillicMap.put('ц', 7); cyrillicMap.put('ч', 7);
cyrillicMap.put('ш', 8); cyrillicMap.put('щ', 8);
cyrillicMap.put('ь', 9); cyrillicMap.put('ю', 9); cyrillicMap.put('я', 9);
// Bulgarian
Map<Character, Integer> bgMap = new HashMap<Character, Integer>(cyrillicMap);
bgMap.put('ъ', 8);
// Russian
Map<Character, Integer> ruMap = new HashMap<Character, Integer>(bgMap);
ruMap.put('ё', 3); ruMap.put('ы', 8); ruMap.put('э', 9);
// Ukrainian
Map<Character, Integer> ukMap = new HashMap<Character, Integer>(cyrillicMap);
ukMap.put('ґ', 2); ukMap.put('є', 3); ukMap.put('і', 4); ukMap.put('ї', 4);// Ukrainian chars
CHARTABLE.add(0, Collections.unmodifiableMap(enMap));
CHARTABLE.add(1, Collections.unmodifiableMap(ruMap));
CHARTABLE.add(2, Collections.unmodifiableMap(enMap));
CHARTABLE.add(3, Collections.unmodifiableMap(enMap));
CHARTABLE.add(4, Collections.unmodifiableMap(enMap));
CHARTABLE.add(5, Collections.unmodifiableMap(ukMap));
CHARTABLE.add(6, Collections.unmodifiableMap(bgMap));
}
protected static final char[][] ENT9TABLE = { { '0', '+' },
{ '.', ',', '?', '!', '"', '/', '-', '@', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'a', 'b', 'c', 'A', 'B', 'C', '2' }, { 'd', 'e', 'f', 'D', 'E', 'F', '3' },
{ 'g', 'h', 'i', 'G', 'H', 'I', '4' }, { 'j', 'k', 'l', 'J', 'K', 'L', '5' },
{ 'm', 'n', 'o', 'M', 'N', 'O', '6' }, { 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S', '7' },
{ 't', 'u', 'v', 'T', 'U', 'V', '8' }, { 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][] RUT9TABLE = { { '0', '+' },
{ '.', ',', '?', '!', '"', '/', '-', '@', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'а', 'б', 'в', 'г', 'А', 'Б', 'В', 'Г', '2' }, { 'д', 'е', 'ё', 'ж', 'з', 'Д', 'Е', 'Ё', 'Ж', 'З', '3' },
{ 'и', 'й', 'к', 'л', 'И', 'Й', 'К', 'Л', '4' }, { 'м', 'н', 'о', 'п', 'М', 'Н', 'О', 'П', '5' },
{ 'р', 'с', 'т', 'у', 'Р', 'С', 'Т', 'У', '6' }, { 'ф', 'х', 'ц', 'ч', 'Ф', 'Х', 'Ц', 'Ч', '7' },
{ 'ш', 'щ', 'ъ', 'ы', 'Ш', 'Щ', 'Ъ', 'Ы', '8' }, { 'ь', 'э', 'ю', 'я', 'Ь', 'Э', 'Ю', 'Я', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][] DET9TABLE = {
{ '0', '+' },
{ '.', ',', '?', '!', ':', ';', '"', '\'', '-', '@', '^', '€', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'a', 'b', 'c', 'A', 'B', 'C', 'ä', 'Ä','á', 'â', 'à', 'å', 'ç', 'Á', 'Â', 'À', 'Å', 'Ç', '2' },
{ 'd', 'e', 'f', 'D', 'E', 'F', 'é','ë','è','ê', 'É', 'Ë', 'È', 'Ê', '3' },
{ 'g', 'h', 'i', 'G', 'H', 'I', 'í', 'ï', 'Í', 'Ï', '4' },
{ 'j', 'k', 'l', 'J', 'K', 'L', '5' },
{ 'm', 'n', 'o', 'M', 'N', 'O', 'ö', 'Ö', 'ñ','ó','ô', 'Ñ', 'Ó', 'Ô', '6' },
{ 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S', 'ß', '7' },
{ 't', 'u', 'v', 'T', 'U', 'V', 'ü', 'Ü', 'û', 'Û', '8' },
{ 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][] FRT9TABLE = {
{ '0', '+' },
{ '.', ',', '?', '!', ':', ';', '"', '/', '-', '@', '^', '€', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'a', 'b', 'c', 'A', 'B', 'C', '2', 'â', 'à', 'æ', 'ç', 'Â', 'À', 'Æ', 'Ç'},
{ 'd', 'e', 'f', 'D', 'E', 'F', '3', 'é', 'è','ê', 'ë', 'É', 'È', 'Ê', 'Ë' },
{ 'g', 'h', 'i', 'G', 'H', 'I', '4', 'î', 'ï', 'Î', 'Ï' },
{ 'j', 'k', 'l', 'J', 'K', 'L', '5' },
{ 'm', 'n', 'o', 'M', 'N', 'O', '6', 'ô', 'œ', 'Ô', 'Œ'},
{ 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S', '7' },
{ 't', 'u', 'v', 'T', 'U', 'V', '8', 'û', 'Û', 'ù', 'Ù', 'ü', 'Ü'},
{ 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][] ITT9TABLE = {
{ '+', '0' },
{ '.', ',', '?', '!', ':', ';', '"', '/', '-', '@', '^', '€', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'a', 'b', 'c', 'A', 'B', 'C', 'à', 'À', '2' }, { 'd', 'e', 'f', 'D', 'E', 'F', 'é', 'è', 'É', 'È', '3' },
{ 'g', 'h', 'i', 'G', 'H', 'I', 'ì', 'Ì', '4' }, { 'j', 'k', 'l', 'J', 'K', 'L', '5' },
{ 'm', 'n', 'o', 'M', 'N', 'O', 'ò', 'Ò', '6' }, { 'p', 'q', 'r', 's', 'P', 'Q', 'R', 'S', '7' },
{ 't', 'u', 'v', 'T', 'U', 'V', 'ù', 'Ù', '8' }, { 'w', 'x', 'y', 'z', 'W', 'X', 'Y', 'Z', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][] UKT9TABLE = { { '0', '+' },
{ '.', ',', '?', '!', '\'', '"', '/', '-', '@', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'а', 'б', 'в', 'г', 'ґ', 'А', 'Б', 'В', 'Г', 'Ґ', '2' }, { 'д', 'е', 'є', 'ж', 'з', 'Д', 'Е', 'Є', 'Ж', 'З', '3' },
{ 'и', 'і', 'ї', 'й', 'к', 'л', 'И', 'І', 'Ї', 'Й', 'К', 'Л', '4' }, { 'м', 'н', 'о', 'п', 'М', 'Н', 'О', 'П', '5' },
{ 'р', 'с', 'т', 'у', 'Р', 'С', 'Т', 'У', '6' }, { 'ф', 'х', 'ц', 'ч', 'Ф', 'Х', 'Ц', 'Ч', '7' },
{ 'ш', 'щ', 'Ш', 'Щ', '8' }, { 'ь', 'ю', 'я', 'Ь', 'Ю', 'Я', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][] BGT9TABLE = { { '0', '+' },
{ '.', ',', '?', '!', '\'', '"', '/', '-', '@', '$', '%', '&', '*', '#', '(', ')', '_', '1' },
{ 'а', 'б', 'в', 'г', 'А', 'Б', 'В', 'Г', '2' }, { 'д', 'е', 'ж', 'з', 'Д', 'Е', 'Ж', 'З', '3' },
{ 'и', 'й', 'к', 'л', 'И', 'Й', 'К', 'Л', '4' }, { 'м', 'н', 'о', 'п', 'М', 'Н', 'О', 'П', '5' },
{ 'р', 'с', 'т', 'у', 'Р', 'С', 'Т', 'У', '6' }, { 'ф', 'х', 'ц', 'ч', 'Ф', 'Х', 'Ц', 'Ч', '7' },
{ 'ш', 'щ', 'ъ', 'Ш', 'Щ', 'Ъ', '8' }, { 'ь', 'ю', 'я', 'Ь', 'Ю', 'Я', '9' },
{ ' ', '\n' }, { ' ', '0', '+' }, { '\n' } }; // LAST TWO SPACE ON 0
protected static final char[][][] T9TABLE = { ENT9TABLE, RUT9TABLE, DET9TABLE, FRT9TABLE, ITT9TABLE, UKT9TABLE, BGT9TABLE };
// last 2 don't matter, are for spaceOnZero extra 'slots' 0 position, and 10 position
protected static final int[] ENT9CAPSTART = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0, 0 };
protected static final int[] RUT9CAPSTART = { 0, 0, 4, 5, 4, 4, 4, 4, 4, 4, 0, 0, 0 };
protected static final int[] DET9CAPSTART = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0, 0 };
protected static final int[] FRT9CAPSTART = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0, 0 };
protected static final int[] ITT9CAPSTART = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4, 0, 0, 0 };
protected static final int[] UKT9CAPSTART = { 0, 0, 5, 5, 6, 4, 4, 4, 2, 3, 0, 0, 0 };
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) {
StringBuilder seq = new StringBuilder();
String tword = word.toLowerCase(LangHelper.LOCALES[lang.index]);
for (int i = 0; i < word.length(); i++) {
char c = tword.charAt(i);
Integer z = CharMap.CHARTABLE.get(lang.index).get(c);
if (z == null) {
Log.e("getStringSequence",
"ERROR: " + (int) c + " NOT FOUND FOR [" + lang.name() + "] (" + Integer.toHexString((int) c) + ") Index: " + i);
throw new NullPointerException();
}
seq.append(z.toString());
}
return seq.toString();
}
}

View file

@ -0,0 +1,10 @@
package io.github.sspanak.tt9;
public class DBException extends Exception {
private static final long serialVersionUID = 376752656441823823L;
protected DBException(String message) {
super(message);
}
}

View file

@ -0,0 +1,80 @@
package io.github.sspanak.tt9;
import android.app.IntentService;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.database.sqlite.SQLiteDatabase;
import android.os.Handler;
import android.util.Log;
import android.widget.Toast;
public class DBUpdateService extends IntentService {
private static final int UPDATING_NOTIFICATION_ID = 9640142;
private Handler mHandler;
// http://stackoverflow.com/a/20690225
public class DisplayToast implements Runnable {
private final Context mContext;
CharSequence mText;
public DisplayToast(Context mContext, CharSequence text){
this.mContext = mContext;
mText = text;
}
public void run(){
Toast.makeText(mContext, mText, Toast.LENGTH_SHORT).show();
}
}
public DBUpdateService() {
super("DBUpdateService");
mHandler = new Handler();
}
/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// do things
T9DB dbhelper = T9DB.getInstance(this);
if (dbhelper.getSQLDB(this) != null) {
return;
}
Log.d("T9DBUpdate.onHandle", "Update pass check.");
// do real things
Intent notificationIntent = new Intent(this, DBUpdateService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
Notification.Builder nBuilder = new Notification.Builder(this);
Notification notification = nBuilder
.setContentIntent(pendingIntent)
.setContentTitle(getText(R.string.updating_database_title))
.setContentText(getText(R.string.updating_database))
.setSmallIcon(R.drawable.ime_lang_en_lower)
.getNotification();
notificationManager.notify(UPDATING_NOTIFICATION_ID, notification);
startForeground(UPDATING_NOTIFICATION_ID, notification);
//put this in a thread
mHandler.post(new DisplayToast(this, getText(R.string.updating_database)));
SQLiteDatabase tdb = dbhelper.getWritableDatabase();
dbhelper.setSQLDB(tdb);
mHandler.post(new DisplayToast(this, getText(R.string.updating_database_done)));
Log.d("T9DBUpdate.onHandle", "done.");
}
}

View file

@ -0,0 +1,135 @@
package io.github.sspanak.tt9;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.ViewSwitcher;
public class InterfaceHandler implements View.OnClickListener, View.OnLongClickListener {
private static final int[] buttons = { R.id.main_left, R.id.main_right, R.id.main_mid };
private TraditionalT9 parent;
private View mainview;
public InterfaceHandler(View mainview, TraditionalT9 iparent) {
this.parent = iparent;
changeView(mainview);
}
protected View getMainview() {
return mainview;
}
protected void changeView(View v) {
this.mainview = v;
View button;
for (int buttid : buttons) {
button = v.findViewById(buttid);
button.setOnClickListener(this);
if (!parent.mAddingWord) {
button.setOnLongClickListener(this);
}
}
}
protected void setPressed(int keyCode, boolean pressed) {
int id = 0;
switch (keyCode) {
case KeyEvent.KEYCODE_SOFT_LEFT:
id = R.id.main_left;
break;
case KeyEvent.KEYCODE_SOFT_RIGHT:
id = R.id.main_right;
break;
case KeyEvent.KEYCODE_DPAD_CENTER:
id = R.id.main_mid;
break;
}
if (id != 0) {
((View) mainview.findViewById(id)).setPressed(pressed);
}
}
protected void showNotFound(boolean notfound) {
if (notfound) {
((TextView) mainview.findViewById(R.id.left_hold_upper))
.setText(R.string.main_left_notfound);
((TextView) mainview.findViewById(R.id.left_hold_lower))
.setText(R.string.main_left_insert);
} else {
((TextView) mainview.findViewById(R.id.left_hold_upper))
.setText(R.string.main_left_insert);
((TextView) mainview.findViewById(R.id.left_hold_lower))
.setText(R.string.main_left_addword);
}
}
protected void emulateMiddleButton() {
((Button) mainview.findViewById(R.id.main_mid)).performClick();
}
protected void midButtonUpdate(boolean composing) {
if (composing) {
((TextView) mainview.findViewById(R.id.main_mid)).setText(R.string.main_mid_commit);
} else {
((TextView) mainview.findViewById(R.id.main_mid)).setText(R.string.main_mid);
}
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_left:
if (parent.mAddingWord) {
parent.showSymbolPage();
} else {
if (parent.mWordFound) {
parent.showSymbolPage();
} else {
parent.showAddWord();
}
}
break;
case R.id.main_mid:
parent.handleMidButton();
break;
case R.id.main_right:
parent.nextKeyMode();
break;
}
}
protected void showHold(boolean show) {
ViewSwitcher vs = (ViewSwitcher) mainview.findViewById(R.id.main_left);
if (show) {
vs.setDisplayedChild(1);
} else {
vs.setDisplayedChild(0);
}
}
@Override
public boolean onLongClick(View v) {
switch (v.getId()) {
case R.id.main_left:
parent.showAddWord();
break;
case R.id.main_right:
parent.launchOptions();
break;
default:
return false;
}
return true;
}
protected void hideView() {
mainview.setVisibility(View.GONE);
}
protected void showView() {
mainview.setVisibility(View.VISIBLE);
}
}

View file

@ -0,0 +1,60 @@
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

@ -0,0 +1,132 @@
package io.github.sspanak.tt9;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
public class LangHelper {
protected static final Locale BULGARIAN = new Locale("bg", "BG");
protected static final Locale RUSSIAN = new Locale("ru","RU");
protected static final Locale UKRAINIAN = new Locale("uk","UA");
public enum LANGUAGE {
// MAKE SURE THESE MATCH WITH values/const.xml
// (index, id) Where index is index in arrays like LOCALES and MUST increment and MUST be in
// the same order as arrays.xml/pref_lang_values, and id is the identifier used in
// the database and such. id should never change unless database update is done.
// id MUST increment in doubles (as the enabled languages are stored as an integer)
NONE(-1, -1), EN(0,1), RU(1,2), DE(2,4), FR(3,8), IT(4,16), UK(5,32), BG(6, 64);
public final int index;
public final int id;
// lookup map
private static final Map<Integer, LANGUAGE> lookup = new HashMap<Integer, LANGUAGE>();
private static final LANGUAGE[] ids = LANGUAGE.values();
static { for (LANGUAGE l : ids) lookup.put(l.id, l); }
private LANGUAGE(int index, int id) { this.index = index; this.id = id; }
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 int LANG_DEFAULT = LANGUAGE.EN.id;
protected static final int NLANGS = LANGUAGE.lookup.size();
protected static String getString(int lang) {
return LANGUAGE.get(lang).name();
}
protected static int getIndex(LANGUAGE l) {
return l.index;
}
//[LANG][MODE][CAPSMODE] = iconref
// first group en, first line LANG, second line TEXT, last line NUM
protected static final int[][][] ICONMAP = {
{
//English resources
{R.drawable.ime_lang_en_lower, R.drawable.ime_lang_en_single, R.drawable.ime_lang_en_upper},
{R.drawable.ime_lang_latin_lower, R.drawable.ime_lang_latin_single, R.drawable.ime_lang_latin_upper},
{R.drawable.ime_number},
},
{
// Russian resources
{R.drawable.ime_lang_ru_lower, R.drawable.ime_lang_ru_single, R.drawable.ime_lang_ru_upper}, //LANG
{R.drawable.ime_lang_cyrillic_lower, R.drawable.ime_lang_cyrillic_single, R.drawable.ime_lang_cyrillic_upper}, //TEXT
{R.drawable.ime_number}, //NUM
},
{
// German resources
{R.drawable.ime_lang_de_lower, R.drawable.ime_lang_de_single, R.drawable.ime_lang_de_upper}, //LANG
{R.drawable.ime_lang_latin_lower, R.drawable.ime_lang_latin_single, R.drawable.ime_lang_latin_upper}, //TEXT
{R.drawable.ime_number}, //NUM
},
{
// French resources
{R.drawable.ime_lang_fr_lower, R.drawable.ime_lang_fr_single, R.drawable.ime_lang_fr_upper}, //LANG
{R.drawable.ime_lang_latin_lower, R.drawable.ime_lang_latin_single, R.drawable.ime_lang_latin_upper}, //TEXT
{R.drawable.ime_number}, //NUM
},
{
// Italian resources
{R.drawable.ime_lang_it_lower, R.drawable.ime_lang_it_single, R.drawable.ime_lang_it_upper}, //LANG
{R.drawable.ime_lang_latin_lower, R.drawable.ime_lang_latin_single, R.drawable.ime_lang_latin_upper}, //TEXT
{R.drawable.ime_number}, //NUM
},
{
// Ukrainian resources
{R.drawable.ime_lang_uk_lower, R.drawable.ime_lang_uk_single, R.drawable.ime_lang_uk_upper}, //LANG
{R.drawable.ime_lang_cyrillic_lower, R.drawable.ime_lang_cyrillic_single, R.drawable.ime_lang_cyrillic_upper}, //TEXT
{R.drawable.ime_number}, //NUM
},
{
// Bulgarian resources
{R.drawable.ime_lang_bg_lower, R.drawable.ime_lang_bg_single, R.drawable.ime_lang_bg_upper}, //LANG
{R.drawable.ime_lang_cyrillic_lower, R.drawable.ime_lang_cyrillic_single, R.drawable.ime_lang_cyrillic_upper}, //TEXT
{R.drawable.ime_number}, //NUM
},
};
public static LANGUAGE[] buildLangs(int i) {
int num = 0;
//calc size of filtered array
for (LANGUAGE l : LANGUAGE.ids) {
if ((i & l.id) == l.id) {
num++;
}
}
LANGUAGE[] la = new LANGUAGE[num];
int lai = 0;
for (LANGUAGE l : LANGUAGE.ids) {
if ((i & l.id) == l.id) {
la[lai] = l;
lai++;
}
}
return la;
}
public static int shrinkLangs(LANGUAGE[] langs) {
int i = 0;
for (LANGUAGE l : langs)
i = i | l.id;
return i;
}
public static int shrinkLangs(int[] langs) {
int i = 0;
for (int l : langs)
i = i | l;
return i;
}
protected static int findIndex(LANGUAGE[] ia, LANGUAGE target) {
for (int x=0; x<ia.length; x++) {
if (ia[x] == target)
return x;
}
return 0;
}
}

View file

@ -0,0 +1,49 @@
package io.github.sspanak.tt9;
import android.content.Context;
import android.view.View;
public class SmileyDialog extends AbsSymDialog {
private static final String[] symbols = {
// lol wiki http://en.wikipedia.org/wiki/List_of_emoticons
":-)", ":o)", ":]", ":3", ":c)", ":>", "=]", "=)", ":}", ":-D",
"8-D", "X-D", "=-D", "B^D", "<:-)", ">:-[", ":-(", ":-<", ":o(", ":{",
":'-(", ":'-)", ":@", "D:<", "D8", "v.v","D-':", ">:O", ":-O", "o_0",
":*", ";-)", ";-D", ">:-P", ":-P", "X-P", "=p", ">:-/", ":-/", ":-.",
":S", ">.<", ":-|", ":$", ":-X", ":-#", ":-%", ":С", ":-E", ":-*",
"0:-3", "0:-)", ">;-)", ">:-)", ">_>", "*<|:-)", "\\o/", "<3", "</3", "=-3", };
private static final int MAX_PAGE = (int) Math.ceil(symbols.length / 10.0);
public SmileyDialog(Context c, View mv) {
super(c, mv);
}
@Override
String[] getContentDescription() {
return context.getResources().getStringArray(R.array.smileyContentDescription);
}
@Override
protected String getSymbol(int index) {
return symbols[index];
}
@Override
protected String getTitleText() {
return context.getString(R.string.smiley_insert);
}
@Override
protected int getSymbolSize() {
return symbols.length;
}
@Override
protected int getMaxPage() {
return MAX_PAGE;
}
}

View file

@ -0,0 +1,42 @@
package io.github.sspanak.tt9;
import android.content.Context;
import android.view.View;
public class SymbolDialog extends AbsSymDialog {
private static final char[] symbols = {
'.', ',', '!', '?', '$', '&', '%', '#', '@', '"', '\'', ':', ';', '(', ')', '/', '\\',
'-', '+', '=', '*', '<', '>', '[', ']', '{', '}', '^', '|', '_', '~', '`' }; // 32
private static final int MAX_PAGE = (int) Math.ceil(symbols.length / 10.0);
public SymbolDialog(Context c, View mv) {
super(c, mv);
}
@Override
String[] getContentDescription() {
return null;
}
@Override
protected String getSymbol(int index) {
return String.valueOf(symbols[index]);
}
@Override
protected String getTitleText() {
return context.getString(R.string.symbol_insert);
}
@Override
protected int getSymbolSize() {
return symbols.length;
}
@Override
protected int getMaxPage() {
return MAX_PAGE;
}
}

View file

@ -0,0 +1,561 @@
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),
LAST_LANG("set_last_lang", 1, 5),
LAST_WORD("set_last_word", null, 6),
SPACE_ZERO("pref_spaceOnZero", 0, 4),
KEY_REMAP("pref_keyMap", 0, 3);
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, " +
DBSettings.SETTING.LAST_LANG.id + " INTEGER, " +
DBSettings.SETTING.KEY_REMAP.id + " INTEGER, " +
DBSettings.SETTING.SPACE_ZERO.id + " INTEGER, " +
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.");
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,962 @@
package io.github.sspanak.tt9;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.ListActivity;
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;
import android.view.View;
import android.widget.ListAdapter;
import android.widget.ListView;
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.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 {
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;
Context mContext = null;
public class LoadException extends Exception {
private static final long serialVersionUID = 3323913652550046354L;
public LoadException() {
super();
}
}
private class Reply {
public boolean status;
private List<String> msgs;
protected Reply() {
this.status = true;
this.msgs = new ArrayList<String>(4);
}
protected void addMsg(String msg) throws LoadException {
msgs.add(msg);
if (msgs.size() > 6) {
msgs.add("Too many errors, bailing.");
throw new LoadException();
}
}
protected void forceMsg(String msg) {
msgs.add(msg);
}
}
private void finishAndShowError(ProgressDialog pd, Reply result, int title){
if (pd != null) {
// Log.d("onPostExecute", "pd");
if (pd.isShowing()) {
pd.dismiss();
}
}
if (result == null) {
// bad thing happened
Log.e("onPostExecute", "Bad things happen?");
} else {
String msg = TextUtils.join("\n", result.msgs);
Log.d("onPostExecute", "Result: " + result.status + " " + msg);
if (!result.status) {
showErrorDialog(getResources().getString(title), msg);
}
}
}
private static void closeStream(Closeable is, Reply reply) {
if (is == null) {
return;
}
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
reply.forceMsg("Couldn't close stream: " + e.getMessage());
}
}
private class LoadDictTask extends AsyncTask<String, Integer, Reply> {
/**
* The system calls this to perform work in a worker thread and delivers
* it the parameters given to AsyncTask.execute()
*/
ProgressDialog pd;
long size;
long pos;
boolean internal;
boolean restore;
String[] dicts;
LANGUAGE[] mSupportedLanguages;
LoadDictTask(int msgid, boolean intern, boolean restorebackup, LANGUAGE[] supportedLanguages) {
internal = intern;
restore = restorebackup;
int suplanglen = supportedLanguages.length;
dicts = new String[suplanglen];
for (int x=0; x<suplanglen; x++) {
if (intern) {
dicts[x] = String.format(dictname, supportedLanguages[x].name().toLowerCase(Locale.ENGLISH));
} else {
dicts[x] = String.format(userdictname, supportedLanguages[x].name().toLowerCase(Locale.ENGLISH));
}
}
mSupportedLanguages = supportedLanguages;
pd = new ProgressDialog(TraditionalT9Settings.this);
pd.setMessage(getResources().getString(msgid));
pd.setOnCancelListener(TraditionalT9Settings.this);
}
private long getDictSizes(boolean internal, boolean restore, String[] dicts) {
if (internal) {
InputStream input;
Properties props = new Properties();
try {
input = getAssets().open("dict.properties");
props.load(input);
long total = 0;
for (String dict : dicts) {
total += Long.parseLong(props.getProperty("size." + dict));
}
return total;
} catch (IOException e) {
Log.e("getDictSizes", "Unable to get dict sizes");
e.printStackTrace();
return -1;
} catch (NumberFormatException e) {
Log.e("getDictSizes", "Unable to parse sizes");
return -1;
}
} 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();
} else {
return -1;
}
} 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;
}
}
}
@Override protected void onPreExecute() {
size = getDictSizes(internal, restore, dicts);
pos = 0;
if ( size >= 0 ) {
pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
pd.setMax(10000);
} else {
pd.setProgressStyle(ProgressDialog.STYLE_SPINNER);
}
pd.show();
}
@Override
protected Reply doInBackground(String... mode) {
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;
}
db.setLockingEnabled(false);
long startnow, endnow;
startnow = SystemClock.uptimeMillis();
// add characters first, then dictionary:
Log.d("doInBackground", "Adding characters...");
// load characters from supported langs
for (LANGUAGE lang : mSupportedLanguages) {
processChars(db, lang);
}
Log.d("doInBackground", "done.");
Log.d("doInBackground", "Adding dict(s)...");
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.
}
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
closeStream(dictstream, reply);
}
endnow = SystemClock.uptimeMillis();
Log.d("TIMING", "Execution time: " + (endnow - startnow) + " ms");
return reply;
}
private void processChars(SQLiteDatabase db, LANGUAGE lang) {
InsertHelper wordhelp = new InsertHelper(db, T9DB.WORD_TABLE_NAME);
final int wordColumn = wordhelp.getColumnIndex(T9DB.COLUMN_WORD);
final int langColumn = wordhelp.getColumnIndex(T9DB.COLUMN_LANG);
final int freqColumn = wordhelp.getColumnIndex(T9DB.COLUMN_FREQUENCY);
final int seqColumn = wordhelp.getColumnIndex(T9DB.COLUMN_SEQ);
try {
// load CHARTABLE and then load T9table, just to cover all bases.
for (Map.Entry<Character, Integer> entry : CharMap.CHARTABLE.get(lang.index).entrySet()) {
wordhelp.prepareForReplace();
wordhelp.bind(langColumn, lang.id);
wordhelp.bind(seqColumn, Integer.toString(entry.getValue()));
wordhelp.bind(wordColumn, Character.toString(entry.getKey()));
wordhelp.bind(freqColumn, 0);
wordhelp.execute();
// upper case
wordhelp.prepareForReplace();
wordhelp.bind(langColumn, lang.id);
wordhelp.bind(seqColumn, Integer.toString(entry.getValue()));
wordhelp.bind(wordColumn, Character.toString(Character.toUpperCase(entry.getKey())));
wordhelp.bind(freqColumn, 0);
wordhelp.execute();
}
char[][] chartable = CharMap.T9TABLE[lang.index];
for (int numkey = 0; numkey < chartable.length; numkey++) {
char[] chars = chartable[numkey];
for (int charindex = 0; charindex < chars.length; charindex++) {
wordhelp.prepareForReplace();
wordhelp.bind(langColumn, lang.id);
wordhelp.bind(seqColumn, Integer.toString(numkey));
wordhelp.bind(wordColumn, Character.toString(chars[charindex]));
wordhelp.bind(freqColumn, 0);
wordhelp.execute();
}
}
} finally {
wordhelp.close();
}
}
private String getLine(BufferedReader br, Reply rpl, String fname) throws LoadException {
try {
return br.readLine();
} catch (IOException e) {
e.printStackTrace();
rpl.status = false;
rpl.addMsg("IO Error ("+fname+"): " + e.getMessage());
}
return null;
}
private Reply processFile(InputStream is, Reply rpl, SQLiteDatabase db, LANGUAGE lang, String fname)
throws LoadException, IOException {
long last = 0;
UnicodeBOMInputStream ubis = new UnicodeBOMInputStream(is);
BufferedReader br = new BufferedReader(new InputStreamReader(ubis));
ubis.skipBOM();
InsertHelper wordhelp = new InsertHelper(db, T9DB.WORD_TABLE_NAME);
final int langColumn = wordhelp.getColumnIndex(T9DB.COLUMN_LANG);
final int wordColumn = wordhelp.getColumnIndex(T9DB.COLUMN_WORD);
final int freqColumn = wordhelp.getColumnIndex(T9DB.COLUMN_FREQUENCY);
final int seqColumn = wordhelp.getColumnIndex(T9DB.COLUMN_SEQ);
String[] ws;
int freq;
String seq;
int linecount = 1;
int wordlen;
String word = getLine(br, rpl, fname);
db.beginTransaction();
try {
while (word != null) {
if (isCancelled()) {
rpl.status = false;
rpl.addMsg("User cancelled.");
break;
}
if (word.contains(" ")) {
ws = word.split(" ");
word = ws[0];
try {
freq = Integer.parseInt(ws[1]);
} catch (NumberFormatException e) {
rpl.status = false;
rpl.addMsg("Number error ("+fname+") at line " + linecount+". Using 0 for frequency.");
freq = 0;
}
if (lang == LANGUAGE.NONE && ws.length == 3) {
try {
lang = LANGUAGE.get(Integer.parseInt(ws[2]));
} catch (NumberFormatException e) {
rpl.status = false;
rpl.addMsg("Number error ("+fname+") at line " + linecount+". Using 1 (en) for language.");
lang = LANGUAGE.EN;
}
if (lang == null) {
rpl.status = false;
rpl.addMsg("Unsupported language ("+fname+") at line " + linecount+". Trying 1 (en) for language.");
lang = LANGUAGE.EN;
}
} else if (lang == LANGUAGE.NONE) {
lang = LANGUAGE.EN;
}
} else {
freq = 0;
}
try {
wordlen = word.getBytes("UTF-8").length;
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
rpl.status = false;
rpl.addMsg("Encoding Error("+fname+") line "+linecount+": " + e.getMessage());
wordlen = word.length();
}
pos += wordlen;
// replace junk characters:
word = word.replace("\uFEFF", "");
try {
seq = CharMap.getStringSequence(word, lang);
} catch (NullPointerException e) {
rpl.status = false;
rpl.addMsg("Error on word ("+word+") line "+
linecount+" in (" + fname+"): "+
getResources().getString(R.string.add_word_badchar, lang.name(), word));
break;
}
linecount++;
wordhelp.prepareForReplace();
wordhelp.bind(seqColumn, seq);
wordhelp.bind(langColumn, lang.id);
wordhelp.bind(wordColumn, word);
wordhelp.bind(freqColumn, freq);
wordhelp.execute();
// System.out.println("Progress: " + pos + " Last: " + last
// + " fsize: " + fsize);
if ((pos - last) > 4096) {
// Log.d("doInBackground", "line: " + linecount);
// Log.d("doInBackground", "word: " + word);
if (size >= 0) { publishProgress((int) ((float) pos / size * 10000)); }
last = pos;
}
word = getLine(br, rpl, fname);
}
publishProgress((int) ((float) pos / size * 10000));
db.setTransactionSuccessful();
} finally {
db.setLockingEnabled(true);
db.endTransaction();
br.close();
is.close();
ubis.close();
is.close();
wordhelp.close();
}
return rpl;
}
@Override
protected void onProgressUpdate(Integer... progress) {
if (pd.isShowing()) {
pd.setProgress(progress[0]);
}
}
@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);
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// maybe need this?
// 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
{SETTING.INPUT_MODE, SETTING.LANG_SUPPORT, SETTING.MODE_NOTIFY, SETTING.KEY_REMAP, SETTING.SPACE_ZERO});
ListAdapter settingitems;
try {
settingitems = new SettingAdapter(this, CustomInflater.inflate(this, R.xml.prefs, settings));
} catch (Exception e) {
e.printStackTrace();
return;
}
setContentView(R.layout.preference_list_content);
setListAdapter(settingitems);
mContext = this;
}
@Override
protected void onListItemClick(ListView l, View v, int position, long id) {
Setting s = (Setting)getListView().getItemAtPosition(position);
if (s.id.equals("help"))
openHelp();
else if (s.id.equals("loaddict"))
preloader(R.string.pref_loadingdict, true, false);
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();
}
}
else
s.clicked(mContext);
}
private void openHelp() {
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(getString(R.string.help_url)));
startActivity(i);
}
// LoadDictTask(int msgid, boolean intern, boolean restorebackup, CheckBoxPreference setting)
private void preloader(int msgid, boolean internal, boolean restorebackup) {
task = new LoadDictTask(msgid, internal, restorebackup,
LangHelper.buildLangs(T9DB.getInstance(mContext).getSettingInt(SETTING.LANG_SUPPORT)));
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);
}
private void showErrorDialog(AlertDialog.Builder builder, CharSequence title, CharSequence msg) {
builder.setMessage(msg).setTitle(title)
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
dialog.show();
}
private void showErrorDialogID(AlertDialog.Builder builder, int titleid, int msgid) {
builder.setMessage(msgid).setTitle(titleid)
.setNeutralButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
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) {
task.cancel(false);
}
}

View file

@ -0,0 +1,77 @@
package io.github.sspanak.tt9;
import android.text.InputType;
import android.util.Log;
class Utils {
interface SpecialInputType extends InputType {
public static final int TYPE_SHARP_007H_PHONE_BOOK = 65633;
}
@SuppressWarnings("unused")
public static void printFlags(int inputType) {
if ((inputType & InputType.TYPE_CLASS_DATETIME) == InputType.TYPE_CLASS_DATETIME)
Log.i("Utils.printFlags", "TYPE_CLASS_DATETIME");
if ((inputType & InputType.TYPE_CLASS_NUMBER) == InputType.TYPE_CLASS_NUMBER)
Log.i("Utils.printFlags", "TYPE_CLASS_NUMBER");
if ((inputType & InputType.TYPE_CLASS_PHONE) == InputType.TYPE_CLASS_PHONE)
Log.i("Utils.printFlags", "TYPE_CLASS_PHONE");
if ((inputType & InputType.TYPE_CLASS_TEXT) == InputType.TYPE_CLASS_TEXT)
Log.i("Utils.printFlags", "TYPE_CLASS_TEXT");
if ((inputType & InputType.TYPE_DATETIME_VARIATION_DATE) == InputType.TYPE_DATETIME_VARIATION_DATE)
Log.i("Utils.printFlags", "TYPE_DATETIME_VARIATION_DATE");
if ((inputType & InputType.TYPE_DATETIME_VARIATION_NORMAL) == InputType.TYPE_DATETIME_VARIATION_NORMAL)
Log.i("Utils.printFlags", "TYPE_DATETIME_VARIATION_NORMAL");
if ((inputType & InputType.TYPE_DATETIME_VARIATION_TIME) == InputType.TYPE_DATETIME_VARIATION_TIME)
Log.i("Utils.printFlags", "YPE_DATETIME_VARIATION_TIME");
if ((inputType & InputType.TYPE_NULL) == InputType.TYPE_NULL)
Log.i("Utils.printFlags", "TYPE_NULL");
if ((inputType & InputType.TYPE_NUMBER_FLAG_DECIMAL) == InputType.TYPE_NUMBER_FLAG_DECIMAL)
Log.i("Utils.printFlags", "TYPE_NUMBER_FLAG_DECIMAL");
if ((inputType & InputType.TYPE_NUMBER_FLAG_SIGNED) == InputType.TYPE_NUMBER_FLAG_SIGNED)
Log.i("Utils.printFlags", "TYPE_NUMBER_FLAG_SIGNED");
if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE) == InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_AUTO_COMPLETE");
if ((inputType & InputType.TYPE_TEXT_FLAG_AUTO_CORRECT) == InputType.TYPE_TEXT_FLAG_AUTO_CORRECT)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_AUTO_CORRECT");
if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS) == InputType.TYPE_TEXT_FLAG_CAP_CHARACTERS)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_CAP_CHARACTERS");
if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_SENTENCES) == InputType.TYPE_TEXT_FLAG_CAP_SENTENCES)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_CAP_SENTENCES");
if ((inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) == InputType.TYPE_TEXT_FLAG_CAP_WORDS)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_CAP_WORDS");
if ((inputType & InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE) == InputType.TYPE_TEXT_FLAG_IME_MULTI_LINE)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_IME_MULTI_LINE");
if ((inputType & InputType.TYPE_TEXT_FLAG_MULTI_LINE) == InputType.TYPE_TEXT_FLAG_MULTI_LINE)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_MULTI_LINE");
if ((inputType & InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS) == InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS)
Log.i("Utils.printFlags", "TYPE_TEXT_FLAG_NO_SUGGESTIONS");
if ((inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS) == InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_EMAIL_ADDRESS");
if ((inputType & InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT) == InputType.TYPE_TEXT_VARIATION_EMAIL_SUBJECT)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_EMAIL_SUBJECT");
if ((inputType & InputType.TYPE_TEXT_VARIATION_FILTER) == InputType.TYPE_TEXT_VARIATION_FILTER)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_FILTER");
if ((inputType & InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE) == InputType.TYPE_TEXT_VARIATION_LONG_MESSAGE)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_LONG_MESSAGE");
if ((inputType & InputType.TYPE_TEXT_VARIATION_NORMAL) == InputType.TYPE_TEXT_VARIATION_NORMAL)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_NORMAL");
if ((inputType & InputType.TYPE_TEXT_VARIATION_PASSWORD) == InputType.TYPE_TEXT_VARIATION_PASSWORD)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_PASSWORD");
if ((inputType & InputType.TYPE_TEXT_VARIATION_PERSON_NAME) == InputType.TYPE_TEXT_VARIATION_PERSON_NAME)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_PERSON_NAME");
if ((inputType & InputType.TYPE_TEXT_VARIATION_PHONETIC) == InputType.TYPE_TEXT_VARIATION_PHONETIC)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_PHONETIC");
if ((inputType & InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS) == InputType.TYPE_TEXT_VARIATION_POSTAL_ADDRESS)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_POSTAL_ADDRESS");
if ((inputType & InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_SHORT_MESSAGE");
if ((inputType & InputType.TYPE_TEXT_VARIATION_URI) == InputType.TYPE_TEXT_VARIATION_URI)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_URI");
if ((inputType & InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD) == InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_VISIBLE_PASSWORD");
if ((inputType & InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT) == InputType.TYPE_TEXT_VARIATION_WEB_EDIT_TEXT)
Log.i("Utils.printFlags", "TYPE_TEXT_VARIATION_WEB_EDIT_TEXT");
}
}

View file

@ -0,0 +1,39 @@
package io.github.sspanak.tt9.settings;
// http://stackoverflow.com/a/8488691
import android.content.Context;
import android.content.res.XmlResourceParser;
import android.util.AttributeSet;
import org.xmlpull.v1.XmlPullParser;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
public class CustomInflater {
public static ArrayList<Setting> inflate(Context context, int xmlFileResId, Object[] isettings)
throws Exception {
ArrayList<Setting> settings = new ArrayList<Setting>();
XmlResourceParser parser = context.getResources().getXml(xmlFileResId);
int token;
while ((token = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (token == XmlPullParser.START_TAG) {
if (!parser.getName().equals("Settings")) {
//prepend package
Class aClass = Class.forName("io.github.sspanak.tt9.settings."+parser.getName());
Class<?>[] params = new Class[]{Context.class, AttributeSet.class, isettings.getClass()};
Constructor<?> constructor = aClass.getConstructor(params);
try {
settings.add((Setting) constructor.newInstance(context, parser, isettings));
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
}
return settings;
}
}

View file

@ -0,0 +1,42 @@
package io.github.sspanak.tt9.settings;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import io.github.sspanak.tt9.R;
public class Setting {
String title;
String summary = null;
public String id;
public int widgetID = 0;
public int layout;
protected View view;
public Setting (Context context, AttributeSet attrs, Object[] isettings) {
// http://stackoverflow.com/a/8488691
for (int i = 0; i < attrs.getAttributeCount(); i++) {
String attr = attrs.getAttributeName(i);
if ("title".equals(attr)) {
// load string resource
title = context.getString(attrs.getAttributeResourceValue(i, 0));
} else if ("summary".equals(attr)) {
summary = context.getString(attrs.getAttributeResourceValue(i, 0));
} else if ("id".equals(attr)){
id = attrs.getAttributeValue(i);
}
}
if (summary == null)
layout = R.layout.setting;
else
layout = R.layout.setting_sum;
}
public void clicked(final Context context) {}
public void setView(View view) {
this.view = view;
}
public void init() {};
}

View file

@ -0,0 +1,54 @@
package io.github.sspanak.tt9.settings;
// https://github.com/codepath/android_guides/wiki/Using-an-ArrayAdapter-with-ListView
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import io.github.sspanak.tt9.R;
import java.util.ArrayList;
public class SettingAdapter extends ArrayAdapter<Setting> {
public SettingAdapter(Context context, ArrayList<Setting> settings) {
super(context, 0, settings);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get the data item for this position
Setting setting = getItem(position);
final LayoutInflater layoutInflater = LayoutInflater.from(getContext());
// Check if an existing view is being reused, otherwise inflate the view
if (convertView == null) {
convertView = layoutInflater.inflate(R.layout.setting_widget, parent, false);
}
setting.setView(convertView);
// Lookup view for data population
((TextView) convertView.findViewById(R.id.title)).setText(setting.title);
View sv = convertView.findViewById(R.id.summary);
if (setting.summary != null && sv != null) {
((TextView) sv).setText(setting.summary);
sv.setVisibility(View.VISIBLE);
}
else if (sv != null) { sv.setVisibility(View.GONE); }
final ViewGroup widgetFrame = (ViewGroup) convertView.findViewById(R.id.widget_frame);
if (setting.widgetID != 0) {
widgetFrame.removeAllViews();
layoutInflater.inflate(setting.widgetID, widgetFrame);
widgetFrame.setVisibility(View.VISIBLE);
}
else {
// hide the widget area
widgetFrame.setVisibility(View.GONE);
}
setting.init();
// Return the completed view to render on screen
return convertView;
}
}

View file

@ -0,0 +1,49 @@
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

@ -0,0 +1,66 @@
package io.github.sspanak.tt9.settings;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
import io.github.sspanak.tt9.R;
import io.github.sspanak.tt9.T9DB;
import io.github.sspanak.tt9.T9DB.DBSettings.SETTING;
public class SettingList extends Setting {
String[] entries;
int[] entryValues;
int defaultValue;
int value;
public SettingList (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.getAttributeIntValue(i, -1);
} else if ("entryValues".equals(attr)) {
// load string resource
entryValues = context.getResources().getIntArray(attrs.getAttributeResourceValue(i, 0));
} else if ("entries".equals(attr)) {
entries = context.getResources().getStringArray(attrs.getAttributeResourceValue(i, 0));
}
}
if (id.equals("pref_inputmode")){
if (isettings[0] != null)
value = (Integer)isettings[0];
else
value = defaultValue;
}
widgetID = R.layout.preference_dialog;
layout = R.layout.setting_widget;
}
public void clicked(final Context context) {
AlertDialog.Builder builderSingle = new AlertDialog.Builder(context);
builderSingle.setTitle(title);
builderSingle.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builderSingle.setSingleChoiceItems(entries, value,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
T9DB.getInstance(context).storeSettingInt(SETTING.get(id), entryValues[which]);
value = entryValues[which];
dialog.dismiss();
}
});
builderSingle.show();
}
}

View file

@ -0,0 +1,84 @@
package io.github.sspanak.tt9.settings;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.util.AttributeSet;
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;
public class SettingMultiList extends SettingList {
boolean[] selectedEntries = new boolean[0];
public SettingMultiList (Context context, AttributeSet attrs, Object[] isettings) {
super(context, attrs, isettings);
selectedEntries = new boolean[entries.length];
for (LangHelper.LANGUAGE l : LangHelper.buildLangs((Integer)isettings[1])) {
selectedEntries[l.index] = true;
}
summary = buildItems();
}
public void clicked(final Context context) {
AlertDialog.Builder builderMulti = new AlertDialog.Builder(context);
builderMulti.setTitle(title);
builderMulti.setNegativeButton(android.R.string.cancel,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builderMulti.setPositiveButton(android.R.string.ok,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
T9DB.getInstance(context).storeSettingInt(SETTING.get(id), LangHelper.shrinkLangs(buildSelection()));
summary = buildItems();
dialog.dismiss();
((TextView)view.findViewById(R.id.summary)).setText(summary);
}
});
builderMulti.setMultiChoiceItems(entries, selectedEntries,
new DialogInterface.OnMultiChoiceClickListener() {
@Override
public void onClick(DialogInterface dialog, int which, boolean opt) {
selectedEntries[which] = opt;
}
});
builderMulti.show();
}
private int[] buildSelection(){
int count = 0;
for (boolean b: selectedEntries) {if (b) count++;}
int[] selection = new int[count];
count = 0;
for (int x=0;x<selectedEntries.length;x++) {
if (selectedEntries[x]) {
selection[count] = entryValues[x];
count++;
}
}
if (selection.length < 1)
return new int[] {entryValues[0]};
return selection;
}
private String buildItems() {
StringBuilder sb = new StringBuilder();
for (int x=0;x<selectedEntries.length;x++) {
if (selectedEntries[x]) {
sb.append(entries[x]);
sb.append((", "));
}
}
if (sb.length() > 1)
sb.setLength(sb.length()-2);
return sb.toString();
}
}