diff --git a/android/KMAPro/kMAPro/src/main/assets/banner.html b/android/KMAPro/kMAPro/src/main/assets/banner.html new file mode 100644 index 00000000000..41107f11424 --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/assets/banner.html @@ -0,0 +1,11 @@ + +
+ + + + + +
+
+
+
diff --git a/android/KMAPro/kMAPro/src/main/assets/banner/keyman_banner.svg b/android/KMAPro/kMAPro/src/main/assets/banner/keyman_banner.svg new file mode 100644 index 00000000000..3888a0937f9 --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/assets/banner/keyman_banner.svg @@ -0,0 +1,372 @@ + + + + image/svg+xml diff --git a/android/KMAPro/kMAPro/src/main/java/com/keyman/android/BannerController.java b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/BannerController.java new file mode 100644 index 00000000000..f716faa9aab --- /dev/null +++ b/android/KMAPro/kMAPro/src/main/java/com/keyman/android/BannerController.java @@ -0,0 +1,29 @@ +package com.keyman.android; + +import android.content.Context; + +import com.keyman.engine.KMManager; +import com.keyman.engine.util.FileUtils; + +import java.io.File; + +public class BannerController { + + // Paths relative to assets folder for banner themes + public static final String KM_BANNER_DIR = "banner"; + public static final String KM_BANNER_THEME_KEYMAN = "banner.html"; + + public static void setHTMLBanner(Context context, KMManager.KeyboardType keyboardType) { + if (keyboardType == KMManager.KeyboardType.KEYBOARD_TYPE_UNDEFINED) { + return; + } + + KMManager.copyHTMLBannerAssets(context, KM_BANNER_DIR); + + // Always use Keyman banner theme + String contents = FileUtils.readContents(context, KM_BANNER_THEME_KEYMAN); + KMManager.setHTMLBanner(keyboardType, contents); + KMManager.setBanner(keyboardType, KMManager.BannerType.HTML); + KMManager.showBanner(true); + } +} 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 697825094bf..cf919deddb4 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 @@ -6,6 +6,7 @@ import com.tavultesoft.kmapro.BuildConfig; import com.tavultesoft.kmapro.KeymanSettingsActivity; +import com.keyman.android.BannerController; import com.keyman.engine.KMManager; import com.keyman.engine.KMManager.KeyboardType; import com.keyman.engine.KMHardwareKeyboardInterpreter; @@ -71,6 +72,9 @@ public void onCreate() { KMManager.SpacebarText spacebarText = KMManager.SpacebarText.fromString(prefs.getString(KeymanSettingsActivity.spacebarTextKey, KMManager.SpacebarText.LANGUAGE_KEYBOARD.toString())); KMManager.setSpacebarText(spacebarText); + // Set the system keyboard HTML banner + BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM); + boolean mayHaveHapticFeedback = prefs.getBoolean(KeymanSettingsActivity.hapticFeedbackKey, false); KMManager.setHapticFeedback(mayHaveHapticFeedback); @@ -93,6 +97,9 @@ public void onDestroy() { @Override public void onInitializeInterface() { super.onInitializeInterface(); + + // KeymanWeb reloaded, so we have to pass the banner again + BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM); } /** 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 6b92d4c2eb5..16899f7c2d9 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 @@ -18,6 +18,7 @@ import java.util.Map; import com.keyman.android.CheckInstallReferrer; +import com.keyman.android.BannerController; import com.keyman.engine.BaseActivity; import com.keyman.engine.KMHelpFileActivity; import com.keyman.engine.KMKeyboardDownloaderActivity; @@ -499,6 +500,8 @@ public void onKeyboardChanged(String newKeyboard) { @Override public void onKeyboardShown() { + // Refresh banner theme + BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_INAPP); resizeTextView(true); } diff --git a/android/KMEA/app/src/main/assets/android-host.js b/android/KMEA/app/src/main/assets/android-host.js index afa2825e33d..7930c76f11f 100644 --- a/android/KMEA/app/src/main/assets/android-host.js +++ b/android/KMEA/app/src/main/assets/android-host.js @@ -8,6 +8,9 @@ if(window.parent && window.parent.jsInterface && !window.jsInterface) { var device = window.jsInterface.getDeviceType(); var oskHeight = Math.ceil(window.jsInterface.getKeyboardHeight() / window.devicePixelRatio); var oskWidth = 0; +var bannerHeight = 0; +var bannerImagePath = ''; +var bannerHTMLContents = ''; var fragmentToggle = 0; var sentryManager = new KeymanSentryManager({ @@ -37,11 +40,13 @@ function init() { oninserttext: insertText, root:'./' }).then(function () { // Note: For non-upgraded API 21, arrow functions will break the keyboard! - const bannerHeight = Math.ceil(window.jsInterface.getDefaultBannerHeight() / window.devicePixelRatio); + bannerHeight = Math.ceil(window.jsInterface.getDefaultBannerHeight() / window.devicePixelRatio); + if (bannerHeight > 0) { - // The OSK is not available until initialization is complete. - keyman.osk.bannerView.activeBannerHeight = bannerHeight; - keyman.refreshOskLayout(); + // The OSK is not available until initialization is complete. + keyman.osk.bannerView.activeBannerHeight = bannerHeight; + keyman.refreshOskLayout(); + } }); keyman.addEventListener('keyboardloaded', setIsChiral); @@ -53,6 +58,29 @@ function init() { notifyHost('pageLoaded'); } +function showBanner(flag) { + console_debug("Setting banner display for dictionaryless keyboards to " + flag); + console_debug("bannerHTMLContents: " + bannerHTMLContents); + var bc = keyman.osk.bannerController; + if (bc) { + if (bannerHTMLContents != '') { + bc.inactiveBanner = flag ? new bc.HTMLBanner(bannerHTMLContents) : null; + } else { + bc.inactiveBanner = flag ? new bc.ImageBanner(bannerImagePath) : null; + } + } +} + +function setBannerImage(path) { + bannerImagePath = path; +} + +// Set the HTML banner to use when predictive-text is not available +// contents - HTML content to use for the banner +function setBannerHTML(contents) { + bannerHTMLContents = contents; +} + function notifyHost(event, params) { console_debug('notifyHost(event='+event+',params='+params+')'); // TODO: Update all other host notifications to use notifyHost instead of directly setting window.location.hash @@ -65,12 +93,19 @@ function notifyHost(event, params) { } // Update the KMW banner height +// h is in dpi (different from iOS) function setBannerHeight(h) { if (h > 0) { - var osk = keyman.osk; - osk.banner.height = Math.ceil(h / window.devicePixelRatio); + // The banner itself may not be loaded yet. This will preemptively help set + // its eventual display height. + bannerHeight = Math.ceil(h / window.devicePixelRatio); + + if (keyman.osk) { + keyman.osk.bannerView.activeBannerHeight = bannerHeight; + } } - // Refresh KMW OSK + + // Refresh KMW's OSK keyman.refreshOskLayout(); } diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java index 6471e875101..215630cd03d 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java @@ -7,13 +7,11 @@ 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.keyman.engine.BaseActivity; import com.keyman.engine.data.Keyboard; import com.keyman.engine.data.KeyboardController; import com.keyman.engine.KMManager.KeyboardType; @@ -25,19 +23,11 @@ import com.keyman.engine.util.KMLog; import com.keyman.engine.util.KMString; -import android.Manifest; import android.annotation.SuppressLint; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; import android.content.res.Configuration; -import android.graphics.Color; -import android.graphics.Rect; -import android.graphics.RectF; -import android.graphics.Typeface; -import android.os.Build; -import android.os.Bundle; import android.os.Handler; import android.util.DisplayMetrics; import android.util.Log; @@ -46,7 +36,6 @@ import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; -import android.view.ViewGroup; import android.view.WindowManager; import android.view.inputmethod.ExtractedText; import android.view.inputmethod.ExtractedTextRequest; @@ -56,12 +45,9 @@ import android.webkit.WebSettings; import android.webkit.WebView; import android.widget.Button; -import android.widget.FrameLayout; -import android.widget.GridLayout; import android.widget.PopupWindow; import android.widget.PopupWindow.OnDismissListener; import android.widget.RelativeLayout; -import android.widget.TextView; import android.widget.Toast; import io.sentry.Breadcrumb; @@ -84,19 +70,10 @@ final class KMKeyboard extends WebView { private static String currentKeyboard = null; - /** - * Banner state value: "blank" - no banner available. - */ - protected static final String KM_BANNER_STATE_BLANK = "blank"; - /** - * Banner state value: "suggestion" - dictionary suggestions are shown. - */ - protected static final String KM_BANNER_STATE_SUGGESTION = "suggestion"; - /** * Current banner state. */ - protected static String currentBanner = KM_BANNER_STATE_BLANK; + protected static KMManager.BannerType currentBanner = KMManager.BannerType.HTML; private static String txtFont = ""; private static String oskFont = null; @@ -105,6 +82,10 @@ final class KMKeyboard extends WebView { private GestureDetector gestureDetector; private static ArrayList kbEventListeners = null; + // Stores the current html string for use by the Banner + // when predictive text is not active + protected String htmlBannerString = ""; + // Facilitates a 'lazy init' - we'll only check the preference when it matters, // rather than at construction time. private Boolean _shouldShowHelpBubble = null; @@ -400,6 +381,9 @@ public void onConfigurationChanged(Configuration newConfig) { int bannerHeight = KMManager.getBannerHeight(context); int oskHeight = KMManager.getKeyboardHeight(context); + if (this.htmlBannerString != null && !this.htmlBannerString.isEmpty()) { + setHTMLBanner(this.htmlBannerString); + } loadJavascript(KMString.format("setBannerHeight(%d)", bannerHeight)); loadJavascript(KMString.format("setOskWidth(%d)", newConfig.screenWidthDp)); loadJavascript(KMString.format("setOskHeight(%d)", oskHeight)); @@ -425,22 +409,15 @@ public static String currentKeyboard() { return currentKeyboard; } - public static void setCurrentBanner(String banner) { - currentBanner = banner; - } - - public static String currentBanner() { return currentBanner; } - protected void toggleSuggestionBanner(HashMap associatedLexicalModel, boolean keyboardChanged) { //reset banner state if new language has no lexical model - if (currentBanner != null && currentBanner.equals(KM_BANNER_STATE_SUGGESTION) + if (currentBanner == KMManager.BannerType.SUGGESTION && associatedLexicalModel == null) { - setCurrentBanner(KMKeyboard.KM_BANNER_STATE_BLANK); + currentBanner = KMManager.BannerType.HTML; } - if(keyboardChanged) { - setLayoutParams(KMManager.getKeyboardLayoutParams()); - } + showBanner(true); + // Since there's always a banner, no need to update setLayoutParams() } /** @@ -653,6 +630,30 @@ public boolean setKeyboard(String packageID, String keyboardID, String languageI return retVal; } + public void showBanner(boolean flag) { + String jsString = KMString.format("showBanner(%b)", flag); + loadJavascript(jsString); + } + + public KMManager.BannerType getBanner() { + return currentBanner; + } + + public void setBanner(KMManager.BannerType bannerType) { + currentBanner = bannerType; + } + + public String getHTMLBanner() { + return this.htmlBannerString; + } + + public void setHTMLBanner(String contents) { + this.htmlBannerString = contents; + String jsString = KMString.format("setBannerHTML(%s)", + JSONObject.quote(this.htmlBannerString)); + loadJavascript(jsString); + } + public void setChirality(boolean flag) { this.isChiral = flag; } diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboardWebViewClient.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboardWebViewClient.java index e7188a94f96..4d458bd0616 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboardWebViewClient.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboardWebViewClient.java @@ -173,8 +173,7 @@ public boolean shouldOverrideUrlLoading(WebView view, String url) { if (KMManager.currentLexicalModel != null) { modelPredictionPref = prefs.getBoolean(KMManager.getLanguagePredictionPreferenceKey(KMManager.currentLexicalModel.get(KMManager.KMKey_LanguageID)), true); } - kmKeyboard.setCurrentBanner((isModelActive && modelPredictionPref) ? - KMKeyboard.KM_BANNER_STATE_SUGGESTION : KMKeyboard.KM_BANNER_STATE_BLANK); + KMManager.setBannerOptions(isModelActive && modelPredictionPref); RelativeLayout.LayoutParams params = KMManager.getKeyboardLayoutParams(); kmKeyboard.setLayoutParams(params); } else if (url.indexOf("suggestPopup") >= 0) { diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java index cbcb28053a1..df90f1d869d 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java @@ -25,32 +25,21 @@ import android.content.pm.PackageManager; import android.content.res.AssetManager; import android.content.res.Configuration; -import android.graphics.Bitmap; -import android.graphics.RectF; import android.graphics.Typeface; import android.inputmethodservice.InputMethodService; import android.net.ConnectivityManager; import android.net.NetworkInfo; -import android.net.Uri; import android.os.Build; -import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.text.InputType; import android.util.Log; -import android.view.HapticFeedbackConstants; -import android.view.KeyEvent; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.view.inputmethod.EditorInfo; -import android.view.inputmethod.ExtractedText; -import android.view.inputmethod.ExtractedTextRequest; import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethodManager; -import android.webkit.JavascriptInterface; import android.webkit.WebView; -import android.webkit.WebViewClient; import android.widget.FrameLayout; import android.widget.RelativeLayout; @@ -71,7 +60,6 @@ import com.keyman.engine.packages.LexicalModelPackageProcessor; import com.keyman.engine.packages.PackageProcessor; import com.keyman.engine.util.BCP47; -import com.keyman.engine.util.CharSequenceUtil; import com.keyman.engine.util.DependencyUtil; import com.keyman.engine.util.DependencyUtil.LibraryType; import com.keyman.engine.util.FileUtils; @@ -157,6 +145,34 @@ public String toString() { } }; + // Maps to enum BannerType in bannerView.ts + public enum BannerType { + BLANK, + IMAGE, + SUGGESTION, + HTML; + + public static BannerType fromString(String mode) { + if (mode == null) return BLANK; + switch (mode) { + case "BLANK": + return BLANK; + case "image": + return IMAGE; + case "suggestion": + return SUGGESTION; + case "html": + return HTML; + } + return BLANK; + } + + public String toString() { + String modes[] = { "blank", "image", "suggestion", "html"}; + return modes[this.ordinal()]; + } + } + protected static InputMethodService IMService; private static boolean debugMode = false; @@ -287,6 +303,9 @@ public String toString() { public static final String KMFilename_LexicalModelsList = "lexical_models_list.dat"; + public static final String KMBLACK_BANNER = "
"; + public static final String KMGRAY_BANNER = "
"; + private static Context appContext; public static String getResourceRoot() { @@ -636,6 +655,16 @@ private static void initKeyboard(Context appContext, KeyboardType keyboardType) keyboard.addJavascriptInterface(new KMKeyboardJSHandler(appContext, keyboard), "jsInterface"); keyboard.loadKeyboard(); + if (!isTestMode()) { + // For apps that don't specify an HTML banner, specify a default phone/tablet HTML banner + if (getFormFactor() == FormFactor.PHONE) { + keyboard.setHTMLBanner(KMBLACK_BANNER); + } else { + keyboard.setHTMLBanner(KMGRAY_BANNER); + } + keyboard.setBanner(KMManager.BannerType.HTML); + keyboard.showBanner(true); + } setEngineWebViewVersionStatus(appContext, keyboard); } @@ -793,6 +822,31 @@ public static boolean hasInternetPermission(Context context) { return hasPermission(context, Manifest.permission.INTERNET); } + /** + * Copy HTML banner assets to the app + * @param context - The context + * @param path - Folder relative to assets/ containing the banner file. + * @return boolean - true if assets copied + */ + public static boolean copyHTMLBannerAssets(Context context, String path) { + AssetManager assetManager = context.getAssets(); + try { + File bannerDir = new File(getResourceRoot() + File.separator + path); + if (!bannerDir.exists()) { + bannerDir.mkdir(); + } + + String[] bannerFiles = assetManager.list(path); + for (String bannerFile : bannerFiles) { + copyAsset(context, bannerFile, path, true); + } + return true; + } catch (Exception e) { + KMLog.LogException(TAG, "copyHTMLBannerAssets() failed. Error: ", e); + } + return false; + } + private static void copyAssets(Context context) { AssetManager assetManager = context.getAssets(); try { @@ -1370,7 +1424,13 @@ public static void deleteLexicalModel(Context context, int position, boolean sil KeyboardPickerActivity.deleteLexicalModel(context, position, silenceNotification); } - public static boolean setBannerOptions(boolean mayPredict) { + /** + * setBannerOptions - Update KMW whether to generate predictions. + * For now, also display banner + * @param mayPredict - boolean whether KMW should generate predictions + * @return boolean - Success + */ + public static boolean setBannerOptions(boolean mayPredict) { String url = KMString.format("setBannerOptions(%s)", mayPredict); if (InAppKeyboard != null) { InAppKeyboard.loadJavascript(url); @@ -1379,6 +1439,73 @@ public static boolean setBannerOptions(boolean mayPredict) { if (SystemKeyboard != null) { SystemKeyboard.loadJavascript(url); } + + return true; + } + + /** + * Update KeymanWeb banner type + * @param {KeyboardType} keyboard + * @param {BannerType} bannerType + * @return status + */ + public static boolean setBanner(KeyboardType keyboard, BannerType bannerType) { + if (keyboard == KeyboardType.KEYBOARD_TYPE_INAPP && InAppKeyboard != null) { + InAppKeyboard.setBanner(bannerType); + } else if (keyboard == KeyboardType.KEYBOARD_TYPE_SYSTEM && SystemKeyboard != null) { + SystemKeyboard.setBanner(bannerType); + } else { + return false; + } + return true; + } + + /** + * Set the HTML content to use with the HTML banner + * @param {KeyboardType} keyboard + * @param {String} HTMl string + * @return {boolean} + */ + public static boolean setHTMLBanner(KeyboardType keyboard, String htmlContent) { + if (keyboard == KeyboardType.KEYBOARD_TYPE_INAPP && InAppKeyboard != null) { + InAppKeyboard.setHTMLBanner(htmlContent); + } else if (keyboard == KeyboardType.KEYBOARD_TYPE_SYSTEM && SystemKeyboard != null) { + SystemKeyboard.setHTMLBanner(htmlContent); + } else { + Log.d(TAG, "setHTMLBanner() but keyboard is null"); + return false; + } + return true; + } + + /** + * Get the HTML content associated with the HTML banner + * @param {KeyboardType} keyboard + * @return {String} + */ + public static String getHTMLBanner(KeyboardType keyboard) { + if (keyboard == KeyboardType.KEYBOARD_TYPE_INAPP && InAppKeyboard != null) { + return InAppKeyboard.getHTMLBanner(); + } else if (keyboard == KeyboardType.KEYBOARD_TYPE_SYSTEM && SystemKeyboard != null) { + return SystemKeyboard.getHTMLBanner(); + } + return ""; + } + + /** + * showBanner - Update KMW whether to display banner. + * For now, always keep displaying banner + * @param flag - boolean whether KMW should display banner + * @return boolean - Success + */ + public static boolean showBanner(boolean flag) { + if (InAppKeyboard != null) { + InAppKeyboard.showBanner(flag); + } + + if (SystemKeyboard != null) { + SystemKeyboard.showBanner(flag); + } return true; } @@ -1845,9 +1972,9 @@ public static void removeKeyboardEventListener(OnKeyboardEventListener listener) public static int getBannerHeight(Context context) { int bannerHeight = 0; - if (InAppKeyboard != null && InAppKeyboard.currentBanner().equals(KMKeyboard.KM_BANNER_STATE_SUGGESTION)) { + if (InAppKeyboard != null && InAppKeyboard.getBanner() != BannerType.BLANK) { bannerHeight = (int) context.getResources().getDimension(R.dimen.banner_height); - } else if (SystemKeyboard != null && SystemKeyboard.currentBanner().equals(KMKeyboard.KM_BANNER_STATE_SUGGESTION)) { + } else if (SystemKeyboard != null && SystemKeyboard.getBanner() != BannerType.BLANK) { bannerHeight = (int) context.getResources().getDimension(R.dimen.banner_height); } return bannerHeight; diff --git a/android/KMEA/app/src/main/java/com/keyman/engine/util/FileUtils.java b/android/KMEA/app/src/main/java/com/keyman/engine/util/FileUtils.java index d5610dedec2..6b04b974f8a 100644 --- a/android/KMEA/app/src/main/java/com/keyman/engine/util/FileUtils.java +++ b/android/KMEA/app/src/main/java/com/keyman/engine/util/FileUtils.java @@ -4,16 +4,22 @@ package com.keyman.engine.util; import android.content.Context; +import android.content.res.AssetManager; +import android.util.Log; + +import com.keyman.engine.KMManager; import org.json.JSONObject; import org.json.JSONArray; import java.io.BufferedInputStream; +import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.nio.charset.StandardCharsets; @@ -248,6 +254,35 @@ public static boolean saveList(File filepath, Object obj) { return result; } + /** + * Read the contents of asset file as a string + * Reference: https://stackoverflow.com/questions/16110002/read-assets-file-as-string + * @param context + * @param path - path of file relative to assets folder + * @return String + */ + public static String readContents(Context context, String path) { + StringBuilder sb = new StringBuilder(); + String str = ""; + AssetManager assetManager = context.getAssets(); + try { + InputStream inputStream = assetManager.open(path); + if (inputStream == null) { + KMLog.LogInfo(TAG, "Unable to read contents of asset: " + path); + return str; + } + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + while ((str = reader.readLine()) != null) { + sb.append(str); + } + reader.close(); + } catch (Exception e) { + KMLog.LogException(TAG, "Error reading asset file", e); + return str; + } + return sb.toString(); + } + /** * Utility to parse a URL and extract the filename * @param urlStr String diff --git a/oem/firstvoices/android/app/src/main/assets/banner.html b/oem/firstvoices/android/app/src/main/assets/banner.html new file mode 100644 index 00000000000..b0c30219cbe --- /dev/null +++ b/oem/firstvoices/android/app/src/main/assets/banner.html @@ -0,0 +1,10 @@ + +
+ + + + + +
+ +
diff --git a/oem/firstvoices/android/app/src/main/assets/banner/red-logo.svg b/oem/firstvoices/android/app/src/main/assets/banner/red-logo.svg new file mode 100644 index 00000000000..cf89f67db51 --- /dev/null +++ b/oem/firstvoices/android/app/src/main/assets/banner/red-logo.svg @@ -0,0 +1,38 @@ + + + + + + + + + + diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/android/BannerController.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/android/BannerController.java new file mode 100644 index 00000000000..a0df15b2f1e --- /dev/null +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/android/BannerController.java @@ -0,0 +1,29 @@ +package com.firstvoices.android; + +import android.content.Context; + +import com.keyman.engine.KMManager; +import com.keyman.engine.util.FileUtils; + +import java.io.File; + +public class BannerController { + + // Paths relative to assets folder for banner themes + public static final String FV_BANNER_DIR = "banner"; + public static final String FV_BANNER_THEME = "banner.html"; + + public static void setHTMLBanner(Context context, KMManager.KeyboardType keyboardType) { + if (keyboardType == KMManager.KeyboardType.KEYBOARD_TYPE_UNDEFINED) { + return; + } + + KMManager.copyHTMLBannerAssets(context, FV_BANNER_DIR); + + // Always use FirstVoices banner theme + String contents = FileUtils.readContents(context, FV_BANNER_THEME); + KMManager.setHTMLBanner(keyboardType, contents); + KMManager.setBanner(keyboardType, KMManager.BannerType.HTML); + KMManager.showBanner(true); + } +} diff --git a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java index 95d0c51b372..0fb770c9b51 100644 --- a/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java +++ b/oem/firstvoices/android/app/src/main/java/com/firstvoices/keyboards/SystemKeyboard.java @@ -20,6 +20,7 @@ import android.view.inputmethod.InputConnection; import android.widget.FrameLayout; +import com.firstvoices.android.BannerController; import com.keyman.engine.KMManager; import com.keyman.engine.KMManager.KeyboardType; import com.keyman.engine.KMHardwareKeyboardInterpreter; @@ -33,7 +34,6 @@ import io.sentry.Sentry; public class SystemKeyboard extends InputMethodService implements OnKeyboardEventListener { - private View inputView = null; private static ExtractedText exText = null; private KMHardwareKeyboardInterpreter interpreter = null; @@ -64,6 +64,9 @@ public void onCreate() { interpreter = new KMHardwareKeyboardInterpreter(getApplicationContext(), KeyboardType.KEYBOARD_TYPE_SYSTEM); KMManager.setInputMethodService(this); // for HW interface + + // Set the system keyboard HTML banner + BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM); } @Override @@ -79,7 +82,10 @@ public void onDestroy() { * is called after creation and any configuration change. */ @Override public void onInitializeInterface() { - super.onInitializeInterface(); + super.onInitializeInterface(); + + // KeymanWeb reloaded, so we have to pass the banner again + BannerController.setHTMLBanner(this, KeyboardType.KEYBOARD_TYPE_SYSTEM); } /** Called by the framework when your view for creating input needs to