diff --git a/.gitignore b/.gitignore index 93a68ba25..6f69b0260 100644 --- a/.gitignore +++ b/.gitignore @@ -56,6 +56,7 @@ infer-out/ fastlane/ app/.externalNativeBuild +openwnn/.externalNativeBuild *.swp diff --git a/app/build.gradle b/app/build.gradle index 203ac516b..0e82ff307 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -332,6 +332,7 @@ repositories { dependencies { implementation fileTree(include: ['*.jar'], dir: 'libs') + implementation deps.openwnn // Common // implementation deps.google_vr.sdk_audio diff --git a/app/src/common/shared/org/mozilla/vrbrowser/input/CustomKeyboard.java b/app/src/common/shared/org/mozilla/vrbrowser/input/CustomKeyboard.java index ecd4bca78..7ca1e9ed6 100644 --- a/app/src/common/shared/org/mozilla/vrbrowser/input/CustomKeyboard.java +++ b/app/src/common/shared/org/mozilla/vrbrowser/input/CustomKeyboard.java @@ -26,6 +26,7 @@ public class CustomKeyboard extends Keyboard { public static final int KEYCODE_SYMBOLS_CHANGE = -10; public static final int KEYCODE_VOICE_INPUT = -11; public static final int KEYCODE_LANGUAGE_CHANGE = -12; + public static final int KEYCODE_EMOJI = -13; public CustomKeyboard(Context context, int xmlLayoutResId) { super(context, xmlLayoutResId, 0); diff --git a/app/src/common/shared/org/mozilla/vrbrowser/ui/keyboards/JapaneseKeyboard.java b/app/src/common/shared/org/mozilla/vrbrowser/ui/keyboards/JapaneseKeyboard.java new file mode 100644 index 000000000..92fe1058e --- /dev/null +++ b/app/src/common/shared/org/mozilla/vrbrowser/ui/keyboards/JapaneseKeyboard.java @@ -0,0 +1,210 @@ +package org.mozilla.vrbrowser.ui.keyboards; + +import android.content.Context; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.mozilla.vrbrowser.R; +import org.mozilla.vrbrowser.input.CustomKeyboard; +import org.mozilla.vrbrowser.utils.StringUtils; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import jp.co.omronsoft.openwnn.ComposingText; +import jp.co.omronsoft.openwnn.JAJP.OpenWnnEngineJAJP; +import jp.co.omronsoft.openwnn.JAJP.Romkan; +import jp.co.omronsoft.openwnn.LetterConverter; +import jp.co.omronsoft.openwnn.StrSegment; +import jp.co.omronsoft.openwnn.SymbolList; +import jp.co.omronsoft.openwnn.WnnEngine; +import jp.co.omronsoft.openwnn.WnnWord; + +public class JapaneseKeyboard extends BaseKeyboard { + + private static final String LOGTAG = "VRB"; + + private CustomKeyboard mKeyboard; + private CustomKeyboard mSymbolsKeyboard; + private List mAutocompleteEndings = Arrays.asList( + ' ', '、', '。','!','?','ー' + ); + + private SymbolList mSymbolsConverter; + + /** OpenWnn dictionary */ + private WnnEngine mConverter; + + /** Pre-converter (for Romaji-to-Kana input, Hangul input, etc.) */ + protected LetterConverter mPreConverter; + + /** The inputing/editing string */ + protected ComposingText mComposingText; + + + public JapaneseKeyboard(Context aContext) { + super(aContext); + + mConverter = new OpenWnnEngineJAJP(); + ((OpenWnnEngineJAJP) mConverter).setKeyboardType(OpenWnnEngineJAJP.KEYBOARD_QWERTY); + ((OpenWnnEngineJAJP) mConverter).setDictionary(OpenWnnEngineJAJP.DIC_LANG_JP); + mConverter.init(); + + mPreConverter = new Romkan(); + mComposingText = new ComposingText(); + } + + @NonNull + @Override + public CustomKeyboard getAlphabeticKeyboard() { + if (mKeyboard == null) { + mKeyboard = new CustomKeyboard(mContext.getApplicationContext(), R.xml.keyboard_qwerty_japanese); + } + + return mKeyboard; + } + + @Nullable + @Override + public CustomKeyboard getSymbolsKeyboard() { + if (mSymbolsKeyboard == null) { + mSymbolsKeyboard = new CustomKeyboard(mContext.getApplicationContext(), R.xml.keyboard_symbols_japanese); + + mSymbolsConverter = new SymbolList(mContext, SymbolList.LANG_JA); + } + return mSymbolsKeyboard; + } + + @Nullable + @Override + public CandidatesResult getCandidates(String aComposingText) { + if (StringUtils.isEmpty(aComposingText)) { + mComposingText.clear(); + return null; + } + + // Autocomplete when special characters are clicked + char lastChar = aComposingText.charAt(aComposingText.length() - 1); + boolean autocompose = mAutocompleteEndings.indexOf(lastChar) >= 0; + + aComposingText = aComposingText.replaceAll("\\s",""); + if (aComposingText.isEmpty()) { + return null; + } + + initializeComposingText(aComposingText); + + List words = new ArrayList<>(); + int candidates = mConverter.predict(mComposingText, 0, -1); + if (candidates > 0) { + WnnWord word; + while ((word = mConverter.getNextCandidate()) != null) { + words.add(new Words(1, word.stroke, word.candidate)); + } + } + + CandidatesResult result = new CandidatesResult(); + result.words = words; + + if (autocompose) { + result.action = CandidatesResult.Action.AUTO_COMPOSE; + result.composing = aComposingText; + + mComposingText.clear(); + + } else { + result.action = CandidatesResult.Action.SHOW_CANDIDATES; + result.composing = mComposingText.toString(ComposingText.LAYER2); + } + + return result; + } + + @Override + public CandidatesResult getEmojiCandidates(String aComposingText) { + ComposingText text = new ComposingText(); + mSymbolsConverter.convert(text); + + List words = new ArrayList<>(); + int candidates = mSymbolsConverter.predict(mComposingText, 0, -1); + if (candidates > 0) { + WnnWord word; + while ((word = mSymbolsConverter.getNextCandidate()) != null) { + words.add(new Words(1, word.stroke, word.candidate)); + } + } + + CandidatesResult result = new CandidatesResult(); + result.words = words; + result.action = CandidatesResult.Action.SHOW_CANDIDATES; + result.composing = aComposingText; + + return result; + } + + @Override + public String getComposingText(String aComposing, String aCode) { + return ""; + } + + private void initializeComposingText(String text) { + mComposingText.clear(); + for (int i=0; i 0); + mAutoCompletionView.setItems(candidates != null ? candidates.words : null); + } + private void handleLanguageChange(KeyboardInterface aKeyboard) { cleanComposingText(); @@ -949,6 +961,7 @@ public void afterTextChanged(Editable aEditable) { if (!mInternalDeleteHint && mCurrentKeyboard.usesComposingText() && mComposingText.length() > 0 && mTextBefore.length() > 0 && aEditable.toString().length() == 0) { // Text has been cleared externally (e.g. URLBar text clear button) mComposingText = ""; + mCurrentKeyboard.clear(); updateCandidates(); } mInternalDeleteHint = false; diff --git a/app/src/main/res/values/non_L10n.xml b/app/src/main/res/values/non_L10n.xml index 4704f6a86..fdc9d279d 100644 --- a/app/src/main/res/values/non_L10n.xml +++ b/app/src/main/res/values/non_L10n.xml @@ -72,6 +72,11 @@ 選定 ㄅㄆㄇ + 次変換 + 空白 + 確定 + かな + aáàäãåâąæā bƀḃḅḇ diff --git a/app/src/main/res/xml/keyboard_qwerty_japanese.xml b/app/src/main/res/xml/keyboard_qwerty_japanese.xml new file mode 100644 index 000000000..42f5c0ebd --- /dev/null +++ b/app/src/main/res/xml/keyboard_qwerty_japanese.xml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/xml/keyboard_symbols_japanese.xml b/app/src/main/res/xml/keyboard_symbols_japanese.xml new file mode 100644 index 000000000..6d6719dcf --- /dev/null +++ b/app/src/main/res/xml/keyboard_symbols_japanese.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/versions.gradle b/versions.gradle index 93f2e0ae5..43f5326b5 100644 --- a/versions.gradle +++ b/versions.gradle @@ -27,6 +27,7 @@ def versions = [:] versions.gecko_view = "69.0.20190530094559" versions.android_components = "0.52.0" versions.mozilla_speech = "1.0.6" +versions.openwnn = "1.3.7" versions.google_vr = "1.190.0" versions.room = "2.1.0-alpha02" versions.lifecycle = "2.0.0" @@ -61,6 +62,8 @@ deps.android_components = android_components deps.mozilla_speech = "com.github.mozilla:mozillaspeechlibrary:$versions.mozilla_speech" +deps.openwnn = "jp.co.omronsoft.openwnn:openwnn:$versions.openwnn" + def google_vr = [:] google_vr.sdk_base = "com.google.vr:sdk-base:$versions.google_vr" google_vr.sdk_audio = "com.google.vr:sdk-audio:$versions.google_vr"