1
0
Fork 0

Big changes: Multilingual, dbupdating, bugfixes:

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

View file

@ -26,9 +26,10 @@
android:resource="@xml/method" />
</service>
<service android:name=".DBUpdateService" />
<activity
android:name="org.nyanya.android.traditionalt9.TraditionalT9Settings"
android:label="@string/traditionalt9_settings" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
@ -37,7 +38,8 @@
<activity
android:theme="@android:style/Theme.Dialog"
android:name="org.nyanya.android.traditionalt9.AddWordAct"
android:label="@string/title_activity_add_word" >
android:label="@string/title_activity_add_word"
android:excludeFromRecents="true" >
</activity>
</application>

View file

@ -1,4 +1,4 @@
радость
радость
ожидать
плакать
желание

View file

@ -3,11 +3,16 @@ buildscript {
mavenCentral()
}
dependencies {
classpath 'com.android.tools.build:gradle:0.6.+'
classpath 'com.android.tools.build:gradle:0.7.+'
}
}
apply plugin: 'android'
ext {
keyStorePass = ''
keyPass = ''
}
dependencies {
compile fileTree(dir: 'libs', include: '*.jar')
}
@ -38,5 +43,57 @@ android {
// by a similar customization.
debug.setRoot('build-types/debug')
release.setRoot('build-types/release')
}
// http://stackoverflow.com/a/19130098
signingConfigs {
release {
storeFile file(System.getenv("KEYSTORE"))
storePassword project.ext.keyStorePass
keyAlias System.getenv("KEYALIAS")
keyPassword project.ext.keyPass
}
}
buildTypes {
release {
signingConfig android.signingConfigs.release
}
}
}
task getDictSizes {
inputs.files 'assets/en-utf8.txt', 'assets/ru-utf8.txt'
outputs.file "assets/dict.properties"
doLast {
ant.echo("Deleting old file...")
delete 'assets/dict.properties'
ant.echo("Calculating dict size...")
FileCollection dicts = files("assets/en-utf8.txt", "assets/ru-utf8.txt")
dicts.each {File file ->
ant.propertyfile(file:"assets/dict.properties") {
entry(key: "size."+ file.name, value: file.length())
}
}
}
}
task readPasswordFromInput << {
android.signingConfigs.release.storePassword = String.valueOf(System.console().readPassword("\nKeyStore Password: "))
android.signingConfigs.release.keyPassword = String.valueOf(System.console().readPassword("\nKey Password: "))
}
//http://stackoverflow.com/a/17484331
tasks.whenTaskAdded { task ->
if (task.name == 'packageRelease') {
task.dependsOn readPasswordFromInput
}
}
preBuild.dependsOn getDictSizes
preBuild.mustRunAfter getDictSizes

View file

@ -1,6 +1,6 @@
#Wed Apr 10 15:27:10 PDT 2013
#Mon Jan 13 17:37:00 EST 2014
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.8-bin.zip
distributionUrl=http\://services.gradle.org/distributions/gradle-1.9-all.zip

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- Gradient Bg for bootan -->
<!-- Gradient Bg for button -->
<gradient
android:startColor="#181C18"
android:endColor="#6B6D6B"

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<!-- Gradient Bg for bootan -->
<!-- Gradient Bg for button -->
<gradient
android:startColor="#8C8E8C"
android:endColor="#636163"

BIN
res/drawable/holdicon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 842 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 749 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

BIN
res/drawable/ime_number.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 824 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 831 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 752 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 929 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 828 B

BIN
res/drawable/key_eight.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4 KiB

BIN
res/drawable/key_five.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
res/drawable/key_four.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
res/drawable/key_nine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

BIN
res/drawable/key_one.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
res/drawable/key_pound.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
res/drawable/key_seven.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.1 KiB

BIN
res/drawable/key_six.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

BIN
res/drawable/key_star.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

BIN
res/drawable/key_three.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
res/drawable/key_two.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
res/drawable/key_zero.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

BIN
res/drawable/rcycle.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

61
res/values-ru/strings.xml Normal file
View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">Traditional T9</string>
<string name="ime_name">Клавиатура T9</string>
<string name="ime_english">T9</string>
<string name="ime_number">Цифры</string>
<string name="pref_inputmode">Режим ввода по умолчанию</string>
<string name="pref_inputmode_desc">Режим ввода по умолчанию</string>
<string name="traditionalt9_settings">Traditional T9 настройки</string>
<string name="main_left_insert">вставить символ</string>
<string name="main_left_addword">Добавить слово</string>
<string name="main_mid">Готово</string>
<string name="main_mid_commit">Commit</string>
<string name="main_right_upper">Режим ввода</string>
<string name="main_right_lower">Изменить IME</string>
<string name="main_left_notfound">Добавить слово?</string>
<string name="ricon_desc">Hold Icon</string>
<string name="symbol_next">Следущая страница</string>
<string name="symbol_prev">Предыдущая страница</string>
<string name="add_word">Добавить слово</string>
<string name="ok">OK</string>
<string name="add_word_blank">Невозможно добавить слово.</string>
<string name="add_word_badchar">Невозможно добавить слово с таким символом %1$s.</string>
<string name="add_word_exist1">Слово (%1$s) уже есть в словаре.</string>
<string name="add_word_exist2">Слово (%1$s) уже есть в словаре %2$s.</string>
<string name="cancel">Отмена</string>
<string name="title_activity_add_word">Добавить слово</string>
<string name="action_settings">Настройки</string>
<string name="pref_russiansupport">Включить поддержку Русского языка</string>
<string name="pref_loaddict">Загрузить словарь</string>
<string name="pref_loaduserdict">Загрузить свой словарь</string>
<string name="pref_loaduserdictdesc">SDcard/traditionalt9/user.lang.dict (lang: en/ru)</string>
<string name="pref_nukedict">Nuke dictionary</string>
<string name="pref_backupdict">Backup dictionary</string>
<string name="pref_restoredict">Restore dictionary</string>
<string name="pref_querytest">Query test</string>
<string name="pref_testfunc">Test func</string>
<string name="pref_loadingdict">Загрузка словаря</string>
<string name="pref_loadinguserdict">Загрузка пользовательского словаря...</string>
<string name="pref_load_title">Загрузить словарь IME</string>
<string name="pref_loadingbackup">Восстановление словаря...</string>
<string name="pref_savingbackup">Сохранение словаря...</string>
<string name="pref_nukingdict">Очистка словаря... Пожалуйста, подождите...</string>
<string name="pref_backup_warn">Предупреждение: Существующая копия базы данных будет перезаписана. Продолжить?</string>
<string name="pref_backup_title">Резервное копирование базы данных IME</string>
<string name="pref_backup_noext">Ошибка: Внешняя память недоступна. Резервное копирование невозможно невозможно.</string>
<string name="pref_restore_warn">При восстановлении существующая база данных будет очищена. Если это нежелательно, то сначала выберите \"%1$s\" перед использованием этой опции.</string>
<string name="pref_restore_title">Восстановить базу данных IME</string>
<string name="pref_restore_noext">Ошибка: Внешняя память недоступна. Восстановление невозможно.</string>
<string name="pref_restore_nofile">Ошибка: Файл встановления не найден.</string>
<string name="pref_nuke_warn">Предупреждение: Будет выполнена очстка словаря. Продолжить?</string>
<string name="pref_nuke_title">Очистить IME словарь</string>
<string name="hello_world">Hello world!</string>
</resources>

View file

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="pref_inputmode_entries">
<item >English</item>
<item >Dictionary</item>
<item >Text</item>
<item >Number</item>
</string-array>
@ -10,4 +10,16 @@
<item >1</item>
<item >2</item>
</string-array>
<string-array name="pref_lang_defaults">
<item >0</item>
</string-array>
<string-array name="pref_lang_titles">
<item >English</item>
<item >Russian</item>
</string-array>
<string-array name="pref_lang_values">
<item >0</item>
<item >1</item>
</string-array>
</resources>

View file

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="help_url">https://github.com/Clam-/TraditionalT9/wiki/Traditional-T9-keypad-IME-for-Android</string>
<string name="app_name">Traditional T9</string>
<string name="ime_name">Traditional T9</string>
<string name="ime_english">English</string>
@ -13,31 +13,50 @@
<string name="main_mid">Done</string>
<string name="main_mid_commit">Commit</string>
<string name="main_right_upper">Cycle Mode</string>
<string name="main_right_lower">Change IME</string>
<string name="main_right_lower">Options</string>
<string name="main_left_notfound">Add word?</string>
<string name="ricon_desc">Hold Icon</string>
<string name="symbol_next">Next Page</string>
<string name="symbol_prev">Prev Page</string>
<string name="add_word">Add word</string>
<string name="ok">OK</string>
<string name="close">Close</string>
<string name="add_word_blank">Blank word not added.</string>
<string name="add_word_badchar">Cannot add word with unmappable symbol.</string>
<string name="add_word_exist1">Word (</string>
<string name="add_word_exist2">) already in DB.</string>
<string name="add_word_badchar">Cannot add word with unmappable symbol for %1$s.</string>
<string name="add_word_exist1">Word (%1$s) already in DB.</string>
<string name="add_word_exist2">Word (%1$s) already in DB for %2$s.</string>
<string name="cancel">Cancel</string>
<string name="title_activity_add_word">Add Word</string>
<string name="action_settings">Settings</string>
<string name="database_notready">Database unavailable.</string>
<string name="no_keyboard_title">Warning: No keypad/keyboard</string>
<string name="no_keyboard">This device does not have a hardware keyboard/keypad, therefore it will not function in any useful way.
Sorry for the inconvenience.</string>
<string name="updating_database_title">Updating dictionary database...</string>
<string name="updating_database">Updating dictionary database, this might take a while.</string>
<string name="updating_database_done">Updating dictionary database complete.</string>
<string name="updating_database_unavailable">Updating dictionary database, word input unavailable at this time.</string>
<string name="pref_lang_title">Multilingual support...</string>
<string name="pref_help">"Show help</string>
<string name="pref_loaddict">Load dictionary</string>
<string name="pref_loaduserdict">Load user dictionary</string>
<string name="pref_loaduserdictdesc">SDcard/traditionalt9/user.lang.dict (lang: en/ru)</string>
<string name="pref_nukedict">Nuke dictionary</string>
<string name="pref_backupdict">Backup dictionary</string>
<string name="pref_restoredict">Restore dictionary</string>
<string name="pref_querytest">Query test</string>
<string name="pref_testfunc">Test func</string>
<string name="pref_loadingdict">Loading dictionary…</string>
<string name="pref_loadinguserdict">Loading user dictionary…</string>
<string name="pref_load_title">Load IME dictionary</string>
<string name="pref_loadingbackup">Restoring dictionary…</string>
<string name="pref_savingbackup">Backing up dictionary…</string>
<string name="pref_nukingdict">Nuking dictionary… Please wait…</string>
<string name="pref_loaduser_notfound">Dictionary for %1$s not found. Not loading.</string>
<string name="pref_backup_warn">Warning: An existing database backup exists. Do you wish to overwrite?</string>
<string name="pref_backup_title">Backup IME database</string>

View file

@ -3,6 +3,7 @@
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android"
android:key="first_preferencescreen">
<Preference android:title="@string/pref_help" android:key="help"/>
<ListPreference
android:key="pref_inputmode"
android:title="@string/pref_inputmode"
@ -10,7 +11,15 @@
android:entries="@array/pref_inputmode_entries"
android:entryValues="@array/pref_inputmode_values"
android:defaultValue="0" android:summary="@string/pref_inputmode_desc"/>
<pl.wavesoftware.widget.MultiSelectListPreference
android:defaultValue="@array/pref_lang_defaults"
android:entries="@array/pref_lang_titles"
android:entryValues="@array/pref_lang_values"
android:key="pref_lang_support"
android:persistent="true"
android:title="@string/pref_lang_title" />
<Preference android:title="@string/pref_loaddict" android:key="loaddict"/>
<Preference android:title="@string/pref_loaduserdict" android:summary="@string/pref_loaduserdictdesc" android:key="loaduserdict"/>
<Preference android:title="@string/pref_nukedict" android:key="nukedict"/>
<Preference android:title="@string/pref_backupdict" android:key="backupdict"/>
<Preference android:title="@string/pref_restoredict" android:key="restoredict"/>

View file

@ -0,0 +1,315 @@
/* ____________________________________________________________________________
*
* File: UnicodeBOMInputStream.java
* Author: Gregory Pakosz.
* Date: 02 - November - 2005
* ____________________________________________________________________________
*/
package com.stackoverflow.answer;
import java.io.IOException;
import java.io.InputStream;
import java.io.PushbackInputStream;
/**
* The <code>UnicodeBOMInputStream</code> class wraps any
* <code>InputStream</code> and detects the presence of any Unicode BOM
* (Byte Order Mark) at its beginning, as defined by
* <a href="http://www.faqs.org/rfcs/rfc3629.html">RFC 3629 - UTF-8, a transformation format of ISO 10646</a>
*
* <p>The
* <a href="http://www.unicode.org/unicode/faq/utf_bom.html">Unicode FAQ</a>
* defines 5 types of BOMs:<ul>
* <li><pre>00 00 FE FF = UTF-32, big-endian</pre></li>
* <li><pre>FF FE 00 00 = UTF-32, little-endian</pre></li>
* <li><pre>FE FF = UTF-16, big-endian</pre></li>
* <li><pre>FF FE = UTF-16, little-endian</pre></li>
* <li><pre>EF BB BF = UTF-8</pre></li>
* </ul></p>
*
* <p>Use the {@link #getBOM()} method to know whether a BOM has been detected
* or not.
* </p>
* <p>Use the {@link #skipBOM()} method to remove the detected BOM from the
* wrapped <code>InputStream</code> object.</p>
*/
public class UnicodeBOMInputStream extends InputStream
{
/**
* Type safe enumeration class that describes the different types of Unicode
* BOMs.
*/
public static final class BOM
{
/**
* NONE.
*/
public static final BOM NONE = new BOM(new byte[]{},"NONE");
/**
* UTF-8 BOM (EF BB BF).
*/
public static final BOM UTF_8 = new BOM(new byte[]{(byte)0xEF,
(byte)0xBB,
(byte)0xBF},
"UTF-8");
/**
* UTF-16, little-endian (FF FE).
*/
public static final BOM UTF_16_LE = new BOM(new byte[]{ (byte)0xFF,
(byte)0xFE},
"UTF-16 little-endian");
/**
* UTF-16, big-endian (FE FF).
*/
public static final BOM UTF_16_BE = new BOM(new byte[]{ (byte)0xFE,
(byte)0xFF},
"UTF-16 big-endian");
/**
* UTF-32, little-endian (FF FE 00 00).
*/
public static final BOM UTF_32_LE = new BOM(new byte[]{ (byte)0xFF,
(byte)0xFE,
(byte)0x00,
(byte)0x00},
"UTF-32 little-endian");
/**
* UTF-32, big-endian (00 00 FE FF).
*/
public static final BOM UTF_32_BE = new BOM(new byte[]{ (byte)0x00,
(byte)0x00,
(byte)0xFE,
(byte)0xFF},
"UTF-32 big-endian");
/**
* Returns a <code>String</code> representation of this <code>BOM</code>
* value.
*/
public final String toString()
{
return description;
}
/**
* Returns the bytes corresponding to this <code>BOM</code> value.
*/
public final byte[] getBytes()
{
final int length = bytes.length;
final byte[] result = new byte[length];
// Make a defensive copy
System.arraycopy(bytes,0,result,0,length);
return result;
}
private BOM(final byte bom[], final String description)
{
assert(bom != null) : "invalid BOM: null is not allowed";
assert(description != null) : "invalid description: null is not allowed";
assert(description.length() != 0) : "invalid description: empty string is not allowed";
this.bytes = bom;
this.description = description;
}
final byte bytes[];
private final String description;
} // BOM
/**
* Constructs a new <code>UnicodeBOMInputStream</code> that wraps the
* specified <code>InputStream</code>.
*
* @param inputStream an <code>InputStream</code>.
*
* @throws NullPointerException when <code>inputStream</code> is
* <code>null</code>.
* @throws IOException on reading from the specified <code>InputStream</code>
* when trying to detect the Unicode BOM.
*/
public UnicodeBOMInputStream(final InputStream inputStream) throws NullPointerException,
IOException
{
if (inputStream == null)
throw new NullPointerException("invalid input stream: null is not allowed");
in = new PushbackInputStream(inputStream,4);
final byte bom[] = new byte[4];
final int read = in.read(bom);
switch(read)
{
case 4:
if ((bom[0] == (byte)0xFF) &&
(bom[1] == (byte)0xFE) &&
(bom[2] == (byte)0x00) &&
(bom[3] == (byte)0x00))
{
this.bom = BOM.UTF_32_LE;
break;
}
else
if ((bom[0] == (byte)0x00) &&
(bom[1] == (byte)0x00) &&
(bom[2] == (byte)0xFE) &&
(bom[3] == (byte)0xFF))
{
this.bom = BOM.UTF_32_BE;
break;
}
case 3:
if ((bom[0] == (byte)0xEF) &&
(bom[1] == (byte)0xBB) &&
(bom[2] == (byte)0xBF))
{
this.bom = BOM.UTF_8;
break;
}
case 2:
if ((bom[0] == (byte)0xFF) &&
(bom[1] == (byte)0xFE))
{
this.bom = BOM.UTF_16_LE;
break;
}
else
if ((bom[0] == (byte)0xFE) &&
(bom[1] == (byte)0xFF))
{
this.bom = BOM.UTF_16_BE;
break;
}
default:
this.bom = BOM.NONE;
break;
}
if (read > 0)
in.unread(bom,0,read);
}
/**
* Returns the <code>BOM</code> that was detected in the wrapped
* <code>InputStream</code> object.
*
* @return a <code>BOM</code> value.
*/
public final BOM getBOM()
{
// BOM type is immutable.
return bom;
}
/**
* Skips the <code>BOM</code> that was found in the wrapped
* <code>InputStream</code> object.
*
* @return this <code>UnicodeBOMInputStream</code>.
*
* @throws IOException when trying to skip the BOM from the wrapped
* <code>InputStream</code> object.
*/
public final synchronized UnicodeBOMInputStream skipBOM() throws IOException
{
if (!skipped)
{
in.skip(bom.bytes.length);
skipped = true;
}
return this;
}
/**
* {@inheritDoc}
*/
public int read() throws IOException
{
return in.read();
}
/**
* {@inheritDoc}
*/
public int read(final byte b[]) throws IOException,
NullPointerException
{
return in.read(b,0,b.length);
}
/**
* {@inheritDoc}
*/
public int read(final byte b[],
final int off,
final int len) throws IOException,
NullPointerException
{
return in.read(b,off,len);
}
/**
* {@inheritDoc}
*/
public long skip(final long n) throws IOException
{
return in.skip(n);
}
/**
* {@inheritDoc}
*/
public int available() throws IOException
{
return in.available();
}
/**
* {@inheritDoc}
*/
public void close() throws IOException
{
in.close();
}
/**
* {@inheritDoc}
*/
public synchronized void mark(final int readlimit)
{
in.mark(readlimit);
}
/**
* {@inheritDoc}
*/
public synchronized void reset() throws IOException
{
in.reset();
}
/**
* {@inheritDoc}
*/
public boolean markSupported()
{
return in.markSupported();
}
private final PushbackInputStream in;
private final BOM bom;
private boolean skipped = false;
} // UnicodeBOMInputStream

View file

@ -2,12 +2,15 @@ package org.nyanya.android.traditionalt9;
import android.app.Dialog;
import android.content.Context;
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 {
@ -279,6 +282,11 @@ public abstract class AbsSymDialog extends Dialog implements
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

@ -1,52 +1,87 @@
package org.nyanya.android.traditionalt9;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.app.Activity;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
public class AddWordAct extends Activity {
View main;
int lang;
SharedPreferences pref;
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);
String word = getIntent().getStringExtra("org.nyanya.android.traditionalt9.word");
Intent i = getIntent();
origword = i.getStringExtra("org.nyanya.android.traditionalt9.word");
lang = i.getIntExtra("org.nyanya.android.traditionalt9.lang", -1);
if (lang == -1) {
Log.e("AddWordAct.onCreate", "lang is invalid. How?");
}
// Log.d("AddWord", "data.get: " + word);
et.setText(word);
et.setSelection(word.length());
et.setText(origword);
et.setSelection(origword.length());
setContentView(v);
main = v;
pref = PreferenceManager.getDefaultSharedPreferences(this);
}
public void addWordButton(View v) {
EditText et = (EditText) main.findViewById(R.id.add_word_text);
// Log.d("AddWordAct", "adding word: " + et.getText());
if (TraditionalT9.ghettoaccess == null) {
Log.e("AddWordAct.addWordbutton", "ghettoaccess is null? Oh no.");
} else {
TraditionalT9.ghettoaccess.doAddWord(et.getText().toString());
}
doAddWord(et.getText().toString());
this.finish();
}
public void doAddWord(String text) {
T9DB db = T9DB.getInstance(this);
try {
db.addWord(text, 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(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
AlertDialog dialog = builder.create();
// Window win = dialog.getWindow();
// WindowManager.LayoutParams lp = win.getAttributes();
// lp.token = getWindow().getWindow().getDecorView().getWindowToken();
// lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
// win.setAttributes(lp);
// win.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.show();
}
SharedPreferences.Editor prefedit = pref.edit();
prefedit.putString("last_word", text);
prefedit.commit();
}
public void cancelButton(View v) {
// Log.d("AddWordAct", "Cancelled...");
// TraditionalT9.ghettoaccess.addCancel();
this.finish();
}
@Override
public void onStop() {
TraditionalT9.ghettoaccess.addCancel();
super.onStop();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.

View file

@ -48,7 +48,6 @@ public class CandidateView extends View {
* Construct a CandidateView for showing suggested words for completion.
*
* @param context
* @param attrs
*/
public CandidateView(Context context) {
super(context);

View file

@ -1,5 +1,6 @@
package org.nyanya.android.traditionalt9;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Locale;
@ -8,73 +9,97 @@ import java.util.Map;
import android.util.Log;
public class CharMap {
protected static final Map<Character, Integer> CHARTABLE;
protected static final ArrayList<Map<Character, Integer>> CHARTABLE = new ArrayList<Map<Character, Integer>>(2);
static {
Map<Character, Integer> aMap = new HashMap<Character, Integer>();
aMap.put('.', 1); aMap.put(',', 1); aMap.put('!', 1); aMap.put('?', 1);
aMap.put('-', 1); aMap.put('"', 1); aMap.put('\'', 1); aMap.put('@', 1);
aMap.put('#', 1); aMap.put('$', 1); aMap.put('%', 1); aMap.put('&', 1);
aMap.put('*', 1); aMap.put('(', 1); aMap.put(')', 1); aMap.put('1', 1);
aMap.put(':', 1); aMap.put(';', 1); aMap.put('/', 1); aMap.put('\\', 1);
aMap.put('+', 1); aMap.put('=', 1); aMap.put('<', 1); aMap.put('>', 1);
aMap.put('[', 1); aMap.put(']', 1); aMap.put('{', 1); aMap.put('}', 1);
aMap.put('^', 1); aMap.put('|', 1); aMap.put('_', 1); aMap.put('~', 1);
aMap.put('`', 1);
aMap.put('a', 2); aMap.put('\u00e1', 2); aMap.put('\u00e4', 2);
aMap.put('\u00e2', 2); aMap.put('\u00e0', 2); aMap.put('\u00e5', 2);
aMap.put('b', 2); aMap.put('c', 2); aMap.put('\u00e7', 2);
aMap.put('2', 2); aMap.put('d', 3); aMap.put('e', 3);
aMap.put('\u00e9', 3); aMap.put('\u00eb', 3); aMap.put('\u00e8', 3);
aMap.put('\u00ea', 3); aMap.put('f', 3); aMap.put('3', 3);
aMap.put('g', 4); aMap.put('h', 4); aMap.put('i', 4);
aMap.put('\u00ed', 4); aMap.put('\u00ef', 4); aMap.put('4', 4);
aMap.put('j', 5); aMap.put('k', 5); aMap.put('l', 5);
aMap.put('5', 5); aMap.put('m', 6); aMap.put('n', 6);
aMap.put('\u00f1', 6); aMap.put('o', 6); aMap.put('\u00f3', 6);
aMap.put('\u00f6', 6); aMap.put('\u00f4', 6); aMap.put('\u00fb', 6);
aMap.put('6', 6); aMap.put('p', 7); aMap.put('q', 7);
aMap.put('r', 7); aMap.put('s', 7); aMap.put('7', 7);
aMap.put('t', 8); aMap.put('u', 8); aMap.put('\u00fc', 8);
aMap.put('v', 8); aMap.put('8', 8); aMap.put('w', 9);
aMap.put('x', 9); aMap.put('y', 9); aMap.put('z', 9);
aMap.put('9', 9); aMap.put('+', 0); aMap.put('0', 0);
CHARTABLE = Collections.unmodifiableMap(aMap);
Map<Character, Integer> enMap = new HashMap<Character, Integer>();
enMap.put('.', 1); enMap.put(',', 1); enMap.put('!', 1); enMap.put('?', 1);
enMap.put('-', 1); enMap.put('"', 1); enMap.put('\'', 1); enMap.put('@', 1);
enMap.put('#', 1); enMap.put('$', 1); enMap.put('%', 1); enMap.put('&', 1);
enMap.put('*', 1); enMap.put('(', 1); enMap.put(')', 1); enMap.put('1', 1);
enMap.put(':', 1); enMap.put(';', 1); enMap.put('/', 1); enMap.put('\\', 1);
enMap.put('+', 1); enMap.put('=', 1); enMap.put('<', 1); enMap.put('>', 1);
enMap.put('[', 1); enMap.put(']', 1); enMap.put('{', 1); enMap.put('}', 1);
enMap.put('^', 1); enMap.put('|', 1); enMap.put('_', 1); enMap.put('~', 1);
enMap.put('`', 1);
enMap.put('a', 2); enMap.put('\u00e1', 2); enMap.put('\u00e4', 2);
enMap.put('\u00e2', 2); enMap.put('\u00e0', 2); enMap.put('\u00e5', 2);
enMap.put('b', 2); enMap.put('c', 2); enMap.put('\u00e7', 2);
enMap.put('2', 2); enMap.put('d', 3); enMap.put('e', 3);
enMap.put('\u00e9', 3); enMap.put('\u00eb', 3); enMap.put('\u00e8', 3);
enMap.put('\u00ea', 3); enMap.put('f', 3); enMap.put('3', 3);
enMap.put('g', 4); enMap.put('h', 4); enMap.put('i', 4);
enMap.put('\u00ed', 4); enMap.put('\u00ef', 4); enMap.put('4', 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('\u00f1', 6); enMap.put('o', 6); enMap.put('\u00f3', 6);
enMap.put('\u00f6', 6); enMap.put('\u00f4', 6); enMap.put('\u00fb', 6);
enMap.put('6', 6); enMap.put('p', 7); enMap.put('q', 7);
enMap.put('r', 7); enMap.put('s', 7); enMap.put('7', 7);
enMap.put('t', 8); enMap.put('u', 8); enMap.put('\u00fc', 8);
enMap.put('v', 8); enMap.put('8', 8); enMap.put('w', 9);
enMap.put('x', 9); enMap.put('y', 9); enMap.put('z', 9);
enMap.put('9', 9); enMap.put('+', 0); enMap.put('0', 0);
CHARTABLE.add(0, Collections.unmodifiableMap(enMap));
Map<Character, Integer> ruMap = new HashMap<Character, Integer>();
ruMap.put('.', 1); ruMap.put(',', 1); ruMap.put('!', 1); ruMap.put('?', 1);
ruMap.put('-', 1); ruMap.put('"', 1); ruMap.put('\'', 1); ruMap.put('@', 1);
ruMap.put('#', 1); ruMap.put('$', 1); ruMap.put('%', 1); ruMap.put('&', 1);
ruMap.put('*', 1); ruMap.put('(', 1); ruMap.put(')', 1); ruMap.put('1', 1);
ruMap.put(':', 1); ruMap.put(';', 1); ruMap.put('/', 1); ruMap.put('\\', 1);
ruMap.put('+', 1); ruMap.put('=', 1); ruMap.put('<', 1); ruMap.put('>', 1);
ruMap.put('[', 1); ruMap.put(']', 1); ruMap.put('{', 1); ruMap.put('}', 1);
ruMap.put('^', 1); ruMap.put('|', 1); ruMap.put('_', 1); ruMap.put('~', 1);
ruMap.put('`', 1); ruMap.put('1', 1);
ruMap.put('а', 2); ruMap.put('б', 2); ruMap.put('в', 2); ruMap.put('г', 2);
ruMap.put('2', 2);
ruMap.put('д', 3); ruMap.put('е', 3); ruMap.put('ё', 3); ruMap.put('ж', 3);
ruMap.put('з', 3); ruMap.put('3', 3);
ruMap.put('и', 4); ruMap.put('й', 4); ruMap.put('к', 4); ruMap.put('л', 4);
ruMap.put('4', 4);
ruMap.put('м', 5); ruMap.put('н', 5); ruMap.put('о', 5); ruMap.put('п', 5);
ruMap.put('5', 5);
ruMap.put('р', 6); ruMap.put('с', 6); ruMap.put('т', 6); ruMap.put('у', 6);
ruMap.put('6', 6);
ruMap.put('ф', 7); ruMap.put('х', 7); ruMap.put('ц', 7); ruMap.put('ч', 7);
ruMap.put('7', 7);
ruMap.put('ш', 8); ruMap.put('щ', 8); ruMap.put('ъ', 8); ruMap.put('ы', 8);
ruMap.put('8', 8);
ruMap.put('ь', 9); ruMap.put('э', 9); ruMap.put('ю', 9); ruMap.put('я', 9);
ruMap.put('9', 9);
ruMap.put('+', 0); ruMap.put('0', 0);
CHARTABLE.add(1, Collections.unmodifiableMap(ruMap));
}
protected static final char[][] T9TABLE = { { '0', '+' },
{ '.', ',', '!', '?', '-', '"', '\'', '@', '#', '$', '%', '&', '*', '(', ')', '1' },
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' } };
protected static final char[][] RUT9TABLE = { { '0', '+' },
{ '.', ',', '?', '!', '"', '\'', '-', '@', '$', '%', '&', '*', '(', ')', '_', '1' },
{ 'а', 'б', 'в', 'г', 'А', 'Б', 'В', 'Г', '2' }, { 'д', 'е', 'ё', 'ж', 'з', 'Д', 'Е', 'Ё', 'Ж', 'З', '3' },
{ 'и', 'й', 'к', 'л', 'И', 'Й', 'К', 'Л', '4' }, { 'м', 'н', 'о', 'п', 'М', 'Н', 'О', 'П', '5' },
{ 'р', 'с', 'т', 'у', 'Р', 'С', 'Т', 'У', '6' }, { 'ф', 'х', 'ц', 'ч', 'Ф', 'Х', 'Ц', 'Ч', '7' },
{ 'ш', 'щ', 'ъ', 'ы', 'Ш', 'Щ', 'Ъ', 'Ы', '8' }, { 'ь', 'э', 'ю', 'я', 'Ь', 'Э', 'Ю', 'Я', '9' },
{ ' ', '\n' } };
protected static final char[][][] T9TABLE = {ENT9TABLE, RUT9TABLE};
protected static final int[] T9CAPSTART = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4, 0 };
protected static final int[] ENT9CAPSTART = { 0, 0, 3, 3, 3, 3, 3, 4, 3, 4, 0 };
protected static final int [] RUT9CAPSTART = {0, 0, 4, 5, 4, 4, 4, 4, 4, 4, 0};
protected static final int[][] T9CAPSTART = {ENT9CAPSTART, RUT9CAPSTART};
protected static int[] getSequence(String word) {
int[] intseq = new int[word.length()];
String tword = word.toLowerCase(Locale.ENGLISH);
for (int i = 0; i < word.length(); i++) {
char c = tword.charAt(i);
Integer z = CharMap.CHARTABLE.get(c);
if (z == null) {
Log.e("getSequence",
"ERROR: " + (int) c + " NOT FOUND (" + Integer.toHexString((int) c) + ")");
throw new NullPointerException();
}
intseq[i] = z;
}
return intseq;
}
protected static String getStringSequence(String word) {
protected static String getStringSequence(String word, int lang) {
StringBuilder seq = new StringBuilder();
String tword = word.toLowerCase(Locale.ENGLISH);
String tword = word.toLowerCase(LangHelper.LOCALES[lang]);
for (int i = 0; i < word.length(); i++) {
char c = tword.charAt(i);
Integer z = CharMap.CHARTABLE.get(c);
Integer z = CharMap.CHARTABLE.get(lang).get(c);
if (z == null) {
Log.e("getStringSequence",
"ERROR: " + (int) c + " NOT FOUND (" + Integer.toHexString((int) c) + ")");
"ERROR: " + (int) c + " NOT FOUND FOR [" + lang + "] (" + Integer.toHexString((int) c) + ") Index: " + i);
throw new NullPointerException();
}
seq.append(z.toString());

View file

@ -0,0 +1,71 @@
package org.nyanya.android.traditionalt9;
import android.app.IntentService;
import android.app.Notification;
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
Notification notification = new Notification(R.drawable.ime_en_lang_lower, getText(R.string.updating_database_title),
System.currentTimeMillis());
Intent notificationIntent = new Intent(this, DBUpdateService.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.updating_database_title),
getText(R.string.updating_database), pendingIntent);
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

@ -126,8 +126,7 @@ public class InterfaceHandler implements View.OnClickListener, View.OnLongClickL
parent.showAddWord();
break;
case R.id.main_right:
((InputMethodManager) parent.getSystemService(Context.INPUT_METHOD_SERVICE))
.showInputMethodPicker();
parent.launchOptions();
break;
default:
return false;

View file

@ -0,0 +1,34 @@
package org.nyanya.android.traditionalt9;
import java.util.Locale;
public class LangHelper {
protected static final Locale RUSSIAN = new Locale("ru","RU");
protected static final int EN = 0;
protected static final int RU = 1;
protected static final Locale[] LOCALES = {Locale.ENGLISH, RUSSIAN};
protected static final String[] LANGS = {"EN", "RU"};
protected static final int NLANGS = LANGS.length;
protected static String getString(int lang) {
return LANGS[lang];
}
//[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_en_lang_lower, R.drawable.ime_en_lang_single, R.drawable.ime_en_lang_upper},
{R.drawable.ime_en_text_lower, R.drawable.ime_en_text_single, R.drawable.ime_en_text_upper},
{R.drawable.ime_number},
},
{
// Russian resources
{R.drawable.ime_ru_lang_lower, R.drawable.ime_ru_lang_single, R.drawable.ime_ru_lang_upper}, //LANG
{R.drawable.ime_ru_text_lower, R.drawable.ime_ru_text_single, R.drawable.ime_ru_text_upper}, //TEXT
{R.drawable.ime_number}, //NUM
}
};
}

View file

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

View file

@ -1,16 +1,13 @@
package org.nyanya.android.traditionalt9;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.nyanya.android.traditionalt9.CandidateView;
import org.nyanya.android.traditionalt9.R;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.KeyboardView;
import android.os.Handler;
@ -20,12 +17,14 @@ import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import android.widget.Toast;
import pl.wavesoftware.widget.MultiSelectListPreference;
public class TraditionalT9 extends InputMethodService implements
KeyboardView.OnKeyboardActionListener {
@ -45,6 +44,8 @@ public class TraditionalT9 extends InputMethodService implements
private static final int EDITING_NOSHOW = 2;
private int mEditing = NON_EDIT;
private boolean mGaveUpdateWarn = false;
private boolean mFirstPress = false;
private boolean mIgnoreDPADKeyUp = false;
@ -59,12 +60,20 @@ public class TraditionalT9 extends InputMethodService implements
private int mPrevious;
private int mCharIndex;
private String mPreviousWord = "";
private int mCapsMode;
private int mLang;
private int mLangIndex;
private int[] mLangsAvailable = null;
private static final int CAPS_OFF = 0;
private static final int CAPS_SINGLE = 1;
private static final int CAPS_ALL = 2;
private final static int[] CAPS_CYCLE = { CAPS_OFF, CAPS_SINGLE, CAPS_ALL };
private final static int T9DELAY = 1200;
final Handler t9releasehandler = new Handler();
Runnable mt9release = new Runnable() {
@Override
@ -75,14 +84,13 @@ public class TraditionalT9 extends InputMethodService implements
private T9DB db;
protected static TraditionalT9 ghettoaccess;
public static final int MODE_EN = 0;
public static final int MODE_LANG = 0;
public static final int MODE_TEXT = 1;
public static final int MODE_NUM = 2;
private static final int[] MODE_CYCLE = { MODE_EN, MODE_TEXT, MODE_NUM };
private static final int[] MODE_CYCLE = { MODE_LANG, MODE_TEXT, MODE_NUM };
private int mKeyMode;
private SharedPreferences pref;
/**
* Main initialization of the input method component. Be sure to call to
* super class.
@ -90,11 +98,12 @@ public class TraditionalT9 extends InputMethodService implements
@Override
public void onCreate() {
super.onCreate();
mPrevious = -1;
mCharIndex = 0;
db = new T9DB(this);
db.init();
db = T9DB.getInstance(this);
pref = PreferenceManager.getDefaultSharedPreferences(this);
buildLangs();
if (interfacehandler == null) {
interfacehandler = new InterfaceHandler(getLayoutInflater().inflate(R.layout.mainview,
@ -102,6 +111,31 @@ public class TraditionalT9 extends InputMethodService implements
}
}
//build and filter Langs
private void buildLangs() {
int[] ia = MultiSelectListPreference.defaultunpack2Int(pref.getString("pref_lang_support", null));
int num = 0;
int i;
//calc size of filtered array
for (int x=0; x<ia.length; x++) {
i = ia[x];
if (i >= 0 && i < LangHelper.NLANGS) {
num++;
}
}
int[] ian = new int[num];
int iansize = 0;
for (int x=0; x<ia.length; x++) {
i = ia[x];
if (i >= 0 && i < LangHelper.NLANGS) {
ian[iansize] = i;
iansize++;
}
}
mLangsAvailable = ian;
}
@Override
public boolean onEvaluateInputViewShown() {
if (mEditing == EDITING_NOSHOW) {
@ -121,7 +155,7 @@ public class TraditionalT9 extends InputMethodService implements
updateKeyMode();
View v = getLayoutInflater().inflate(R.layout.mainview, null);
interfacehandler.changeView(v);
if (mKeyMode == MODE_EN) {
if (mKeyMode == MODE_LANG) {
interfacehandler.showHold(true);
} else {
interfacehandler.showHold(false);
@ -155,47 +189,54 @@ public class TraditionalT9 extends InputMethodService implements
mSmileyPopup.doShow(getWindow().getWindow().getDecorView());
}
private void clearState() {
mSuggestionStrings.clear();
mSuggestionInts.clear();
mSuggestionSym.clear();
mPreviousWord = "";
mComposing.setLength(0);
mComposingI.setLength(0);
mWordFound = true;
}
protected void showAddWord() {
if (mKeyMode == MODE_EN) {
ghettoaccess = this;
if (mKeyMode == MODE_LANG) {
Intent awintent = new Intent(this, AddWordAct.class);
awintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
awintent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
awintent.putExtra("org.nyanya.android.traditionalt9.word", mComposing.toString());
awintent.putExtra("org.nyanya.android.traditionalt9.lang", mLang);
clearState();
InputConnection ic = getCurrentInputConnection();
ic.setComposingText("", 0);
ic.finishComposingText();
updateCandidates();
//onFinishInput();
mWordFound = true;
startActivity(awintent);
}
}
public void doAddWord(String text) {
try {
db.addWord(text);
} catch (DBException e) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage(e.getMessage()).setTitle(R.string.add_word)
.setPositiveButton(R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
// sanitize lang and set index for cycling lang
// Need to check if last lang is available, if not, set index to -1 and set lang to default to 0
private int sanitizeLang(int lang) {
if (mLangsAvailable.length < 1 || lang == -1) {
Log.w("T9.sanitizeLang", "This shouldn't happen.");
return 0;
}
});
AlertDialog dialog = builder.create();
// so many ghettos to display dialogs from IME
Window win = dialog.getWindow();
WindowManager.LayoutParams lp = win.getAttributes();
lp.token = getWindow().getWindow().getDecorView().getWindowToken();
lp.type = WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG;
win.setAttributes(lp);
win.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
dialog.show();
if (lang >= LangHelper.NLANGS) {
Log.w("T9.sanitizeLang", "Previous lang not supported: " + lang + " langs: " + Arrays.toString(LangHelper.LANGS));
return mLangsAvailable[0];
} else {
int index = Arrays.asList(mLangsAvailable).indexOf(lang);
if (index == -1) {
mLangIndex = 0;
return mLangsAvailable[mLangIndex];
} else {
mLangIndex = index;
return lang;
}
}
protected void addCancel() {
interfacehandler.showNotFound(false);
ghettoaccess = null;
}
/**
* This is the main point where we do our initialization of the input method
* to begin operating on an application. At this point we have been bound to
@ -205,8 +246,10 @@ public class TraditionalT9 extends InputMethodService implements
@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
// Log.d("onStartInput", "attribute.inputType: " + attribute.inputType +
// " restarting? " + restarting);
// Log.d("onStartInput", "attribute.inputType: " + attribute.inputType +
// " restarting? " + restarting);
//Utils.printFlags(attribute.inputType);
if (attribute.inputType == 0) {
// don't do anything when not in any kind of edit field.
// should also turn off input screen and stuff
@ -220,13 +263,11 @@ public class TraditionalT9 extends InputMethodService implements
// Reset our state. We want to do this even if restarting, because
// the underlying state of the text editor could have changed in any
// way.
mSuggestionStrings.clear();
mSuggestionInts.clear();
mSuggestionSym.clear();
mComposing.setLength(0);
mComposingI.setLength(0);
clearState();
buildLangs();
mLang = sanitizeLang(pref.getInt("last_lang", 0));
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(this);
updateCandidates();
if (!restarting) {
@ -304,6 +345,11 @@ public class TraditionalT9 extends InputMethodService implements
// keyboard with no special features.
updateShiftKeyState(attribute);
}
// Special case for Softbank Sharp 007SH phone book.
if (attribute.inputType == 65633) {
mKeyMode = MODE_TEXT;
}
String prevword = null;
if (attribute.privateImeOptions != null
&& attribute.privateImeOptions.equals("org.nyanya.android.traditionalt9.addword=true")) {
mAddingWord = true;
@ -313,6 +359,13 @@ public class TraditionalT9 extends InputMethodService implements
} else {
mAddingWord = false;
// Log.d("onStartInput", "not adding word");
prevword = pref.getString("last_word", null);
if (prevword != null) {
onText(prevword);
Editor prefedit = pref.edit();
prefedit.remove("last_word");
prefedit.commit();
}
}
// Update the label on the enter key, depending on what the application
@ -339,6 +392,9 @@ public class TraditionalT9 extends InputMethodService implements
public void onFinishInput() {
super.onFinishInput();
// Log.d("onFinishInput", "When is this called?");
Editor prefedit = pref.edit();
prefedit.putInt("last_lang", mLang);
prefedit.commit();
if (mEditing == EDITING) {
commitTyped();
finish();
@ -353,8 +409,7 @@ public class TraditionalT9 extends InputMethodService implements
// Log.d("finish", "why?");
// Clear current composing text and candidates.
pickSelectedCandidate(getCurrentInputConnection());
mComposing.setLength(0);
mComposingI.setLength(0);
clearState();
// updateCandidates();
// We only hide the candidates window when finishing input on
@ -423,8 +478,8 @@ public class TraditionalT9 extends InputMethodService implements
*/
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
// Log.d("onKeyDown", "Key: " + event + " repeat?: " +
// event.getRepeatCount() + " long-time: " + event.isLongPress());
// Log.d("onKeyDown", "Key: " + event + " repeat?: " +
// event.getRepeatCount() + " long-time: " + event.isLongPress());
if (mEditing == NON_EDIT) {
// // catch for UI weirdness on up event thing
return false;
@ -531,9 +586,20 @@ public class TraditionalT9 extends InputMethodService implements
// event.toString() + ")");
}
Log.w("onKeyDown", "Unhandled Key: " + keyCode + "(" + event.toString() + ")");
commitReset();
return super.onKeyDown(keyCode, event);
}
protected void launchOptions() {
Intent awintent = new Intent(this, TraditionalT9Settings.class);
awintent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
awintent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
if (interfacehandler != null) {
interfacehandler.setPressed(KeyEvent.KEYCODE_SOFT_RIGHT, false);
}
hideWindow();
startActivity(awintent);
}
@Override
public boolean onKeyLongPress(int keyCode, KeyEvent event) {
// consume since we will assume we have already handled the long press
@ -566,7 +632,11 @@ public class TraditionalT9 extends InputMethodService implements
return true;
case KeyEvent.KEYCODE_STAR:
if (mKeyMode != MODE_NUM) {
showSmileyPage();
if (mLangsAvailable.length > 1){
nextLang();
} else {
showSmileyPage(); // TODO: replace with lang select if lang thing
}
return true;
}
break;
@ -574,7 +644,7 @@ public class TraditionalT9 extends InputMethodService implements
if (interfacehandler != null) {
interfacehandler.setPressed(keyCode, false);
}
if (mKeyMode == MODE_EN) {
if (mKeyMode == MODE_LANG) {
if (mWordFound) {
showAddWord();
} else {
@ -586,17 +656,21 @@ public class TraditionalT9 extends InputMethodService implements
if (interfacehandler != null) {
interfacehandler.setPressed(keyCode, false);
}
((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE))
.showInputMethodPicker();
// show IME
launchOptions();
// show Options
return true;
}
if (keyCode >= KeyEvent.KEYCODE_0 && keyCode <= KeyEvent.KEYCODE_9) {
if (mKeyMode == MODE_EN) {
if (mKeyMode == MODE_LANG) {
commitTyped();
onText(String.valueOf(keyCode - KeyEvent.KEYCODE_0));
} else if (mKeyMode == MODE_TEXT) {
commitReset();
onText(String.valueOf(keyCode - KeyEvent.KEYCODE_0));
} else if (mKeyMode == MODE_NUM) {
if (keyCode == KeyEvent.KEYCODE_0) {
onText("+");
}
}
}
return true;
@ -609,8 +683,8 @@ public class TraditionalT9 extends InputMethodService implements
*/
@Override
public boolean onKeyUp(int keyCode, KeyEvent event) {
// Log.d("onKeyUp", "Key: " + keyCode + " repeat?: " +
// event.getRepeatCount());
// Log.d("onKeyUp", "Key: " + keyCode + " repeat?: " +
// event.getRepeatCount());
if (mEditing == NON_EDIT) {
// if (mButtonClose) {
// //handle UI weirdness on up event
@ -661,24 +735,20 @@ public class TraditionalT9 extends InputMethodService implements
}
break;
}
// Log.d("onKeyUp", "Key: " + keyCode);
// Log.d("onKeyUp", "Key: " + event + " cancelled?: " +
// event.isCanceled());
if (event.isCanceled()) {
return true;
}
switch (keyCode) {
case KeyEvent.KEYCODE_BACK:
// Log.d("onKeyUp", "back pres");
if (isInputViewShown()) {
// Log.d("onKeyUp", "input shown");
hideWindow();
return true;
}
return false;
case KeyEvent.KEYCODE_DEL:
break;
return true;
case KeyEvent.KEYCODE_ENTER:
return false;
@ -719,6 +789,7 @@ public class TraditionalT9 extends InputMethodService implements
// KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD).getNumber(keyCode)
Log.w("onKeyUp", "Unhandled Key: " + keyCode + "(" + event.toString() + ")");
}
commitReset();
return super.onKeyUp(keyCode, event);
}
@ -732,13 +803,10 @@ public class TraditionalT9 extends InputMethodService implements
private void commitTyped(InputConnection ic) {
if (interfacehandler != null) {
interfacehandler.midButtonUpdate(false);
interfacehandler.showNotFound(false);
}
pickSelectedCandidate(ic);
mComposing.setLength(0);
mSuggestionStrings.clear();
mSuggestionInts.clear();
mSuggestionSym.clear();
mComposingI.setLength(0);
clearState();
updateCandidates();
setCandidatesViewShown(false);
}
@ -856,7 +924,7 @@ public class TraditionalT9 extends InputMethodService implements
}
if (mComposing.length() > 0) {
switch (mKeyMode) {
case MODE_EN:
case MODE_LANG:
commitTyped();
break;
case MODE_TEXT:
@ -874,26 +942,39 @@ public class TraditionalT9 extends InputMethodService implements
/**
* Update the list of available candidates from the current composing text.
* This will need to be filled in by however you are determining candidates.
* Do a lot of complicated stuffs.
*/
private void updateCandidates() {
if (mKeyMode == MODE_EN) {
updateCandidates(false);
}
private void updateCandidates(boolean backspace) {
if (mKeyMode == MODE_LANG) {
int len = mComposingI.length();
if (len > 0) {
if (mComposingI.charAt(len - 1) == '1') {
boolean nosuggestion = mSuggestionStrings.isEmpty();
boolean suggestions = !mSuggestionStrings.isEmpty();
String prefix = "";
if (!nosuggestion) {
prefix = mSuggestionStrings.get(mCandidateView.mSelectedIndex);
} else if (len > 1) {
prefix = db.getWord(mComposingI.substring(0, len - 1));
if (mPreviousWord.length() == 0) {
if (suggestions && !backspace) {
prefix = mPreviousWord = mSuggestionStrings.get(mCandidateView.mSelectedIndex);
}
} else {
if (backspace) {
prefix = mPreviousWord;
} else {
if (suggestions) {
prefix = mPreviousWord = mSuggestionStrings.get(mCandidateView.mSelectedIndex);
} else {
prefix = mPreviousWord;
}
}
}
mSuggestionInts.clear();
mSuggestionStrings.clear();
mSuggestionSym.clear();
db.updateWords("1", mSuggestionSym, mSuggestionInts, mCapsMode);
db.updateWords("1", mSuggestionSym, mSuggestionInts, mCapsMode, mLang);
for (String a : mSuggestionSym) {
if (prefix != "") {
if (!prefix.equals("")) {
mSuggestionStrings.add(prefix + a);
} else {
mSuggestionStrings.add(String.valueOf(a));
@ -903,7 +984,7 @@ public class TraditionalT9 extends InputMethodService implements
}
} else {
db.updateWords(mComposingI.toString(), mSuggestionStrings, mSuggestionInts,
mCapsMode);
mCapsMode, mLang);
}
if (!mSuggestionStrings.isEmpty()) {
mWordFound = true;
@ -931,7 +1012,7 @@ public class TraditionalT9 extends InputMethodService implements
} else if (mKeyMode == MODE_TEXT) {
if (mComposing.length() > 0) {
mSuggestionStrings.clear();
char[] ca = CharMap.T9TABLE[mPrevious];
char[] ca = CharMap.T9TABLE[mLang][mPrevious];
for (int i = 0; i < ca.length; i++) {
mSuggestionStrings.add(String.valueOf(ca[i]));
}
@ -961,13 +1042,23 @@ public class TraditionalT9 extends InputMethodService implements
}
setCandidatesViewShown(false);
}
if (length > 1 || length2 > 1) {
// Log.d("BS", "comp: " + length + " compI: " + length2);
mComposing.delete(length - 1, length);
if (length2 > 1) {
if (mComposingI.charAt(length2-1) == '1' ) {
// revert previous word
mPreviousWord = mPreviousWord.substring(0, mPreviousWord.length()-1);
}
mComposingI.delete(length2 - 1, length2);
mSuggestionStrings.clear();
updateCandidates();
if (length2-1 > 1) {
if (mComposingI.charAt(length2-2) != '1') {
if (mComposingI.indexOf("1") == -1) {
// no longer contains punctuation so we no longer care
mPreviousWord = "";
}
}
} else {
mPreviousWord = "";
}
updateCandidates(true);
getCurrentInputConnection().setComposingText(mComposing, 1);
} else if (length > 0 || length2 > 0) {
mComposing.setLength(0);
@ -975,9 +1066,11 @@ public class TraditionalT9 extends InputMethodService implements
interfacehandler.midButtonUpdate(false);
interfacehandler.showNotFound(false);
mSuggestionStrings.clear();
mPreviousWord = "";
getCurrentInputConnection().commitText("", 0);
updateCandidates();
} else {
mPreviousWord = "";
keyDownUp(KeyEvent.KEYCODE_DEL);
}
updateShiftKeyState(getCurrentInputEditorInfo());
@ -994,7 +1087,7 @@ public class TraditionalT9 extends InputMethodService implements
mCapsMode++;
}
if (mKeyMode == MODE_EN && mComposing.length() > 0) {
if (mKeyMode == MODE_LANG && mComposing.length() > 0) {
updateCandidates();
getCurrentInputConnection().setComposingText(mComposing, 1);
}
@ -1007,18 +1100,14 @@ public class TraditionalT9 extends InputMethodService implements
* @param keyCode
*/
private void handleCharacter(int keyCode) {
// if (mInputView.isShifted()) {
// primaryCode = Character.toUpperCase(primaryCode);
// }
switch (mKeyMode) {
case MODE_EN:
case MODE_LANG:
// it begins
// on POUND commit and space
if (keyCode == KeyEvent.KEYCODE_POUND) {
if (mComposing.length() > 0) {
commitTyped();
}
// Log.d("handleChar", "SENDING SPACE?");
onText(" ");
} else {
// do things
@ -1055,14 +1144,14 @@ public class TraditionalT9 extends InputMethodService implements
// start at caps if CapMode
// Log.d("handleChar", "Cm: " + mCapsMode);
if (mCharIndex == 0 && mCapsMode != CAPS_OFF) {
mCharIndex = CharMap.T9CAPSTART[keyCode];
mCharIndex = CharMap.T9CAPSTART[mLang][keyCode];
}
// private int mPrevious;
// private int mCharindex;
mComposing.setLength(0);
mComposingI.setLength(0);
char[] ca = CharMap.T9TABLE[keyCode];
char[] ca = CharMap.T9TABLE[mLang][keyCode];
if (mCharIndex >= ca.length) {
mCharIndex = 0;
}
@ -1071,7 +1160,7 @@ public class TraditionalT9 extends InputMethodService implements
mComposingI.append(keyCode);
getCurrentInputConnection().setComposingText(mComposing, 1);
t9releasehandler.postDelayed(mt9release, 1500);
t9releasehandler.postDelayed(mt9release, T9DELAY);
if (newChar) {
// consume single caps
if (mCapsMode == CAPS_SINGLE) {
@ -1093,7 +1182,6 @@ public class TraditionalT9 extends InputMethodService implements
break;
default:
onText(String.valueOf(keyCode - KeyEvent.KEYCODE_0));
}
break;
@ -1144,7 +1232,11 @@ public class TraditionalT9 extends InputMethodService implements
return true;
case KeyEvent.KEYCODE_DPAD_LEFT:
case KeyEvent.KEYCODE_DPAD_RIGHT:
if (mKeyMode == MODE_LANG) {
commitTyped();
} else if (mKeyMode == MODE_TEXT) {
commitReset();
}
// getCurrentInputConnection().sendKeyEvent(mDPADkeyEvent);
// return super.onKeyUp(keyCode, event);
return true;
@ -1187,14 +1279,25 @@ public class TraditionalT9 extends InputMethodService implements
}
protected void nextKeyMode() {
if (mKeyMode == MODE_CYCLE.length - 1)
if (mKeyMode == MODE_CYCLE.length - 1) {
mKeyMode = 0;
else
}
else {
mKeyMode++;
}
updateKeyMode();
resetKeyMode();
}
private void nextLang() {
mLangIndex++;
if (mLangIndex == mLangsAvailable.length) {
mLangIndex = 0;
}
mLang = mLangsAvailable[mLangIndex];
updateKeyMode();
}
private void resetKeyMode() {
charReset();
if (mKeyMode != MODE_NUM) {
@ -1215,35 +1318,29 @@ public class TraditionalT9 extends InputMethodService implements
switch (mKeyMode) {
case MODE_TEXT:
interfacehandler.showHold(false);
switch (mCapsMode) {
case CAPS_OFF:
icon = R.drawable.ime_text_lower;
break;
case CAPS_ALL:
icon = R.drawable.ime_text_upper;
break;
case CAPS_SINGLE:
icon = R.drawable.ime_text_single;
icon = LangHelper.ICONMAP[mLang][mKeyMode][mCapsMode];
break;
case MODE_LANG:
if (!db.ready) {
if (!mGaveUpdateWarn) {
Toast.makeText(this, getText(R.string.updating_database_unavailable), Toast.LENGTH_LONG).show();
mGaveUpdateWarn = true;
}
nextKeyMode();
return;
}
if (mLangIndex == -1) {
nextKeyMode();
return;
}
break;
case MODE_EN:
if (mAddingWord) {
interfacehandler.showHold(false);
} else {
interfacehandler.showHold(true);
}
switch (mCapsMode) {
case CAPS_ALL:
icon = R.drawable.ime_en_upper;
break;
case CAPS_SINGLE:
icon = R.drawable.ime_en_single;
break;
case CAPS_OFF:
icon = R.drawable.ime_en_lower;
break;
}
//Log.d("T9.updateKeyMode", "lang: " + mLang + " mKeyMode: " + mKeyMode + " mCapsMode"
// + mCapsMode);
icon = LangHelper.ICONMAP[mLang][mKeyMode][mCapsMode];
break;
case MODE_NUM:
interfacehandler.showHold(false);
@ -1272,14 +1369,14 @@ public class TraditionalT9 extends InputMethodService implements
// mSuggestionStrings.get(mCandidateView.mSelectedIndex));
// get and commit selected suggestion
ic.commitText(mSuggestionStrings.get(mCandidateView.mSelectedIndex), 1);
if (mKeyMode == MODE_EN) {
if (mKeyMode == MODE_LANG) {
// update freq
db.incrementWord(mSuggestionInts.get(mCandidateView.mSelectedIndex));
}
} else {
// commit suggestion index
ic.commitText(mSuggestionStrings.get(index), 1);
if (mKeyMode == MODE_EN) {
if (mKeyMode == MODE_LANG) {
db.incrementWord(mSuggestionInts.get(index));
}
}

View file

@ -0,0 +1,73 @@
package org.nyanya.android.traditionalt9;
import android.text.InputType;
import android.util.Log;
public class Utils {
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,198 @@
package pl.wavesoftware.widget;
// https://gist.github.com/cardil/4754571/07b4b6ffd37b440bbdec2cafa1ab7411c5ad3873
// modified to work specifically for this service
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import android.app.AlertDialog.Builder;
import android.content.Context;
import android.content.DialogInterface;
import android.content.DialogInterface.OnMultiChoiceClickListener;
import android.content.res.TypedArray;
import android.preference.ListPreference;
import android.util.AttributeSet;
import android.util.Log;
public class MultiSelectListPreference extends ListPreference {
private String separator;
private static final String DEFAULT_SEPARATOR = "\u0001\u0007\u001D\u0007\u0001";
private boolean[] entryChecked;
public MultiSelectListPreference(Context context, AttributeSet attributeSet) {
super(context, attributeSet);
entryChecked = new boolean[getEntries().length];
separator = DEFAULT_SEPARATOR;
}
public MultiSelectListPreference(Context context) {
this(context, null);
}
@Override
protected void onPrepareDialogBuilder(Builder builder) {
CharSequence[] entries = getEntries();
CharSequence[] entryValues = getEntryValues();
if (entries == null || entryValues == null
|| entries.length != entryValues.length) {
throw new IllegalStateException(
"MultiSelectListPreference requires an entries array and an entryValues "
+ "array which are both the same length");
}
restoreCheckedEntries();
OnMultiChoiceClickListener listener = new DialogInterface.OnMultiChoiceClickListener() {
public void onClick(DialogInterface dialog, int which, boolean val) {
entryChecked[which] = val;
}
};
builder.setMultiChoiceItems(entries, entryChecked, listener);
}
private CharSequence[] unpack(CharSequence val) {
if (val == null || "".equals(val)) {
return new CharSequence[0];
} else {
return ((String) val).split(separator);
}
}
// added method
public static int[] defaultunpack2Int(CharSequence val) {
if (val == null || "".equals(val)) {
//Log.w("MultiSelectPref.defaultunpack", "val is null or empty");
return new int[] {0}; //default pref
} else {
String[] sa = ((String) val).split(DEFAULT_SEPARATOR);
if (sa.length < 1) {
Log.w("MultiSelectPref.defaultunpack", "split is less than 1");
return new int[] {0}; //default pref
}
int[] ia = new int[sa.length];
for (int x=0;x<sa.length;x++) {
ia[x] = Integer.valueOf(sa[x]);
}
return ia;
}
}
/**
* Gets the entries values that are selected
*
* @return the selected entries values
*/
public CharSequence[] getCheckedValues() {
return unpack(getValue());
}
private void restoreCheckedEntries() {
CharSequence[] entryValues = getEntryValues();
// Explode the string read in sharedpreferences
CharSequence[] vals = unpack(getValue());
if (vals != null) {
List<CharSequence> valuesList = Arrays.asList(vals);
for (int i = 0; i < entryValues.length; i++) {
CharSequence entry = entryValues[i];
entryChecked[i] = valuesList.contains(entry);
}
}
}
@Override
protected void onDialogClosed(boolean positiveResult) {
List<CharSequence> values = new ArrayList<CharSequence>();
CharSequence[] entryValues = getEntryValues();
if (positiveResult && entryValues != null) {
for (int i = 0; i < entryValues.length; i++) {
if (entryChecked[i] == true) {
String val = (String) entryValues[i];
values.add(val);
}
}
String value = join(values, separator);
setSummary(prepareSummary(values));
setValueAndEvent(value);
}
}
//modified to make sure some sane thing gets stored
private void setValueAndEvent(String value) {
if (callChangeListener(unpack(value))) {
if (value == null || value.length() < 1) {
setValue("0"); //default
} else {
setValue(value);
}
}
}
private CharSequence prepareSummary(List<CharSequence> joined) {
List<String> titles = new ArrayList<String>();
CharSequence[] entryTitle = getEntries();
CharSequence[] entryValues = getEntryValues();
int ix = 0;
for (CharSequence value : entryValues) {
if (joined.contains(value)) {
titles.add((String) entryTitle[ix]);
}
ix += 1;
}
return join(titles, ", ");
}
@Override
protected Object onGetDefaultValue(TypedArray typedArray, int index) {
return typedArray.getTextArray(index);
}
@Override
protected void onSetInitialValue(boolean restoreValue,
Object rawDefaultValue) {
String value = null;
CharSequence[] defaultValue;
if (rawDefaultValue == null) {
defaultValue = new CharSequence[0];
} else {
defaultValue = (CharSequence[]) rawDefaultValue;
}
List<CharSequence> joined = Arrays.asList(defaultValue);
String joinedDefaultValue = join(joined, separator);
if (restoreValue) {
value = getPersistedString(joinedDefaultValue);
} else {
value = joinedDefaultValue;
}
setSummary(prepareSummary(Arrays.asList(unpack(value))));
setValueAndEvent(value);
}
/**
* Joins array of object to single string by separator
*
* Credits to kurellajunior on this post
* http://snippets.dzone.com/posts/show/91
*
* @param iterable
* any kind of iterable ex.: <code>["a", "b", "c"]</code>
* @param separator
* separetes entries ex.: <code>","</code>
* @return joined string ex.: <code>"a,b,c"</code>
*/
protected static String join(Iterable<?> iterable, String separator) {
Iterator<?> oIter;
if (iterable == null || (!(oIter = iterable.iterator()).hasNext()))
return "";
StringBuilder oBuilder = new StringBuilder(String.valueOf(oIter.next()));
while (oIter.hasNext())
oBuilder.append(separator).append(oIter.next());
return oBuilder.toString();
}
}