From 67a43243b7bb6e36c3eadcdf0c27a306e78e52be Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 26 Mar 2019 16:06:23 +0700 Subject: [PATCH 1/6] Start integrating lexical model installs to KMW --- .../com/tavultesoft/kmapro/MainActivity.java | 8 + .../tavultesoft/kmapro/PackageActivity.java | 33 +++- .../kMAPro/src/main/res/values/strings.xml | 1 + .../KMEA/app/src/main/assets/keyboard.html | 6 + .../java/com/tavultesoft/kmea/KMManager.java | 36 +++++ .../kmea/KeyboardEventHandler.java | 27 +++- .../kmea/KeyboardListActivity.java | 7 +- .../kmea/KeyboardPickerActivity.java | 145 ++++++++++++++++-- .../kmea/LanguageListActivity.java | 5 + web/source/kmwembedded.ts | 10 +- 10 files changed, 247 insertions(+), 31 deletions(-) diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java index 4deb03edf0..2071569fe6 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java @@ -830,6 +830,14 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi } } + @Override + public void onLexicalModelInstalled(List> lexicalModelsInstalled) { + for(int i=0; ilexicalModelInfo = new HashMap<>(lexicalModelsInstalled.get(i)); + KMManager.addLexicalModel(this, lexicalModelInfo); + } + } + private void copyFile(FileInputStream inStream, File dstFile) throws IOException { OutputStream outStream = new FileOutputStream(dstFile); diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java index 9c30bb556a..47179ed6e2 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/PackageActivity.java @@ -182,26 +182,37 @@ public class PackageActivity extends AppCompatActivity { try { if (pkgTarget.equals(PackageProcessor.PP_TARGET_KEYBOARDS)) { // processKMP will remove currently installed package and install - installedPackageKeyboards = kmpProcessor.processKMP(kmpFile, tempPackagePath, PackageProcessor.PP_KEYBOARDS_KEY); + installedPackageKeyboards = kmpProcessor.processKMP(kmpFile, tempPackagePath, + PackageProcessor.PP_KEYBOARDS_KEY); // Do the notifications! boolean success = installedPackageKeyboards.size() != 0; if (success) { - notifyPackageInstallListeners(KeyboardEventHandler.EventType.PACKAGE_INSTALLED, installedPackageKeyboards, 1); + notifyPackageInstallListeners(KeyboardEventHandler.EventType.PACKAGE_INSTALLED, + installedPackageKeyboards, 1); if (installedPackageKeyboards != null) { - notifyPackageInstallListeners(KeyboardEventHandler.EventType.PACKAGE_INSTALLED, installedPackageKeyboards, 1); + notifyPackageInstallListeners(KeyboardEventHandler.EventType.PACKAGE_INSTALLED, + installedPackageKeyboards, 1); } cleanup(); } else { showErrorDialog(context, pkgId, getString(R.string.no_new_touch_keyboards_to_install)); } } else if (pkgTarget.equals(PackageProcessor.PP_TARGET_LEXICAL_MODELS)) { - installedLexicalModels = kmpProcessor.processKMP(kmpFile, tempPackagePath, PackageProcessor.PP_LEXICAL_MODELS_KEY); + installedLexicalModels = kmpProcessor.processKMP(kmpFile, tempPackagePath, + PackageProcessor.PP_LEXICAL_MODELS_KEY); // Do the notifications boolean success = installedLexicalModels.size() != 0; if (success) { - + notifyLexicalModelInstallListeners(KeyboardEventHandler.EventType.LEXICAL_MODEL_INSTALLED, + installedLexicalModels, 1); + if (installedLexicalModels != null) { + notifyLexicalModelInstallListeners(KeyboardEventHandler.EventType.LEXICAL_MODEL_INSTALLED, + installedLexicalModels, 1); + } + cleanup(); + } else { + showErrorDialog(context, pkgId, getString(R.string.no_new_predictive_text_to_install)); } - cleanup(); } } catch (Exception e) { Log.e("PackageActivity", "Error " + e); @@ -280,12 +291,20 @@ public class PackageActivity extends AppCompatActivity { alertDialog.show(); } - void notifyPackageInstallListeners(KeyboardEventHandler.EventType eventType, List> keyboards, int result) { + void notifyPackageInstallListeners(KeyboardEventHandler.EventType eventType, + List> keyboards, int result) { if (kbDownloadEventListeners != null) { KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, eventType, keyboards, result); } } + void notifyLexicalModelInstallListeners(KeyboardEventHandler.EventType eventType, + List> models, int result) { + if (kbDownloadEventListeners != null) { + KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, eventType, models, result); + } + } + public static void addKeyboardDownloadEventListener(KeyboardEventHandler.OnKeyboardDownloadEventListener listener) { if (kbDownloadEventListeners == null) { kbDownloadEventListeners = new ArrayList(); diff --git a/android/KMAPro/kMAPro/src/main/res/values/strings.xml b/android/KMAPro/kMAPro/src/main/res/values/strings.xml index e1d33632f5..6750efd1af 100644 --- a/android/KMAPro/kMAPro/src/main/res/values/strings.xml +++ b/android/KMAPro/kMAPro/src/main/res/values/strings.xml @@ -49,6 +49,7 @@ Install Keyboard Package Install Predictive Text Package No new touch-optimized keyboards to install + No new predictive text to install No valid touch-optimized keyboards to install No keyboards or predictive text to install kmp.json does not exist diff --git a/android/KMEA/app/src/main/assets/keyboard.html b/android/KMEA/app/src/main/assets/keyboard.html index 88cccf60d0..cfcdb5aced 100644 --- a/android/KMEA/app/src/main/assets/keyboard.html +++ b/android/KMEA/app/src/main/assets/keyboard.html @@ -126,6 +126,12 @@ window.jsInterface.insertText(dn, s); } + function registerModel(model) { + var kmw=window['keyman']; + window.console.log('model: ' + model); + kmw.registerModel(model); + } + function resetContext() { var kmw=window['keyman']; kmw.resetContext(); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index a6e03e3500..ab3991e854 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -57,6 +57,8 @@ import com.tavultesoft.kmea.packages.PackageProcessor; import com.tavultesoft.kmea.KMScanCodeMap; import com.tavultesoft.kmea.util.FileUtils; +import org.json.JSONArray; +import org.json.JSONException; import org.json.JSONObject; public final class KMManager { @@ -154,6 +156,7 @@ public final class KMManager { protected static final String KMFilename_Osk_Ttf_Font = "keymanweb-osk.ttf"; protected static final String KMFilename_Osk_Woff_Font = "keymanweb-osk.woff"; public static final String KMFilename_KeyboardsList = "keyboards_list.dat"; + public static final String KMFilename_LexicalModelsList = "lexical_models_list.dat"; private static Context appContext; @@ -647,6 +650,39 @@ public final class KMManager { return KeyboardPickerActivity.getKeyboardsList(context); } + public static boolean registerLexicalModel(HashMap lexicalModelInfo) { + String pkgID = lexicalModelInfo.get(KMKey_PackageID); + String modelID = lexicalModelInfo.get(KMKey_LexicalModelID); + String languageID = lexicalModelInfo.get(KMKey_LanguageID); + String path = "file://" + getLexicalModelsDir() + pkgID + File.separator + modelID + ".model.js"; + + JSONObject m = new JSONObject(); + JSONArray languageArray = new JSONArray(); + try { + m.put("id", modelID); + languageArray.put(languageID); + m.put("languages", languageArray); + m.put("path", path); + } catch (JSONException e) { + + } + + // Escape quotes for javascript call + String model = String.valueOf(m).replaceAll("\"", "\\\\\""); + + if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { + InAppKeyboard.loadUrl(String.format("javascript:registerModel('%s')", model)); + } + if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { + SystemKeyboard.loadUrl(String.format("javascript:registerModel('%s')", model)); + } + return true; + } + + public static boolean addLexicalModel(Context context, HashMap lexicalModelInfo) { + return KeyboardPickerActivity.addLexicalModel(context, lexicalModelInfo); + } + public static boolean addKeyboard(Context context, HashMap keyboardInfo) { // Log Firebase analytic event. Bundle params = new Bundle(); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardEventHandler.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardEventHandler.java index 3e19750b6b..a92e4d6c1c 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardEventHandler.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardEventHandler.java @@ -20,7 +20,8 @@ public final class KeyboardEventHandler { KEYBOARD_DISMISSED, KEYBOARD_DOWNLOAD_STARTED, KEYBOARD_DOWNLOAD_FINISHED, - PACKAGE_INSTALLED; + PACKAGE_INSTALLED, + LEXICAL_MODEL_INSTALLED; } public static void notifyListeners(ArrayList listeners, KeyboardType keyboardType, EventType event, String newValue) { @@ -44,11 +45,13 @@ public final class KeyboardEventHandler { } } - public static void notifyListeners(ArrayList listeners, EventType event, HashMap keyboardInfo, int result) { + public static void notifyListeners(ArrayList listeners, + EventType event, HashMap keyboardInfo, int result) { if (listeners != null) { @SuppressWarnings("unchecked") // make a copy of the list to avoid concurrent modification while iterating - ArrayList _listeners = (ArrayList) listeners.clone(); + ArrayList _listeners = + (ArrayList) listeners.clone(); if (event == EventType.KEYBOARD_DOWNLOAD_STARTED) { for (OnKeyboardDownloadEventListener listener : _listeners) listener.onKeyboardDownloadStarted(keyboardInfo); @@ -59,14 +62,22 @@ public final class KeyboardEventHandler { } } - public static void notifyListeners(ArrayList listeners, EventType event, List> keyboardsInfo, int result) { + public static void notifyListeners(ArrayList listeners, + EventType event, List> info, int result) { if (listeners != null) { @SuppressWarnings("unchecked") // make a copy of the list to avoid concurrent modification while iterating - ArrayList _listeners = (ArrayList) listeners.clone(); + ArrayList _listeners = + (ArrayList) listeners.clone(); if (event == EventType.PACKAGE_INSTALLED) { - for (OnKeyboardDownloadEventListener listener : _listeners) - listener.onPackageInstalled(keyboardsInfo); + for (OnKeyboardDownloadEventListener listener : _listeners) { + listener.onPackageInstalled(info); + } + } else if (event == EventType.LEXICAL_MODEL_INSTALLED) { + for (OnKeyboardDownloadEventListener listener : _listeners) { + listener.onLexicalModelInstalled(info); + } + } } } @@ -88,5 +99,7 @@ public final class KeyboardEventHandler { void onKeyboardDownloadFinished(HashMap keyboardInfo, int result); // result > 0 if successful, < 0 if failed void onPackageInstalled(List> keyboardsInstalled); + + void onLexicalModelInstalled(List> lexicalModelsInstalled); } } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java index 8259176eb3..937550131b 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardListActivity.java @@ -185,4 +185,9 @@ public final class KeyboardListActivity extends AppCompatActivity implements OnK public void onPackageInstalled(List> keyboardsInstalled) { // Do nothing. } -} \ No newline at end of file + + @Override + public void onLexicalModelInstalled(List> lexicalModelsInstalled) { + // Do nothing. + } +} diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java index db1dca3cf8..c2647accf1 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java @@ -58,6 +58,8 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O private static KMKeyboardPickerAdapter listAdapter = null; private static ArrayList> keyboardsList = null; private static HashMap keyboardVersions = null; + private static ArrayList> lexicalModelsList = null; + // private static HashMap lexicalModelsVersions = null; TODO private static boolean checkingUpdates = false; private static int updateCount = 0; private static int failedUpdateCount = 0; @@ -125,9 +127,21 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O keyboardsList.add(kbInfo); // We'd prefer not to overwrite a file if it exists - File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), KMManager.KMFilename_KeyboardsList); + File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), + KMManager.KMFilename_KeyboardsList); if (!file.exists()) { - saveKeyboardsList(context); + saveList(context, KMManager.KMFilename_KeyboardsList); + } + } + + if (lexicalModelsList == null) { + lexicalModelsList = new ArrayList>(); + + // We'd prefer not to overwrite a file if it exists + File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), + KMManager.KMFilename_LexicalModelsList); + if (!file.exists()) { + saveList(context, KMManager.KMFilename_LexicalModelsList); } } @@ -315,17 +329,21 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O return false; } - private static boolean saveKeyboardsList(Context context) { + private static boolean saveList(Context context, String listName) { boolean result; try { - File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), KMManager.KMFilename_KeyboardsList); + File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), listName); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file)); - outputStream.writeObject(keyboardsList); + if (listName.equalsIgnoreCase(KMManager.KMFilename_KeyboardsList)) { + outputStream.writeObject(keyboardsList); + } else if (listName.equalsIgnoreCase(KMManager.KMFilename_LexicalModelsList)) { + outputStream.writeObject(lexicalModelsList); + } outputStream.flush(); outputStream.close(); result = true; } catch (Exception e) { - Log.e(TAG, "Failed to save keyboards list. Error: " + e); + Log.e(TAG, "Failed to save " + listName + ". Error: " + e); result = false; } @@ -335,7 +353,14 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O protected static boolean updateKeyboardsList(Context context, ArrayList> list) { boolean result; keyboardsList = list; - result = saveKeyboardsList(context); + result = saveList(context, KMManager.KMFilename_KeyboardsList); + return result; + } + + protected static boolean updateLexicalModelsList(Context context, ArrayList> list) { + boolean result; + lexicalModelsList = list; + result = saveList(context, KMManager.KMFilename_LexicalModelsList); return result; } @@ -359,6 +384,13 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O String kFont = kbInfo.get(KMManager.KMKey_Font); String kOskFont = kbInfo.get(KMManager.KMKey_OskFont); KMManager.setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + + // Register associated lexical model + HashMap lmInfo = getAssociatedLexicalModel(langId); + if (lmInfo != null) { + KMManager.registerLexicalModel(lmInfo); + } + } protected static boolean addKeyboard(Context context, HashMap keyboardInfo) { @@ -382,10 +414,10 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O int x = getKeyboardIndex(context, kbKey); if (x >= 0) { keyboardsList.set(x, keyboardInfo); - result = saveKeyboardsList(context); + result = saveList(context, KMManager.KMFilename_KeyboardsList); } else { keyboardsList.add(keyboardInfo); - result = saveKeyboardsList(context); + result = saveList(context, KMManager.KMFilename_KeyboardsList); if (!result) { keyboardsList.remove(keyboardsList.size() - 1); } @@ -397,6 +429,39 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O return result; } + protected static boolean addLexicalModel(Context context, HashMap lexicalModelInfo) { + boolean result = false; + + if (lexicalModelsList == null) { + lexicalModelsList = new ArrayList>(); + } + + if (lexicalModelInfo != null) { + String pkgID = lexicalModelInfo.get(KMManager.KMKey_PackageID); + String modelID = lexicalModelInfo.get(KMManager.KMKey_LexicalModelID); + String langID = lexicalModelInfo.get(KMManager.KMKey_LanguageID); + + if (pkgID != null && modelID != null && langID != null) { + String lmKey = String.format("%s_%s_%s", langID, pkgID, modelID); + if (lmKey.length() >= 3) { + int x = getLexicalModelIndex(context, lmKey); + if (x >= 0) { + lexicalModelsList.set(x, lexicalModelInfo); + result = saveList(context, KMManager.KMFilename_LexicalModelsList); + } else { + lexicalModelsList.add(lexicalModelInfo); + result = saveList(context, KMManager.KMFilename_LexicalModelsList); + if (!result) { + lexicalModelsList.remove(lexicalModelsList.size() - 1); + } + } + } + } + } + + return result; + } + protected static boolean removeKeyboard(Context context, int position) { boolean result = false; if (keyboardsList == null) { @@ -405,7 +470,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O if (keyboardsList != null && position >= 0 && position < keyboardsList.size()) { keyboardsList.remove(position); - result = saveKeyboardsList(context); + result = saveList(context, KMManager.KMFilename_KeyboardsList); } return result; @@ -430,17 +495,17 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O } @SuppressWarnings("unchecked") - protected static ArrayList> getKeyboardsList(Context context) { + private static ArrayList> getList(Context context, String filename) { ArrayList> list = null; - File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), KMManager.KMFilename_KeyboardsList); + File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), filename); if (file.exists()) { try { ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file)); list = (ArrayList>) inputStream.readObject(); inputStream.close(); } catch (Exception e) { - Log.e(TAG, "Failed to read keyboards list. Error: " + e); + Log.e(TAG, "Failed to read " + filename + ". Error: " + e); list = null; } } @@ -448,6 +513,14 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O return list; } + protected static ArrayList> getKeyboardsList(Context context) { + return getList(context, KMManager.KMFilename_KeyboardsList); + } + + protected static ArrayList> getLexicalModelsList(Context context) { + return getList(context, KMManager.KMFilename_LexicalModelsList); + } + protected static boolean containsKeyboard(Context context, String keyboardKey) { if (keyboardsList == null) { keyboardsList = getKeyboardsList(context); @@ -524,6 +597,43 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O return index; } + protected static int getLexicalModelIndex(Context context, String lexicalModelKey) { + int index = -1; + + if (lexicalModelsList == null) { + lexicalModelsList = getLexicalModelsList(context); + } + + if (lexicalModelsList != null) { + int length = lexicalModelsList.size(); + for (int i=0; i < length; i++) { + HashMap lmInfo = lexicalModelsList.get(i); + String langId = lmInfo.get(KMManager.KMKey_LanguageID); + String pkgId = lmInfo.get(KMManager.KMKey_PackageID); + String lmId = lmInfo.get(KMManager.KMKey_LexicalModelID); + String lmKey = String.format("%s_%s_%s", langId, pkgId, lmId); + if (lmKey.equals(lexicalModelKey)) { + index = i; + break; + } + } + } + + return index; + } + + protected static HashMap getAssociatedLexicalModel(String langId) { + int length = lexicalModelsList.size(); + for( int i=0; i < length; i++) { + HashMap lmInfo = lexicalModelsList.get(i); + if (langId.equalsIgnoreCase(lmInfo.get(KMManager.KMKey_LanguageID))) { + return lmInfo; + } + } + + return null; + } + protected static HashMap getKeyboardInfo(Context context, int index) { if (index < 0) { return null; @@ -751,7 +861,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O index = getKeyboardIndex(this, kbKey); } keyboardsList.set(index, keyboardInfo); - saveKeyboardsList(this); + saveList(this, KMManager.KMFilename_KeyboardsList); } else if (result < 0) { failedUpdateCount++; } @@ -795,4 +905,9 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O public void onPackageInstalled(List> keyboardsInstalled) { // Do nothing } -} \ No newline at end of file + + @Override + public void onLexicalModelInstalled(List> lexicalModelsInstalled) { + // Do nothing + } +} diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java index 538c68e115..b14a6b1c40 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageListActivity.java @@ -164,6 +164,11 @@ public final class LanguageListActivity extends AppCompatActivity implements OnK // Do nothing. } + @Override + public void onLexicalModelInstalled(List> lexicalModelsInstalled) { + // Do nothing. + } + protected static HashMap getKeyboardInfo(int languageIndex, int keyboardIndex) { if (languages == null) return null; diff --git a/web/source/kmwembedded.ts b/web/source/kmwembedded.ts index 629216ff60..6ee0eb9294 100644 --- a/web/source/kmwembedded.ts +++ b/web/source/kmwembedded.ts @@ -351,12 +351,20 @@ namespace com.keyman.text { } }; + /** + * Register and enable lexical model + */ + keymanweb['registerModel']=function(model: com.keyman.text.prediction.ModelSpec) { + keymanweb.modelManager.register(model); + keymanweb.modelManager.enabled = true; + } + /** * Function called by iOS when a device-implemented keyboard popup is displayed or hidden * * @param {boolean} isVisible * - **/ + **/ keymanweb['popupVisible'] = function(isVisible) { osk.vkbd.popupVisible = isVisible; From 7ea8da554f1022b4802234b91b98d418cdcb1d84 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 26 Mar 2019 16:40:20 +0700 Subject: [PATCH 2/6] Add associated lexical model --- .../kmea/KMKeyboardDownloaderActivity.java | 21 ++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java index ca9def245a..d4f86f83c7 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardDownloaderActivity.java @@ -367,10 +367,16 @@ public class KMKeyboardDownloaderActivity extends AppCompatActivity { String pkgTarget = kmpProcessor.getPackageTarget(kmpFile); if (pkgTarget.equals(PackageProcessor.PP_TARGET_LEXICAL_MODELS)) { File unzipPath = kmpProcessor.unzipKMP(kmpFile); - // TODO: Propogate installedLexicalModels to KMW List> installedLexicalModels = kmpProcessor.processKMP(kmpFile, unzipPath, PackageProcessor.PP_LEXICAL_MODELS_KEY); + + boolean success = installedLexicalModels.size() != 0; + if (success) { + notifyLexicalModelInstallListeners(KeyboardEventHandler.EventType.LEXICAL_MODEL_INSTALLED, + installedLexicalModels, 1); + } } + } if (result < 0) { if (FileUtils.hasFontExtension(url)) { @@ -407,6 +413,19 @@ public class KMKeyboardDownloaderActivity extends AppCompatActivity { KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, eventType, keyboardInfo, result); } } + + /** + * Notify listeners when a lexical model is installed + * @param eventType + * @param models + * @param result + */ + protected void notifyLexicalModelInstallListeners(KeyboardEventHandler.EventType eventType, + List> models, int result) { + if (kbDownloadEventListeners != null) { + KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, eventType, models, result); + } + } } /** From 36f8edb875f55c168caa5735d0a991026d3d4157 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 27 Mar 2019 08:33:30 +0700 Subject: [PATCH 3/6] Remove unneeded enable Remove setting `modelManager.enable = true;` --- web/source/kmwembedded.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/web/source/kmwembedded.ts b/web/source/kmwembedded.ts index 6ee0eb9294..3e98bd613c 100644 --- a/web/source/kmwembedded.ts +++ b/web/source/kmwembedded.ts @@ -352,11 +352,12 @@ namespace com.keyman.text { }; /** - * Register and enable lexical model + * Register a lexical model + * + * @param {com.keyman.text.prediction.ModelSpec} model Spec of the lexical model */ keymanweb['registerModel']=function(model: com.keyman.text.prediction.ModelSpec) { keymanweb.modelManager.register(model); - keymanweb.modelManager.enabled = true; } /** From 8cea2e07d7d36895d583e7fe0ef5b3fc591bc43d Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 27 Mar 2019 10:37:10 +0700 Subject: [PATCH 4/6] Fix modelSpec passed for registration * Also read in lexical models list --- .../java/com/tavultesoft/kmea/KMManager.java | 22 ++++++++++--------- .../kmea/KeyboardPickerActivity.java | 13 ++++++----- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index ab3991e854..88fdfe45d8 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -656,25 +656,27 @@ public final class KMManager { String languageID = lexicalModelInfo.get(KMKey_LanguageID); String path = "file://" + getLexicalModelsDir() + pkgID + File.separator + modelID + ".model.js"; - JSONObject m = new JSONObject(); - JSONArray languageArray = new JSONArray(); + JSONObject modelObj = new JSONObject(); + JSONArray languageJSONArray = new JSONArray(); try { - m.put("id", modelID); - languageArray.put(languageID); - m.put("languages", languageArray); - m.put("path", path); + modelObj.put("id", modelID); + languageJSONArray.put(languageID); + modelObj.put("languages", languageJSONArray); + modelObj.put("path", path); } catch (JSONException e) { } - // Escape quotes for javascript call - String model = String.valueOf(m).replaceAll("\"", "\\\\\""); + // Use single quotes in JSONobject for javascript call + String model = String.valueOf(modelObj); + model = model.replaceAll("\"", "'"); + //model = "{'id': 'example.en.custom', 'languages': ['en'], 'path': 'file:///data/user/0/com.tavultesoft.kmapro.debug/app_data/models/example.en.custom.model/example.en.custom.model.js'}"; if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { - InAppKeyboard.loadUrl(String.format("javascript:registerModel('%s')", model)); + InAppKeyboard.loadUrl(String.format("javascript:registerModel(%s)", model)); } if (SystemKeyboard != null && SystemKeyboardLoaded && !SystemKeyboardShouldIgnoreTextChange) { - SystemKeyboard.loadUrl(String.format("javascript:registerModel('%s')", model)); + SystemKeyboard.loadUrl(String.format("javascript:registerModel(%s)", model)); } return true; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java index c2647accf1..389e313258 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardPickerActivity.java @@ -134,6 +134,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O } } + lexicalModelsList = getLexicalModelsList(context); if (lexicalModelsList == null) { lexicalModelsList = new ArrayList>(); @@ -623,11 +624,13 @@ public final class KeyboardPickerActivity extends AppCompatActivity implements O } protected static HashMap getAssociatedLexicalModel(String langId) { - int length = lexicalModelsList.size(); - for( int i=0; i < length; i++) { - HashMap lmInfo = lexicalModelsList.get(i); - if (langId.equalsIgnoreCase(lmInfo.get(KMManager.KMKey_LanguageID))) { - return lmInfo; + if (lexicalModelsList != null) { + int length = lexicalModelsList.size(); + for (int i = 0; i < length; i++) { + HashMap lmInfo = lexicalModelsList.get(i); + if (langId.equalsIgnoreCase(lmInfo.get(KMManager.KMKey_LanguageID))) { + return lmInfo; + } } } From 93a8c84de365e00d3d1e01fe3b8202061027652a Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 27 Mar 2019 13:35:54 +0700 Subject: [PATCH 5/6] log exception when model fails to register --- .../app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java | 4 ++++ .../app/src/main/java/com/tavultesoft/kmea/KMManager.java | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index b60612aed5..f88739f9f9 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -137,9 +137,13 @@ final class KMKeyboard extends WebView { Toast.makeText(context, "Fatal Error with " + currentKeyboard + ". Loading default keyboard", Toast.LENGTH_LONG).show(); + // TODO: Revert this after integration. + // Commented out to avoid infinite cycle of setting a keyboard, and throwing KMW registration errors + /* setKeyboard(KMManager.KMDefault_UndefinedPackageID, KMManager.KMDefault_KeyboardID, KMManager.KMDefault_LanguageID, KMManager.KMDefault_KeyboardName, KMManager.KMDefault_LanguageName, KMManager.KMDefault_KeyboardFont, null); + */ } return true; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index 88fdfe45d8..a86eff1343 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -664,7 +664,8 @@ public final class KMManager { modelObj.put("languages", languageJSONArray); modelObj.put("path", path); } catch (JSONException e) { - + Log.e(TAG, "Invalid lexical model to register"); + return false; } // Use single quotes in JSONobject for javascript call From 00a97a68c1d825b674e504c2b09132695f064be9 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Thu, 28 Mar 2019 15:53:07 +0700 Subject: [PATCH 6/6] Remove commented code --- .../app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java | 4 ---- .../app/src/main/java/com/tavultesoft/kmea/KMManager.java | 1 - 2 files changed, 5 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java index f88739f9f9..b60612aed5 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboard.java @@ -137,13 +137,9 @@ final class KMKeyboard extends WebView { Toast.makeText(context, "Fatal Error with " + currentKeyboard + ". Loading default keyboard", Toast.LENGTH_LONG).show(); - // TODO: Revert this after integration. - // Commented out to avoid infinite cycle of setting a keyboard, and throwing KMW registration errors - /* setKeyboard(KMManager.KMDefault_UndefinedPackageID, KMManager.KMDefault_KeyboardID, KMManager.KMDefault_LanguageID, KMManager.KMDefault_KeyboardName, KMManager.KMDefault_LanguageName, KMManager.KMDefault_KeyboardFont, null); - */ } return true; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java index a86eff1343..6b1bb0c7e5 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMManager.java @@ -671,7 +671,6 @@ public final class KMManager { // Use single quotes in JSONobject for javascript call String model = String.valueOf(modelObj); model = model.replaceAll("\"", "'"); - //model = "{'id': 'example.en.custom', 'languages': ['en'], 'path': 'file:///data/user/0/com.tavultesoft.kmapro.debug/app_data/models/example.en.custom.model/example.en.custom.model.js'}"; if (InAppKeyboard != null && InAppKeyboardLoaded && !InAppKeyboardShouldIgnoreTextChange) { InAppKeyboard.loadUrl(String.format("javascript:registerModel(%s)", model));