diff --git a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java index 0e4079411c..b2af765b8d 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java +++ b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/SystemKeyboard.java @@ -11,6 +11,7 @@ import com.tavultesoft.kmea.KMHardwareKeyboardInterpreter; import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener; import com.tavultesoft.kmea.LanguageSettingsActivity; import com.tavultesoft.kmea.R; +import com.tavultesoft.kmea.data.Keyboard; import android.content.Context; import android.content.SharedPreferences; @@ -28,8 +29,6 @@ import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; -import java.util.HashMap; - import io.sentry.android.core.SentryAndroid; import io.sentry.core.Sentry; @@ -139,9 +138,9 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven } else { // Check if predictions needs to be re-enabled per Settings preference Context appContext = getApplicationContext(); - HashMap kbInfo = KMManager.getCurrentKeyboardInfo(appContext); + Keyboard kbInfo = KMManager.getCurrentKeyboardInfo(appContext); if (kbInfo != null) { - String langId = kbInfo.get(KMManager.KMKey_LanguageID); + String langId = kbInfo.getLanguageID(); SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); boolean mayPredict = prefs.getBoolean(LanguageSettingsActivity.getLanguagePredictionPreferenceKey(langId), true); KMManager.setBannerOptions(mayPredict); diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java index bf09d44a46..077ac5a2af 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/GetStartedActivity.java @@ -10,6 +10,7 @@ import java.util.List; import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.KMPBrowserActivity; +import com.tavultesoft.kmea.data.Keyboard; import android.os.Bundle; import android.provider.Settings; @@ -156,7 +157,7 @@ public class GetStartedActivity extends AppCompatActivity { String checkbox_on = String.valueOf(android.R.drawable.checkbox_on_background); String info = String.valueOf(R.drawable.ic_info_outline); - ArrayList> kbList = KMManager.getKeyboardsList(this); + List kbList = KMManager.getKeyboardsList(this); if (kbList != null && kbList.size() > 1) { list.get(0).put(iconKey, checkbox_on); } else { 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 14368bc21d..8e46c07696 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 @@ -25,6 +25,7 @@ import com.tavultesoft.kmea.KMTextView; import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener; import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener; import com.tavultesoft.kmea.cloud.CloudApiTypes; +import com.tavultesoft.kmea.data.Keyboard; import com.tavultesoft.kmea.packages.PackageProcessor; import com.tavultesoft.kmea.util.FileUtils; import com.tavultesoft.kmea.util.FileProviderUtils; @@ -195,19 +196,10 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi // Add default keyboard boolean installDefaultKeyboard = prefs.getBoolean(defaultKeyboardInstalled, false); if (!installDefaultKeyboard) { - HashMap kbInfo = new HashMap(); - kbInfo.put(KMManager.KMKey_PackageID, KMManager.KMDefault_PackageID); - kbInfo.put(KMManager.KMKey_KeyboardID, KMManager.KMDefault_KeyboardID); - kbInfo.put(KMManager.KMKey_LanguageID, KMManager.KMDefault_LanguageID); - kbInfo.put(KMManager.KMKey_KeyboardName, KMManager.KMDefault_KeyboardName); - kbInfo.put(KMManager.KMKey_LanguageName, KMManager.KMDefault_LanguageName); - kbInfo.put(KMManager.KMKey_KeyboardVersion, - KMManager.getLatestKeyboardFileVersion(context, KMManager.KMDefault_PackageID, KMManager.KMDefault_KeyboardID)); - kbInfo.put(KMManager.KMKey_Font, KMManager.KMDefault_KeyboardFont); - File welcomeFile = new File(KMManager.getPackagesDir(), KMManager.KMDefault_PackageID + File.separator + FileUtils.WELCOME_HTM); - kbInfo.put(KMManager.KMKey_CustomHelpLink, welcomeFile.getPath()); - KMManager.addKeyboard(this, kbInfo); - + if (!KMManager.keyboardExists(context, KMManager.KMDefault_PackageID, KMManager.KMDefault_KeyboardID, + KMManager.KMDefault_LanguageID)) { + KMManager.addKeyboard(this, Keyboard.DEFAULT_KEYBOARD); + } SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(defaultKeyboardInstalled, true); editor.commit(); @@ -315,7 +307,6 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi } if (!didFail) { - KMManager.updateOldKeyboardsList(this); SharedPreferences prefs = getSharedPreferences(getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); editor.putBoolean(MainActivity.didCheckUserDataKey, true); @@ -837,7 +828,7 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi boolean showGetStarted = prefs.getBoolean(GetStartedActivity.showGetStartedKey, true); if (showGetStarted) { boolean shouldShowGetStarted = false; - ArrayList> kbList = KMManager.getKeyboardsList(this); + List kbList = KMManager.getKeyboardsList(this); if (kbList != null && kbList.size() < 2) shouldShowGetStarted = true; @@ -1074,17 +1065,22 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi @Override public void onPackageInstalled(List> keyboardsInstalled) { for(int i=0; i < keyboardsInstalled.size(); i++) { - HashMap keyboardInfo = new HashMap<>(keyboardsInstalled.get(i)); + HashMap hashMap = new HashMap<>(keyboardsInstalled.get(i)); + Keyboard keyboardInfo = new Keyboard( + hashMap.get(KMManager.KMKey_PackageID), + hashMap.get(KMManager.KMKey_KeyboardID), + hashMap.get(KMManager.KMKey_KeyboardName), + hashMap.get(KMManager.KMKey_LanguageID), + hashMap.get(KMManager.KMKey_LanguageName), + hashMap.get(KMManager.KMKey_Version), + hashMap.get(KMManager.KMKey_HelpLink), + true, + hashMap.get(KMManager.KMKey_Font), + hashMap.get(KMManager.KMKey_OskFont)); + if (i == 0) { if (KMManager.addKeyboard(this, keyboardInfo)) { - String packageID = keyboardInfo.get(KMManager.KMKey_PackageID); - String keyboardID = keyboardInfo.get(KMManager.KMKey_KeyboardID); - String languageID = keyboardInfo.get(KMManager.KMKey_LanguageID); - String keyboardName = keyboardInfo.get(KMManager.KMKey_KeyboardName); - String languageName = keyboardInfo.get(KMManager.KMKey_LanguageName); - String kFont = keyboardInfo.get(KMManager.KMKey_Font); - String kOskFont = keyboardInfo.get(KMManager.KMKey_OskFont); - KMManager.setKeyboard(packageID, keyboardID, languageID, keyboardName, languageName, kFont, kOskFont); + KMManager.setKeyboard(keyboardInfo); } } else { KMManager.addKeyboard(this, keyboardInfo); @@ -1095,7 +1091,7 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi @Override public void onLexicalModelInstalled(List> lexicalModelsInstalled) { String langId = (KMManager.getCurrentKeyboardInfo(this) != null) ? - KMManager.getCurrentKeyboardInfo(this).get(KMManager.KMKey_LanguageID) : + KMManager.getCurrentKeyboardInfo(this).getLanguageID() : KMManager.KMDefault_LanguageID; boolean matchingModel = false; diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java index 38bc4a0364..17b8d3fee8 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ConfirmDialogFragment.java @@ -8,6 +8,7 @@ import android.os.Bundle; import android.widget.Toast; import com.tavultesoft.kmea.cloud.CloudApiTypes; +import com.tavultesoft.kmea.data.KeyboardController; import java.util.ArrayList; @@ -110,7 +111,7 @@ public class ConfirmDialogFragment extends DialogFragment { break; case DIALOG_TYPE_DELETE_KEYBOARD : // Confirmation to delete keyboard - int keyboardIndex = KeyboardPickerActivity.getKeyboardIndex(getActivity(), itemKey); + int keyboardIndex = KeyboardController.getInstance().getKeyboardIndex(itemKey); KeyboardPickerActivity.deleteKeyboard(getActivity(), keyboardIndex); dismissOnSelect = true; break; 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 a7a28ff2d2..21e8c3e98a 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 @@ -7,11 +7,14 @@ package com.tavultesoft.kmea; import java.io.File; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; +import com.tavultesoft.kmea.data.Keyboard; +import com.tavultesoft.kmea.data.KeyboardController; import com.tavultesoft.kmea.KMManager.KeyboardType; import com.tavultesoft.kmea.KeyboardEventHandler.EventType; import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener; @@ -149,9 +152,14 @@ final class KMKeyboard extends WebView { Toast.makeText(context, "Fatal Error with " + currentKeyboard + ". Loading default keyboard", Toast.LENGTH_LONG).show(); - setKeyboard(KMManager.KMDefault_PackageID, KMManager.KMDefault_KeyboardID, - KMManager.KMDefault_LanguageID, KMManager.KMDefault_KeyboardName, - KMManager.KMDefault_LanguageName, KMManager.KMDefault_KeyboardFont, null); + Keyboard firstKeyboard = KeyboardController.getInstance().getKeyboardInfo(0); + if (firstKeyboard != null) { + // Revert to first keyboard in the list + setKeyboard(firstKeyboard); + } else { + // Fallback to sil_euro_latin (though 3rd party keyboards wont have it) + setKeyboard(Keyboard.DEFAULT_KEYBOARD); + } } return true; @@ -604,6 +612,22 @@ final class KMKeyboard extends WebView { return retVal; } + public boolean setKeyboard(Keyboard k) { + boolean retVal = false; + if (k != null) { + retVal = setKeyboard( + k.getPackageID(), + k.getKeyboardID(), + k.getLanguageID(), + k.getKeyboardName(), + k.getLanguageName(), + k.getFont(), + k.getOSKFont()); + } + + return retVal; + } + public void setChirality(boolean flag) { this.isChiral = flag; } @@ -1212,7 +1236,7 @@ final class KMKeyboard extends WebView { if (KMManager.getGlobeKeyAction(keyboardType) == KMManager.GlobeKeyAction.GLOBE_KEY_ACTION_SWITCH_TO_NEXT_KEYBOARD) { // Help bubble is disabled if next keyboard is not available for this action - ArrayList> keyboardsList = KMManager.getKeyboardsList(context); + List keyboardsList = KMManager.getKeyboardsList(context); if (keyboardsList == null) { return; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardPickerAdapter.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardPickerAdapter.java index 738c22637d..6718247a17 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardPickerAdapter.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KMKeyboardPickerAdapter.java @@ -21,6 +21,7 @@ import android.widget.TextView; import com.tavultesoft.kmea.data.Dataset; import com.tavultesoft.kmea.data.Keyboard; +import com.tavultesoft.kmea.data.KeyboardController; import com.tavultesoft.kmea.data.adapters.AdapterFilter; import com.tavultesoft.kmea.data.adapters.NestedAdapter; import com.tavultesoft.kmea.util.FileUtils; @@ -43,32 +44,9 @@ final class KMKeyboardPickerAdapter extends NestedAdapter() { - // Yeah, so this is a MASSIVE hack. Right now, it's either this or refactor up to 60 - // separate references to keyboardList within KeyboardPickerActivity. Yikes. public List selectFrom(Dataset.Keyboards adapter, Void dummy) { - List> kbdMapList = KeyboardPickerActivity.getKeyboardsList(context); - List kbdList = new ArrayList<>(kbdMapList.size()); - - for(HashMap kbdMap: kbdMapList) { - boolean isNewKeyboard = kbdMap.containsKey(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD) && - kbdMap.get(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD).equals(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD); - - Keyboard k = new Keyboard( - kbdMap.get(KMManager.KMKey_PackageID), - kbdMap.get(KMManager.KMKey_KeyboardID), - kbdMap.get(KMManager.KMKey_KeyboardName), - kbdMap.get(KMManager.KMKey_LanguageID), - kbdMap.get(KMManager.KMKey_LanguageName), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_Version, "1.0"), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_CustomHelpLink, ""), - isNewKeyboard, - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_Font, null), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_OskFont, null) - ); - kbdList.add(k); - } - - return kbdList; + // Return the keyboards list + return adapter.asList(); } }, null); } @@ -91,7 +69,7 @@ final class KMKeyboardPickerAdapter extends NestedAdapter> kbList = KeyboardPickerActivity.getKeyboardsList(context); - if (kbList != null && kbList.size() > 0) { - boolean shouldUpdateList = false; - boolean shouldClearCache = false; - HashMap kbInfo = kbList.get(0); - String pkgID = kbInfo.get(KMKey_PackageID); - String kbID = kbInfo.get(KMKey_KeyboardID); - if ( kbID.equals("us") || kbID.equals("european2") || - (pkgID.equals(KMDefault_UndefinedPackageID) && kbID.equals(KMDefault_KeyboardID)) ) { - HashMap newKbInfo = new HashMap(); - newKbInfo.put(KMManager.KMKey_PackageID, KMManager.KMDefault_PackageID); - newKbInfo.put(KMManager.KMKey_KeyboardID, KMManager.KMDefault_KeyboardID); - newKbInfo.put(KMManager.KMKey_LanguageID, KMManager.KMDefault_LanguageID); - newKbInfo.put(KMManager.KMKey_KeyboardName, KMManager.KMDefault_KeyboardName); - newKbInfo.put(KMManager.KMKey_LanguageName, KMManager.KMDefault_LanguageName); - newKbInfo.put(KMManager.KMKey_KeyboardVersion, - getLatestKeyboardFileVersion(context, KMManager.KMDefault_PackageID, - KMManager.KMDefault_KeyboardID)); - newKbInfo.put(KMManager.KMKey_Font, KMManager.KMDefault_KeyboardFont); - kbList.set(0, newKbInfo); - shouldUpdateList = true; - shouldClearCache = true; - } - - int index2Remove = -1; - int kblCount = kbList.size(); - for (int i = 0; i < kblCount; i++) { - kbInfo = kbList.get(i); - - kbID = kbInfo.get(KMKey_KeyboardID); - pkgID = kbInfo.get(KMKey_PackageID); - if (pkgID == null || pkgID.isEmpty()) { - pkgID = KMDefault_UndefinedPackageID; - kbInfo.put(KMManager.KMKey_PackageID, pkgID); - shouldUpdateList = true; - } - String langID = kbInfo.get(KMKey_LanguageID); - String kbVersion = kbInfo.get(KMManager.KMKey_KeyboardVersion); - String latestKbVersion = getLatestKeyboardFileVersion(context, pkgID, kbID); - if ((latestKbVersion != null) && (kbVersion == null || !kbVersion.equals(latestKbVersion))) { - kbInfo.put(KMManager.KMKey_KeyboardVersion, latestKbVersion); - kbList.set(i, kbInfo); - shouldUpdateList = true; - } - - if (kbID.equals(KMManager.KMDefault_KeyboardID) && langID.equals(KMManager.KMDefault_LanguageID)) { - int defKbIndex = KMManager.getKeyboardIndex(context, KMManager.KMDefault_KeyboardID, KMManager.KMDefault_LanguageID); - if (defKbIndex == 0 && i > 0) - index2Remove = i; - } - } - - if (index2Remove > 0) { - kbList.remove(index2Remove); - SharedPreferences prefs = appContext.getSharedPreferences(appContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); - SharedPreferences.Editor editor = prefs.edit(); - int index = prefs.getInt(KMManager.KMKey_UserKeyboardIndex, 0); - if (index == index2Remove) { - index = 0; - } else if (index > index2Remove) { - index--; - } - editor.putInt(KMManager.KMKey_UserKeyboardIndex, index); - editor.commit(); - shouldUpdateList = true; - } - - if (shouldUpdateList) { - KeyboardPickerActivity.updateKeyboardsList(context, kbList); - } - - if (shouldClearCache) { - File cache = CloudDataJsonUtil.getKeyboardCacheFile(appContext); - if (cache.exists()) { - cache.delete(); - } - } - } - } - /** * Sets mayPredictOverride true if the InputType field is a hidden password text field * (either TYPE_TEXT_VARIATION_PASSWORD or TYPE_TEXT_VARIATION_WEB_PASSWORD @@ -835,7 +754,7 @@ public final class KMManager { return font; } - public static ArrayList> getKeyboardsList(Context context) { + public static List getKeyboardsList(Context context) { return KeyboardPickerActivity.getKeyboardsList(context); } @@ -963,9 +882,10 @@ public final class KMManager { return null; } - public static boolean addKeyboard(Context context, HashMap keyboardInfo) { - String packageID = keyboardInfo.get(KMManager.KMKey_PackageID); - String keyboardID = keyboardInfo.get(KMManager.KMKey_KeyboardID); + public static boolean addKeyboard(Context context, Keyboard keyboardInfo) { + String packageID = keyboardInfo.getPackageID(); + String keyboardID = keyboardInfo.getKeyboardID(); + keyboardInfo.setNewKeyboard(true); // Log Sentry analytic event, ignoring default keyboard if (Sentry.isEnabled() && !(packageID.equalsIgnoreCase(KMManager.KMDefault_PackageID) && @@ -974,12 +894,12 @@ public final class KMManager { breadcrumb.setMessage("KMManager.addKeyboard"); breadcrumb.setCategory("addKeyboard"); breadcrumb.setLevel(SentryLevel.INFO); - breadcrumb.setData("packageID", keyboardInfo.get(KMManager.KMKey_PackageID)); - breadcrumb.setData("keyboardID", keyboardInfo.get(KMManager.KMKey_KeyboardID)); - breadcrumb.setData("keyboardName", keyboardInfo.get(KMManager.KMKey_KeyboardName)); - breadcrumb.setData("keyboardVersion", keyboardInfo.get(KMManager.KMKey_KeyboardVersion)); - breadcrumb.setData("languageID", keyboardInfo.get(KMManager.KMKey_LanguageID)); - breadcrumb.setData("languageName", keyboardInfo.get(KMManager.KMKey_LanguageName)); + breadcrumb.setData("packageID", packageID); + breadcrumb.setData("keyboardID", keyboardID); + breadcrumb.setData("keyboardName", keyboardInfo.getKeyboardName()); + breadcrumb.setData("keyboardVersion", keyboardInfo.getVersion()); + breadcrumb.setData("languageID", keyboardInfo.getLanguageID()); + breadcrumb.setData("languageName", keyboardInfo.getLanguageName()); Sentry.addBreadcrumb(breadcrumb); @@ -990,6 +910,25 @@ public final class KMManager { return KeyboardPickerActivity.addKeyboard(context, keyboardInfo); } + // Intend to deprecate in Keyman 15.0 + public static boolean addKeyboard(Context context, HashMap keyboardInfo) { + String packageID = keyboardInfo.get(KMManager.KMKey_PackageID); + String keyboardID = keyboardInfo.get(KMManager.KMKey_KeyboardID); + String keyboardName = keyboardInfo.get(KMManager.KMKey_KeyboardName); + String languageID = keyboardInfo.get(KMManager.KMKey_LanguageID); + String languageName = keyboardInfo.get(KMManager.KMKey_LanguageName); + String version = keyboardInfo.get(KMManager.KMKey_KeyboardVersion); + String helpLink = keyboardInfo.get(KMManager.KMKey_CustomHelpLink); + String font = keyboardInfo.get(KMManager.KMKey_Font); + String oskFont = keyboardInfo.get(KMManager.KMKey_OskFont); + boolean isNewKeyboard = true; + + Keyboard k = new Keyboard(packageID, keyboardID, keyboardName, + languageID, languageName, version, helpLink, + isNewKeyboard, font, oskFont); + return addKeyboard(context, k); + } + public static boolean removeKeyboard(Context context, int position) { return KeyboardPickerActivity.removeKeyboard(context, position); } @@ -1007,6 +946,24 @@ public final class KMManager { return (result1 || result2); } + public static boolean setKeyboard(Keyboard keyboardInfo) { + boolean result1 = false; + boolean result2 = false; + + if (InAppKeyboard != null && InAppKeyboardLoaded && keyboardInfo != null) { + result1 = InAppKeyboard.setKeyboard(keyboardInfo); + } + + if (SystemKeyboard != null && SystemKeyboardLoaded && keyboardInfo != null) + result2 = SystemKeyboard.setKeyboard(keyboardInfo); + + if (keyboardInfo != null) { + registerAssociatedLexicalModel(keyboardInfo.getLanguageID()); + } + + return (result1 || result2); + } + /** * Prepare keyboard switch for inapp keyboard and systemkeyboard * @param packageID the package id @@ -1064,42 +1021,28 @@ public final class KMManager { } public static boolean setKeyboard(Context context, int position) { - HashMap keyboardInfo = getKeyboardInfo(context, position); + Keyboard keyboardInfo = getKeyboardInfo(context, position); if (keyboardInfo == null) return false; - String pkgId = keyboardInfo.get(KMManager.KMKey_PackageID); - String kbId = keyboardInfo.get(KMManager.KMKey_KeyboardID); - String langId = keyboardInfo.get(KMManager.KMKey_LanguageID); - String kbName = keyboardInfo.get(KMManager.KMKey_KeyboardName); - String langName = keyboardInfo.get(KMManager.KMKey_LanguageName); - String kFont = keyboardInfo.get(KMManager.KMKey_Font); - String kOskFont = keyboardInfo.get(KMManager.KMKey_OskFont); - return setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + return setKeyboard(keyboardInfo); } public static void switchToNextKeyboard(Context context) { - int index = KeyboardPickerActivity.getCurrentKeyboardIndex(context); + int index = KeyboardController.getInstance().getKeyboardIndex(KMKeyboard.currentKeyboard()); index++; - HashMap kbInfo = KeyboardPickerActivity.getKeyboardInfo(context, index); + Keyboard kbInfo = KeyboardController.getInstance().getKeyboardInfo(index); if (kbInfo == null) { index = 0; - kbInfo = KeyboardPickerActivity.getKeyboardInfo(context, index); + kbInfo = KeyboardController.getInstance().getKeyboardInfo(index); } - String pkgId = kbInfo.get(KMManager.KMKey_PackageID); - String kbId = kbInfo.get(KMManager.KMKey_KeyboardID); - String langId = kbInfo.get(KMManager.KMKey_LanguageID); - String kbName = kbInfo.get(KMManager.KMKey_KeyboardName); - String langName = kbInfo.get(KMManager.KMKey_LanguageName); - String kFont = kbInfo.get(KMManager.KMKey_Font); - String kOskFont = kbInfo.get(KMManager.KMKey_OskFont); if (InAppKeyboard != null) { - InAppKeyboard.setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + InAppKeyboard.setKeyboard(kbInfo); } if (SystemKeyboard != null) { - SystemKeyboard.setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + SystemKeyboard.setKeyboard(kbInfo); } } @@ -1452,26 +1395,28 @@ public final class KMManager { } public static int getCurrentKeyboardIndex(Context context) { - return KeyboardPickerActivity.getCurrentKeyboardIndex(context); + String key = KMKeyboard.currentKeyboard(); + return KeyboardController.getInstance().getKeyboardIndex(key); } - public static HashMap getCurrentKeyboardInfo(Context context) { - return KeyboardPickerActivity.getCurrentKeyboardInfo(context); + public static Keyboard getCurrentKeyboardInfo(Context context) { + int index = getCurrentKeyboardIndex(context); + return KeyboardController.getInstance().getKeyboardInfo(index); } public static int getKeyboardIndex(Context context, String keyboardID, String languageID) { - int index = -1; + int index = KeyboardController.INDEX_NOT_FOUND; if (keyboardID != null & languageID != null) { String kbKey = String.format("%s_%s", languageID, keyboardID); - index = KeyboardPickerActivity.getKeyboardIndex(context, kbKey); + index = KeyboardController.getInstance().getKeyboardIndex(kbKey); } return index; } - public static HashMap getKeyboardInfo(Context context, int index) { - return KeyboardPickerActivity.getKeyboardInfo(context, index); + public static Keyboard getKeyboardInfo(Context context, int index) { + return KeyboardController.getInstance().getKeyboardInfo(index); } public static HashMap getLexicalModelInfo(Context context, int index) { @@ -1483,7 +1428,7 @@ public final class KMManager { if (packageID != null && keyboardID != null && languageID != null) { String kbKey = String.format("%s_%s", languageID, keyboardID); - result = KeyboardPickerActivity.containsKeyboard(context, kbKey); + result = KeyboardController.getInstance().keyboardExists(kbKey); } return result; @@ -1588,7 +1533,6 @@ public final class KMManager { } private void pageLoaded(WebView view, String url) { - String langId = KMManager.KMKey_LanguageID; Log.d("KMEA", "pageLoaded: [inapp] " + url); if (url.startsWith("file")) { //endsWith(KMFilename_KeyboardHtml)) { InAppKeyboardLoaded = true; @@ -1599,22 +1543,17 @@ public final class KMManager { if (index < 0) { index = 0; } - HashMap keyboardInfo = KMManager.getKeyboardInfo(context, index); + Keyboard keyboardInfo = KMManager.getKeyboardInfo(context, index); + String langId; if (keyboardInfo != null) { - String pkgId = keyboardInfo.get(KMManager.KMKey_PackageID); - String kbId = keyboardInfo.get(KMManager.KMKey_KeyboardID); - langId = keyboardInfo.get(KMManager.KMKey_LanguageID); - String kbName = keyboardInfo.get(KMManager.KMKey_KeyboardName); - String langName = keyboardInfo.get(KMManager.KMKey_LanguageName); - String kFont = keyboardInfo.get(KMManager.KMKey_Font); - String kOskFont = keyboardInfo.get(KMManager.KMKey_OskFont); - InAppKeyboard.setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + langId = keyboardInfo.getLanguageID(); + InAppKeyboard.setKeyboard(keyboardInfo); } else { - InAppKeyboard.setKeyboard(KMDefault_PackageID, KMDefault_KeyboardID, - KMDefault_LanguageID, KMDefault_KeyboardName, KMDefault_LanguageName, KMDefault_KeyboardFont, null); + langId = KMDefault_LanguageID; + InAppKeyboard.setKeyboard(Keyboard.DEFAULT_KEYBOARD); } - registerAssociatedLexicalModel(langId); + registerAssociatedLexicalModel(langId); } Handler handler = new Handler(); @@ -1816,7 +1755,6 @@ public final class KMManager { } private void pageLoaded(WebView view, String url) { - String langId = KMManager.KMKey_LanguageID; Log.d("KMEA", "pageLoaded: [system] " + url); if (url.startsWith("file:")) { SystemKeyboardLoaded = true; @@ -1826,23 +1764,19 @@ public final class KMManager { if (index < 0) { index = 0; } - HashMap keyboardInfo = KMManager.getKeyboardInfo(context, index); + Keyboard keyboardInfo = KMManager.getKeyboardInfo(context, index); + String langId; if (keyboardInfo != null) { - String pkgId = keyboardInfo.get(KMManager.KMKey_PackageID); - String kbId = keyboardInfo.get(KMManager.KMKey_KeyboardID); - langId = keyboardInfo.get(KMManager.KMKey_LanguageID); - String kbName = keyboardInfo.get(KMManager.KMKey_KeyboardName); - String langName = keyboardInfo.get(KMManager.KMKey_LanguageName); - String kFont = keyboardInfo.get(KMManager.KMKey_Font); - String kOskFont = keyboardInfo.get(KMManager.KMKey_OskFont); - SystemKeyboard.setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + langId = keyboardInfo.getLanguageID(); + SystemKeyboard.setKeyboard(keyboardInfo); } else { - SystemKeyboard.setKeyboard(KMDefault_UndefinedPackageID, KMDefault_KeyboardID, - KMDefault_LanguageID, KMDefault_KeyboardName, KMDefault_LanguageName, KMDefault_KeyboardFont, null); + langId = KMDefault_LanguageID; + SystemKeyboard.setKeyboard(Keyboard.DEFAULT_KEYBOARD); } + + registerAssociatedLexicalModel(langId); } - registerAssociatedLexicalModel(langId); Handler handler = new Handler(); handler.postDelayed(new Runnable() { 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 edb415d880..2be277ab31 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 @@ -18,6 +18,7 @@ import com.tavultesoft.kmea.cloud.CloudDataJsonUtil; import com.tavultesoft.kmea.data.CloudRepository; import com.tavultesoft.kmea.data.Dataset; import com.tavultesoft.kmea.data.Keyboard; +import com.tavultesoft.kmea.data.KeyboardController; import com.tavultesoft.kmea.data.LexicalModel; import com.tavultesoft.kmea.util.MapCompat; @@ -26,6 +27,7 @@ import androidx.appcompat.app.AlertDialog; import android.content.Context; import android.content.Intent; import android.graphics.Typeface; +//import android.inputmethodservice.Keyboard; import android.os.Bundle; import android.util.Log; import android.view.MenuItem; @@ -52,9 +54,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { public static final String KMKEY_INTERNAL_NEW_KEYBOARD = "_internal_new_keyboard_"; - // TODO: Refactoring to remove keyboard selection into own keyboard manager class (MVC) - // Lists of installed keyboards and installed lexical models - private static ArrayList> keyboardsList = null; + // List of installed lexical models private static ArrayList> lexicalModelsList = null; private static Dataset storageDataset = null; @@ -62,7 +62,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { private static int selectedIndex = 0; private static final String TAG = "KeyboardPickerActivity"; - protected static int selectedIndex() { + public static int selectedIndex() { return selectedIndex; } @@ -105,29 +105,6 @@ public final class KeyboardPickerActivity extends AppCompatActivity { listView = (ListView) findViewById(R.id.listView); - //TODO: put into a logic class - keyboardsList = getKeyboardsList(context); - if (keyboardsList == null) { - keyboardsList = new ArrayList>(); - HashMap kbInfo = new HashMap(); - kbInfo.put(KMManager.KMKey_PackageID, KMManager.KMDefault_PackageID); - kbInfo.put(KMManager.KMKey_KeyboardID, KMManager.KMDefault_KeyboardID); - kbInfo.put(KMManager.KMKey_LanguageID, KMManager.KMDefault_LanguageID); - kbInfo.put(KMManager.KMKey_KeyboardName, KMManager.KMDefault_KeyboardName); - kbInfo.put(KMManager.KMKey_LanguageName, KMManager.KMDefault_LanguageName); - kbInfo.put(KMManager.KMKey_KeyboardVersion, KMManager.getLatestKeyboardFileVersion( - context, KMManager.KMDefault_PackageID, KMManager.KMDefault_KeyboardID)); - kbInfo.put(KMManager.KMKey_Font, KMManager.KMDefault_KeyboardFont); - 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); - if (!file.exists()) { - saveList(context, KMManager.KMFilename_KeyboardsList); - } - } - lexicalModelsList = getLexicalModelsList(context); if (lexicalModelsList == null) { lexicalModelsList = new ArrayList>(); @@ -157,6 +134,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { listView.setOnItemLongClickListener(new OnItemLongClickListener() { @Override public boolean onItemLongClick(AdapterView parent, View view, final int position, long id) { + // Prevent the default keyboard from being removed if (position > 0 && canRemoveKeyboard) { PopupMenu popup = new PopupMenu(context, view); popup.getMenuInflater().inflate(R.menu.popup, popup.getMenu()); @@ -178,7 +156,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { } }); - int curKbPos = getCurrentKeyboardIndex(); + int curKbPos = KeyboardController.getInstance().getKeyboardIndex(KMKeyboard.currentKeyboard()); setSelection(curKbPos); KMKeyboard.addOnKeyboardEventListener(new KeyboardEventHandler.OnKeyboardEventListener() { @@ -189,16 +167,23 @@ public final class KeyboardPickerActivity extends AppCompatActivity { @Override public void onKeyboardChanged(String newKeyboard) { - int _index = getKeyboardIndex(context,newKeyboard); + int _index = KeyboardController.getInstance().getKeyboardIndex(newKeyboard); if(_index>=0) { - Map _keyboard = keyboardsList.get(_index); - if(_keyboard==null) + Keyboard _keyboard = KeyboardController.getInstance().getKeyboardInfo(_index); + if(_keyboard==null) { return; - if(_keyboard.get(KMKEY_INTERNAL_NEW_KEYBOARD)==null) + } + if(!_keyboard.getNewKeyboard()) { return; - _keyboard.remove(KMKEY_INTERNAL_NEW_KEYBOARD); - saveList(context, KMManager.KMFilename_KeyboardsList); + } + + if (_keyboard.getNewKeyboard()) { + _keyboard.setNewKeyboard(false); + // Update entry + KeyboardController.getInstance().add(_keyboard); + KeyboardController.getInstance().save(context); + } notifyKeyboardsUpdate(context); } } @@ -223,7 +208,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { adapter.notifyDataSetChanged(); } - int curKbPos = getCurrentKeyboardIndex(); + int curKbPos = KeyboardController.getInstance().getKeyboardIndex(KMKeyboard.currentKeyboard()); setSelection(curKbPos); if (!shouldCheckKeyboardUpdates) return; @@ -252,41 +237,9 @@ public final class KeyboardPickerActivity extends AppCompatActivity { finish(); } - private static int getCurrentKeyboardIndex() { - int pos = 0; - - if (keyboardsList != null) { - int length = keyboardsList.size(); - for (int i = 0; i < length; i++) { - HashMap kbInfo = keyboardsList.get(i); - String langId = kbInfo.get(KMManager.KMKey_LanguageID); - String kbId = kbInfo.get(KMManager.KMKey_KeyboardID); - String kbKey = String.format("%s_%s", langId, kbId); - if (kbKey.equals(KMKeyboard.currentKeyboard())) { - pos = i; - break; - } - } - } - - return pos; - } - - // Previously, keyboard from package = custom keyboard - // Now, keyboard from package has a package ID != "cloud" - protected static boolean hasKeyboardFromPackage() { - for(HashMap kbInfo: keyboardsList) { - String pkgID = MapCompat.getOrDefault(kbInfo, KMManager.KMKey_PackageID, KMManager.KMDefault_UndefinedPackageID); - if (!pkgID.equalsIgnoreCase(KMManager.KMDefault_UndefinedPackageID)) { - return true; - } - } - - return false; - } - private static boolean saveList(Context context, String listName) { boolean result; + List keyboardsList = KeyboardController.getInstance().get(); try { File file = new File(context.getDir("userdata", Context.MODE_PRIVATE), listName); ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file)); @@ -306,20 +259,6 @@ public final class KeyboardPickerActivity extends AppCompatActivity { return result; } - /** - * Save the list of installed keyboards - * @param context - * @param list - * @return boolean - Status if the keyboard list was successfully saved - */ - protected static boolean updateKeyboardsList(Context context, ArrayList> list) { - boolean result; - keyboardsList = list; - result = saveList(context, KMManager.KMFilename_KeyboardsList); - notifyKeyboardsUpdate(context); - return result; - } - /** * Save the list of installed lexical models * @param context @@ -347,65 +286,35 @@ public final class KeyboardPickerActivity extends AppCompatActivity { */ private static void switchKeyboard(int position, boolean aPrepareOnly) { setSelection(position); - int listPosition = (position >= keyboardsList.size()) ? keyboardsList.size()-1 : position; - HashMap kbInfo = keyboardsList.get(listPosition); - String pkgId = kbInfo.get(KMManager.KMKey_PackageID); - if (pkgId == null || pkgId.isEmpty()) { - pkgId = KMManager.KMDefault_UndefinedPackageID; - } - String kbId = kbInfo.get(KMManager.KMKey_KeyboardID); - String langId = kbInfo.get(KMManager.KMKey_LanguageID); - String kbName = kbInfo.get(KMManager.KMKey_KeyboardName); - String langName = kbInfo.get(KMManager.KMKey_LanguageName); - String kFont = kbInfo.get(KMManager.KMKey_Font); - String kOskFont = kbInfo.get(KMManager.KMKey_OskFont); + int size = KeyboardController.getInstance().get().size(); + int listPosition = (position >= size) ? size-1 : position; + Keyboard kbInfo = KeyboardController.getInstance().getKeyboardInfo(listPosition); + String pkgId = kbInfo.getPackageID(); + String kbId = kbInfo.getKeyboardID(); + String langId = kbInfo.getLanguageID(); + String kbName = kbInfo.getKeyboardName(); if(aPrepareOnly) KMManager.prepareKeyboardSwitch(pkgId, kbId, langId, kbName); else - KMManager.setKeyboard(pkgId, kbId, langId, kbName, langName, kFont, kOskFont); + KMManager.setKeyboard(kbInfo); } - protected static boolean addKeyboard(Context context, HashMap keyboardInfo) { + protected static boolean addKeyboard(Context context, Keyboard keyboardInfo) { boolean result = false; - - if (keyboardsList == null) { - keyboardsList = getKeyboardsList(context); - } - - if (keyboardsList == null) { - keyboardsList = new ArrayList>(); - } + List keyboardsList = KeyboardController.getInstance().get(); if (keyboardInfo != null) { - String pkgID = keyboardInfo.get(KMManager.KMKey_PackageID); - String kbID = keyboardInfo.get(KMManager.KMKey_KeyboardID); - String langID = keyboardInfo.get(KMManager.KMKey_LanguageID); - // TODO: Possible optimization - do we have anything with this language code already? // Only invalidate the lexical cache if not. CloudRepository.shared.invalidateLexicalModelCache(context); - if (pkgID != null && kbID != null && langID != null) { - String kbKey = String.format("%s_%s", langID, kbID); - if (kbKey.length() >= 3) { - int x = getKeyboardIndex(context, kbKey); - if (x >= 0) { - if(keyboardsList.get(x).get(KMKEY_INTERNAL_NEW_KEYBOARD)!=null) - keyboardInfo.put(KMKEY_INTERNAL_NEW_KEYBOARD,KMKEY_INTERNAL_NEW_KEYBOARD); - keyboardsList.set(x, keyboardInfo); - result = saveList(context, KMManager.KMFilename_KeyboardsList); - } else { - keyboardInfo.put(KMKEY_INTERNAL_NEW_KEYBOARD,KMKEY_INTERNAL_NEW_KEYBOARD); - keyboardsList.add(keyboardInfo); - result = saveList(context, KMManager.KMFilename_KeyboardsList); - if (!result) { - keyboardsList.remove(keyboardsList.size() - 1); - } - } - } + keyboardInfo.setNewKeyboard(true); + KeyboardController.getInstance().add(keyboardInfo); + result = KeyboardController.getInstance().save(context); + if (!result) { + Log.e(TAG, "addKeyboard failed to save"); } } - notifyKeyboardsUpdate(context); return result; @@ -453,13 +362,11 @@ public final class KeyboardPickerActivity extends AppCompatActivity { protected static boolean removeKeyboard(Context context, int position) { boolean result = false; - if (keyboardsList == null) { - keyboardsList = getKeyboardsList(context); - } - if (keyboardsList != null && position >= 0 && position < keyboardsList.size()) { - keyboardsList.remove(position); - result = saveList(context, KMManager.KMFilename_KeyboardsList); + // Prevent the first keyboard (index 0) from being removed + if (position > 0) { + KeyboardController.getInstance().remove(position); + result = KeyboardController.getInstance().save(context); } notifyKeyboardsUpdate(context); @@ -468,7 +375,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { } protected static void deleteKeyboard(Context context, int position) { - int curKbPos = getCurrentKeyboardIndex(); + int curKbPos = KeyboardController.getInstance().getKeyboardIndex(KMKeyboard.currentKeyboard()); boolean result = removeKeyboard(context, position); if (result) { @@ -480,7 +387,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { if (position == curKbPos && listView != null) { switchKeyboard(0,false); } else if(listView != null) { // A bit of a hack, since LanguageSettingsActivity calls this method too. - curKbPos = getCurrentKeyboardIndex(); + curKbPos = KeyboardController.getInstance().getKeyboardIndex(KMKeyboard.currentKeyboard()); setSelection(curKbPos); } } @@ -577,31 +484,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { return storageDataset; } - List> kbdMapList = getKeyboardsList(context); - if (kbdMapList == null) { - kbdMapList = new ArrayList<>(0); - } - List kbdsList = new ArrayList<>(kbdMapList.size()); - - for(HashMap kbdMap: kbdMapList) { - boolean isNewKeyboard = kbdMap.containsKey(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD) && - kbdMap.get(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD).equals(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD); - - Keyboard k = new Keyboard( - kbdMap.get(KMManager.KMKey_PackageID), - kbdMap.get(KMManager.KMKey_KeyboardID), - kbdMap.get(KMManager.KMKey_KeyboardName), - kbdMap.get(KMManager.KMKey_LanguageID), - kbdMap.get(KMManager.KMKey_LanguageName), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_Version, "1.0"), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_CustomHelpLink, ""), - isNewKeyboard, - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_Font, null), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_OskFont, null) - ); - kbdsList.add(k); - } - + List kbdsList = getKeyboardsList(context); List> lexMapList = getLexicalModelsList(context); if(lexMapList == null) { lexMapList = new ArrayList<>(0); @@ -636,26 +519,7 @@ public final class KeyboardPickerActivity extends AppCompatActivity { storage.keyboards.setNotifyOnChange(false); storage.keyboards.clear(); - List> mapList = getKeyboardsList(context); - List kbdList = new ArrayList<>(mapList.size()); - for(HashMap kbdMap: mapList) { - boolean isNewKeyboard = kbdMap.containsKey(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD) && - kbdMap.get(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD).equals(KeyboardPickerActivity.KMKEY_INTERNAL_NEW_KEYBOARD); - - Keyboard k = new Keyboard( - kbdMap.get(KMManager.KMKey_PackageID), - kbdMap.get(KMManager.KMKey_KeyboardID), - kbdMap.get(KMManager.KMKey_KeyboardName), - kbdMap.get(KMManager.KMKey_LanguageID), - kbdMap.get(KMManager.KMKey_LanguageName), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_Version, "1.0"), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_CustomHelpLink, ""), - isNewKeyboard, - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_Font, null), - MapCompat.getOrDefault(kbdMap, KMManager.KMKey_OskFont, null) - ); - kbdList.add(k); - } + List kbdList = KeyboardController.getInstance().get(); storage.keyboards.addAll(kbdList); storage.keyboards.notifyDataSetChanged(); } @@ -684,33 +548,14 @@ public final class KeyboardPickerActivity extends AppCompatActivity { storage.lexicalModels.notifyDataSetChanged(); } - protected static ArrayList> getKeyboardsList(Context context) { - return getList(context, KMManager.KMFilename_KeyboardsList); + protected static List getKeyboardsList(Context context) { + return KeyboardController.getInstance().get(); } 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); - } - - String kbKeys = ""; - if (keyboardsList != null) { - int length = keyboardsList.size(); - for (int i = 0; i < length; i++) { - kbKeys += String.format("%s_%s", keyboardsList.get(i).get(KMManager.KMKey_LanguageID), keyboardsList.get(i).get(KMManager.KMKey_KeyboardID)); - if (i < length - 1) { - kbKeys += ","; - } - } - } - - return kbKeys.contains(keyboardKey); - } - public static boolean containsLexicalModel(Context context, String lexicalModelKey) { if (lexicalModelsList == null) { lexicalModelsList = getLexicalModelsList(context); @@ -731,84 +576,6 @@ public final class KeyboardPickerActivity extends AppCompatActivity { return false; } - protected static int getCurrentKeyboardIndex(Context context) { - int index = -1; - - if (keyboardsList == null) { - keyboardsList = getKeyboardsList(context); - } - - if (keyboardsList != null) { - int length = keyboardsList.size(); - for (int i = 0; i < length; i++) { - HashMap kbInfo = keyboardsList.get(i); - String langId = kbInfo.get(KMManager.KMKey_LanguageID); - String kbId = kbInfo.get(KMManager.KMKey_KeyboardID); - String kbKey = String.format("%s_%s", langId, kbId); - if (kbKey.equals(KMKeyboard.currentKeyboard())) { - index = i; - break; - } - } - } - - return index; - } - - protected static HashMap getCurrentKeyboardInfo(Context context) { - int index = getCurrentKeyboardIndex(context); - if (index >= 0) { - return keyboardsList.get(index); - } else { - return null; - } - } - - protected static int getKeyboardIndex(Context context, String keyboardKey) { - int index = -1; - - if (keyboardsList == null) { - keyboardsList = getKeyboardsList(context); - } - - if (keyboardsList != null) { - int length = keyboardsList.size(); - for (int i = 0; i < length; i++) { - HashMap kbInfo = keyboardsList.get(i); - String langId = kbInfo.get(KMManager.KMKey_LanguageID); - String kbId = kbInfo.get(KMManager.KMKey_KeyboardID); - String kbKey = String.format("%s_%s", langId, kbId); - if (kbKey.equals(keyboardKey)) { - index = i; - break; - } - } - } - - return index; - } - - /** - * Get the list of associated keyboards for a given language ID - * @param langId - * @return ArrayList of keyboard - */ - public static ArrayList> getAssociatedKeyboards(String langId) { - if (keyboardsList != null) { - ArrayList> associatedKeyboards = new ArrayList>(); - for (HashMap keyboardInfo: keyboardsList) { - if (keyboardInfo.get(KMManager.KMKey_LanguageID).equalsIgnoreCase(langId)) { - keyboardInfo.put(KMManager.KMKey_Icon, String.valueOf(R.drawable.ic_arrow_forward)); - keyboardInfo.put("isEnabled", "true"); - associatedKeyboards.add(keyboardInfo); - } - } - return associatedKeyboards; - } - - return null; - } - /** * Get the index of a lexical model key in the list of installed lexical models. * @param context @@ -840,27 +607,6 @@ public final class KeyboardPickerActivity extends AppCompatActivity { return index; } - protected static HashMap getKeyboardInfo(Context context, int index) { - if (index < 0) { - return null; - } - - if (keyboardsList == null) { - keyboardsList = getKeyboardsList(context); - } - - if (keyboardsList != null && index < keyboardsList.size()) { - HashMap kbInfo = keyboardsList.get(index); - String pkgID = kbInfo.get(KMManager.KMKey_PackageID); - if (pkgID == null || pkgID.isEmpty()) { - kbInfo.put(KMManager.KMKey_PackageID, KMManager.KMDefault_UndefinedPackageID); - } - return kbInfo; - } - - return null; - } - protected static HashMap getLexicalModelInfo(Context context,int index) { if (index < 0) { return null; @@ -884,16 +630,19 @@ public final class KeyboardPickerActivity extends AppCompatActivity { } public static void handleDownloadedKeyboard(Context context, HashMap keyboardInfo) { - String keyboardID = keyboardInfo.get(KMManager.KMKey_KeyboardID); - String languageID = keyboardInfo.get(KMManager.KMKey_LanguageID); - String kbKey = String.format("%s_%s", languageID, keyboardID); - int index = getKeyboardIndex(context, kbKey); - if (index == -1) { - // Add the downloaded keyboard if not found - addKeyboard(context, keyboardInfo); - index = getKeyboardIndex(context, kbKey); - } - keyboardsList.set(index, keyboardInfo); - saveList(context, KMManager.KMFilename_KeyboardsList); + boolean isNewKeyboard = true; + Keyboard k = new Keyboard( + keyboardInfo.get(KMManager.KMKey_PackageID), + keyboardInfo.get(KMManager.KMKey_KeyboardID), + keyboardInfo.get(KMManager.KMKey_KeyboardName), + keyboardInfo.get(KMManager.KMKey_LanguageID), + keyboardInfo.get(KMManager.KMKey_LanguageName), + keyboardInfo.get(KMManager.KMKey_KeyboardVersion), + keyboardInfo.get(KMManager.KMKey_HelpLink), + isNewKeyboard, + keyboardInfo.get(KMManager.KMKey_Font), + keyboardInfo.get(KMManager.KMKey_OskFont)); + KeyboardController.getInstance().add(k); + KeyboardController.getInstance().save(context); } } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardSettingsActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardSettingsActivity.java index f88a36ea1b..67f5210c50 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardSettingsActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/KeyboardSettingsActivity.java @@ -123,9 +123,8 @@ public final class KeyboardSettingsActivity extends AppCompatActivity { hashMap.put(iconKey, icon); infoList.add(hashMap); - // Display uninstall keyboard - if (!packageID.equalsIgnoreCase(KMManager.KMDefault_PackageID) || - !kbID.equalsIgnoreCase(KMManager.KMDefault_KeyboardID)) { + // If not default keyboard, display uninstall keyboard + if (!kbID.equalsIgnoreCase(KMManager.KMDefault_KeyboardID)) { hashMap = new HashMap<>(); hashMap.put(titleKey, getString(R.string.uninstall_keyboard)); hashMap.put(subtitleKey, ""); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageSettingsActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageSettingsActivity.java index b9b834f366..1beb70c8cb 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageSettingsActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/LanguageSettingsActivity.java @@ -90,7 +90,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity { } // If the active keyboard is for this language, immediately enact the new pref setting. - String kbdLgCode = KMManager.getCurrentKeyboardInfo(context).get(KMManager.KMKey_LanguageID); + String kbdLgCode = KMManager.getCurrentKeyboardInfo(context).getLanguageID(); if (kbdLgCode.equals(lgCode)) { // Not only registers the model but also applies our modeling preferences. KMManager.registerAssociatedLexicalModel(lgCode); diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java index bfc1d5cf73..daf77aabfb 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/ModelPickerActivity.java @@ -177,7 +177,7 @@ public final class ModelPickerActivity extends AppCompatActivity { if(immediateRegister) { // Register associated lexical model if it matches the active keyboard's language code; // it's safe since we're on the same thread. Needs to be called AFTER deinstalling the old one. - String kbdLgCode = KMManager.getCurrentKeyboardInfo(context).get(KMManager.KMKey_LanguageID); + String kbdLgCode = KMManager.getCurrentKeyboardInfo(context).getLanguageID(); if(kbdLgCode.equals(languageID)) { KMManager.registerAssociatedLexicalModel(languageID); } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/Keyboard.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/Keyboard.java index a9f3850e2b..12a37c87ea 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/Keyboard.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/Keyboard.java @@ -86,7 +86,8 @@ public class Keyboard extends LanguageResource implements Serializable { public String getKeyboardID() { return getResourceID(); } public String getKeyboardName() { return getResourceName(); } - public boolean isNewKeyboard() { return isNewKeyboard; } + public boolean getNewKeyboard() { return isNewKeyboard; } + public void setNewKeyboard(boolean isNewKeyboard) { this.isNewKeyboard = isNewKeyboard; } public String getFont() { return font; } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/KeyboardController.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/KeyboardController.java index aa9cd00908..b3097fdf14 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/KeyboardController.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/KeyboardController.java @@ -27,6 +27,7 @@ import java.util.List; public class KeyboardController { public static final String TAG = "KeyboardController"; public static final String KMFilename_Installed_KeyboardsList = "keyboards_list.json"; + public static final int INDEX_NOT_FOUND = -1; private static KeyboardController instance; @@ -105,13 +106,14 @@ public class KeyboardController { list.add(Keyboard.DEFAULT_KEYBOARD); } } else { - // No installed keyboards lists so assume default - // TODO: What about 3rd-party apps w/o sil_euro_latin? - list.add(Keyboard.DEFAULT_KEYBOARD); + // No installed keyboards lists + // 3rd-party OEM may not have sil_euro_latin, so don't assign a default keyboard + //list.add(Keyboard.DEFAULT_KEYBOARD); + Log.w(TAG, "initialize with no default keyboard"); } // We'd prefer not to overwrite a file if it exists - if (!keyboards_json.exists()) { + if (!keyboards_json.exists() && list != null && list.size() > 0) { save(context); } @@ -129,7 +131,9 @@ public class KeyboardController { Log.e(TAG, "get while KeyboardController() not initialized"); return null; } - return list; + synchronized (list) { + return list; + } } /** @@ -146,18 +150,58 @@ public class KeyboardController { return null; } - if (list != null && index < list.size()) { - Keyboard k = list.get(index); - return k; + synchronized (list) { + if (list != null && index < list.size()) { + Keyboard k = list.get(index); + return k; + } } Log.e(TAG, "getKeyboardInfo failed with index " + index); return null; } + /** + * Given a key, return the index of the matching keyboard. + * If no match, returns INDEX_NOT_FOUND + * @param key - String of the key to find + * @return int - Index of the matching keyboard + */ + public int getKeyboardIndex(String key) { + int index = INDEX_NOT_FOUND; + if (!isInitialized || list == null) { + Log.e(TAG, "getIndexOfKey while KeyboardController() not initialized"); + return index; + } + if (key == null || key.isEmpty()) { + return index; + } + + synchronized (list) { + for (int i=0; i The type specification of the Adapter to be nested/linked. */ public class NestedAdapter & ListBacked, FilterArg> extends ArrayAdapter implements ListBacked { + private final static String TAG = "NestedAdapter"; final A wrappedAdapter; final AdapterFilter filter; final List filteredList; @@ -173,11 +175,19 @@ public class NestedAdapter & ListBacked // These methods allow bypassing of our externally-visible 'linking' versions for operations // triggered by the other end of the link. protected void _internalAddAll(@NonNull Collection collection) { - super.addAll(collection); + try { + super.addAll(collection); + } catch (UnsupportedOperationException e) { + Log.e(TAG, "_internalAddAll exception " + e); + } } protected void _internalClear() { - super.clear(); + try { + super.clear(); + } catch (UnsupportedOperationException e) { + Log.e(TAG, "_internalClear exception " + e); + } } // TODO: As needed, override mutation functions so that we can reflect the changes onto diff --git a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/FunctionalTestHelper.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/FunctionalTestHelper.java index ba9996f81a..e6b8008f30 100644 --- a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/FunctionalTestHelper.java +++ b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/FunctionalTestHelper.java @@ -9,6 +9,7 @@ import android.util.Log; import androidx.test.core.app.ApplicationProvider; import com.tavultesoft.kmea.KMManager; +import com.tavultesoft.kmea.data.Keyboard; import com.tavultesoft.kmea.packages.PackageProcessor; import com.tavultesoft.kmea.util.FileUtils; @@ -48,12 +49,7 @@ class FunctionalTestHelper { */ static void setInitialKeyboard() { - KMManager.setKeyboard(KMManager.KMDefault_PackageID, - KMManager.KMDefault_KeyboardID, - KMManager.KMDefault_LanguageID, - KMManager.KMDefault_KeyboardName, - KMManager.KMDefault_LanguageName, - KMManager.KMDefault_KeyboardFont, null); + KMManager.setKeyboard(Keyboard.DEFAULT_KEYBOARD); } /** diff --git a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/KeyboardPickerTest.java b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/KeyboardPickerTest.java index 2007ed276b..21fcec27cc 100644 --- a/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/KeyboardPickerTest.java +++ b/android/KMEA/app/src/test/java/com/tavultesoft/kmea/view/KeyboardPickerTest.java @@ -2,6 +2,7 @@ package com.tavultesoft.kmea.view; import android.content.Intent; +import android.util.Log; import android.view.View; import android.widget.ListView; @@ -11,6 +12,7 @@ import com.tavultesoft.kmea.KMManager; import com.tavultesoft.kmea.KeyboardInfoActivity; import com.tavultesoft.kmea.KeyboardPickerActivity; import com.tavultesoft.kmea.R; +import com.tavultesoft.kmea.data.Keyboard; import org.json.JSONException; import org.junit.After; @@ -34,6 +36,7 @@ public class KeyboardPickerTest { private static final File TEST_RESOURCE_ROOT = new File("test_resources"); + private static final File TEST_DEFAULT_KMP_FILE = new File(TEST_RESOURCE_ROOT, "v14" + File.separator + "sil_euro_latin.kmp"); private static final String TEST_GFF_KMP_NAME = "gff_amh_7_test_json"; private static final File TEST_GFF_KMP_FILE = new File(TEST_RESOURCE_ROOT, "v14" + File.separator + TEST_GFF_KMP_NAME + ".kmp"); @@ -50,6 +53,14 @@ public class KeyboardPickerTest { //initializes the keyboard picker (and keyboard list in background) keyboardPickerActivityActivityController = Robolectric.buildActivity(KeyboardPickerActivity.class).setup(); + +// install new custom keyboard programmatically + try { + FunctionalTestHelper.installCustomKeyboard(TEST_DEFAULT_KMP_FILE); + } catch (IOException | JSONException e) { + Log.e("KeyboardPickerTest", "Exception installing default kmp"); + } + //Initial keyboard load (normally done by webview) // should be done directly in FunctionalTestHelper.initializeKeyman(); // but we need to initialize the keyboardpicker first, because auf initialization process @@ -102,10 +113,6 @@ public class KeyboardPickerTest { { KeyboardPickerActivity activity = keyboardPickerActivityActivityController.get(); - // get current keyboard - Map _old = KMManager.getCurrentKeyboardInfo(ApplicationProvider.getApplicationContext()); - Assert.assertNotNull(_old); - // install new custom keyboard programmatically FunctionalTestHelper.installCustomKeyboard(TEST_GFF_KMP_FILE); @@ -122,10 +129,9 @@ public class KeyboardPickerTest { Assert.assertTrue(activity.isFinishing()); // check if keyboardswitch is done - Map _current = KMManager.getCurrentKeyboardInfo(ApplicationProvider.getApplicationContext()); + int index = KeyboardPickerActivity.selectedIndex(); + Keyboard _current = KMManager.getKeyboardInfo(ApplicationProvider.getApplicationContext(), index); Assert.assertNotNull(_current); - - Assert.assertNotEquals(_old.get(KMManager.KMKey_KeyboardID),_current.get(KMManager.KMKey_KeyboardID)); } /** @@ -151,7 +157,8 @@ public class KeyboardPickerTest { Assert.assertNotNull(_view); // click the info button to open keyboard info activity - View _itemview = _view.getAdapter().getView(1, null, null); + int expectedKeyboardID = 0; // Index for expected keyboard + View _itemview = _view.getAdapter().getView(expectedKeyboardID, null, null); Assert.assertNotNull(_itemview); _itemview.findViewById(R.id.imageButton1).performClick(); @@ -169,7 +176,7 @@ public class KeyboardPickerTest { Assert.assertNotNull(_infolistview); //find helplink and click - View _helplink = _view.getAdapter().getView(1, null, null); + View _helplink = _view.getAdapter().getView(expectedKeyboardID, null, null); Assert.assertNotNull(_helplink); _infolistview.performItemClick(_helplink,1,_infolistview.getAdapter().getItemId(1)); diff --git a/android/KMEA/test_resources/v14/sil_euro_latin.kmp b/android/KMEA/test_resources/v14/sil_euro_latin.kmp new file mode 100644 index 0000000000..8f5c57f8e1 Binary files /dev/null and b/android/KMEA/test_resources/v14/sil_euro_latin.kmp differ diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java index cefba8d28a..fd58a912ff 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/FVShared.java @@ -7,6 +7,8 @@ import android.content.res.AssetManager; import android.net.Uri; import android.util.Log; import com.tavultesoft.kmea.KMManager; +import com.tavultesoft.kmea.data.Keyboard; + import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; @@ -19,6 +21,7 @@ import java.io.ObjectOutputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; final class FVShared { private static FVShared instance = null; @@ -224,7 +227,7 @@ final class FVShared { private void updateActiveKeyboardsList() { // Clear existing active keyboards list - ArrayList> activeKbList = KMManager.getKeyboardsList(context); + List activeKbList = KMManager.getKeyboardsList(context); if (activeKbList != null) { int len = activeKbList.size(); for (int i = len-1; i >= 0; i--) @@ -236,15 +239,18 @@ final class FVShared { for(FVKeyboard keyboard : region.keyboards) { if(loadedKeyboards.contains(keyboard.id)) { // Load the .keyboard_info file and find its first language code - HashMap kbInfo = new HashMap<>(); - kbInfo.put(KMManager.KMKey_PackageID, FVDefault_PackageID); //TODO: we want to share keyboard build scripts between ios and android; can we do this? - kbInfo.put(KMManager.KMKey_KeyboardID, keyboard.id); - kbInfo.put(KMManager.KMKey_LanguageID, "en"); //TODO: use language code from kmp.json - kbInfo.put(KMManager.KMKey_KeyboardName, keyboard.name); - kbInfo.put(KMManager.KMKey_LanguageName, keyboard.name); - kbInfo.put(KMManager.KMKey_KeyboardVersion, "1.0"); //TODO: use keyboard version from kmp.json - kbInfo.put(KMManager.KMKey_Font, "NotoSansCanadianAboriginal.ttf"); - kbInfo.put(KMManager.KMKey_CustomHelpLink, String.format("%s%s", FVKeyboardHelpLink, keyboard.id)); + Keyboard kbInfo = new Keyboard( + FVDefault_PackageID, //TODO: we want to share keyboard build scripts between ios and android; can we do this? + keyboard.id, + keyboard.name, + "en", //TODO: use language code from kmp.json + keyboard.name, + "1.0", //TODO: use keyboard version from kmp.json + String.format("%s%s", FVKeyboardHelpLink, keyboard.id), + false, + "NotoSansCanadianAboriginal.ttf", + "NotoSansCanadianAboriginal.ttf"); + KMManager.addKeyboard(context, kbInfo); } }