diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java index 3308caff9a..4c24da2559 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java @@ -1,9 +1,10 @@ -/** - * Copyright (C) 2017 SIL International. All rights reserved. +/* + * Keyman is copyright (C) SIL Global. MIT License. */ package com.tavultesoft.kmapro; +import java.io.File; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URL; @@ -386,7 +387,7 @@ public class WebBrowserActivity extends BaseActivity { super.onResume(); if (webView != null) { if (didFinishLoading) { - String fontFilename = KMManager.getKeyboardTextFontFilename(); + String fontFilename = getKeyboardTextFontFilenameOnly(); if (!loadedFont.equals(fontFilename)) { webView.reload(); } @@ -432,8 +433,19 @@ public class WebBrowserActivity extends BaseActivity { } } + /** + * Returns the filename without path of the display font of the current keyboard. + */ + private String getKeyboardTextFontFilenameOnly() { + String fontPath = KMManager.getKeyboardTextFontFilename(); + if (fontPath == null || fontPath.isEmpty()) { + return ""; + } + return new File(fontPath).getName(); + } + private void loadFont() { - String font = KMManager.getKeyboardTextFontFilename(); + String font = getKeyboardTextFontFilenameOnly(); if (!font.isEmpty()) { loadedFont = font; String fontUrl = String.format("%s%s", fontBaseUri, font); 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 541e20edcb..212de6d0a0 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 @@ -84,10 +84,8 @@ final class KMKeyboard extends WebView { */ protected static KMManager.BannerType currentBanner = KMManager.BannerType.HTML; - private static String txtFont = ""; - private static String oskFont = null; - private static String dataRoot = ""; - private static String packageRoot = ""; + private static String txtFontPath = ""; + private static String oskFontPath = ""; private final String fontUndefined = "undefined"; private GestureDetector gestureDetector; private static ArrayList kbEventListeners = null; @@ -551,7 +549,7 @@ final class KMKeyboard extends WebView { * @return String */ public static String textFontFilename() { - return txtFont; + return txtFontPath; } /** @@ -559,10 +557,10 @@ final class KMKeyboard extends WebView { * @return String */ public static String oskFontFilename() { - return oskFont; + return oskFontPath; } - // REVIEW: this method seems to be unused + // REVIEW: this method seems to be unused and undocumented. Can we remove it? /** * Return the full path to the special OSK font, * which is with all the keyboard assets at the root app_data folder @@ -648,8 +646,6 @@ final class KMKeyboard extends WebView { } String kbKey = KMString.format("%s_%s", languageID, keyboardID); - setPackageRoot(packageID); - // Escape single-quoted names for javascript call keyboardName = keyboardName.replaceAll("\'", "\\\\'"); // Double-escaped-backslash b/c regex. @@ -704,16 +700,14 @@ final class KMKeyboard extends WebView { KMManager.getLatestKeyboardFileVersion(getContext(), packageID, keyboardID) : null; } - setPackageRoot(packageID); - if(kOskFont == null || kOskFont.isEmpty()) kOskFont = kFont; - JSONObject jDisplayFont = makeFontObject(kFont); - JSONObject jOskFont = makeFontObject(kOskFont); + JSONObject jDisplayFont = makeFontObject(kFont, packageID); + JSONObject jOskFont = makeFontObject(kOskFont, packageID); - txtFont = getFontFilename(jDisplayFont); - oskFont = getFontFilename(jOskFont); + txtFontPath = getFontFilename(kFont, packageID); + oskFontPath = getFontFilename(kOskFont, packageID); String kbKey = KMString.format("%s_%s", languageID, keyboardID); @@ -810,26 +804,40 @@ final class KMKeyboard extends WebView { } } - // Set the base path of the keyboard depending on the package ID - private void setPackageRoot(String packageID) { - this.dataRoot = WebViewUtils.buildAssetUrl(""); + /** + * Return the root URL for the data folder. Even though this is a local + * location this returns a URL with a magic domain so that it can be + * loaded with fetch() in the webview. + */ + private String getDataRootUrl() { + return WebViewUtils.buildAssetUrl(""); + } + + /** + * Return the root path for the data folder as a file path. This should be + * used where the file is not loaded through the webview, but is instead + * used by the app directly. + */ + private String getDataRootPath() { + return context.getDir("data", Context.MODE_PRIVATE).toString() + File.separator; + } + + private String getPackageRootUrl(String packageID) { if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) { - this.packageRoot = this.dataRoot + KMManager.KMDefault_UndefinedPackageID + "/"; - } else { - this.packageRoot = this.dataRoot + KMManager.KMDefault_AssetPackages + "/" + packageID + "/"; + return getDataRootUrl() + KMManager.KMDefault_UndefinedPackageID + "/"; } + return getDataRootUrl() + KMManager.KMDefault_AssetPackages + "/" + packageID + "/"; } - private String getDataRoot() { - return this.dataRoot; - } - - private String getPackageRoot() { - return this.packageRoot; + private String getPackageRootPath(String packageID) { + if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) { + return getDataRootPath() + KMManager.KMDefault_UndefinedPackageID + File.separator; + } + return getDataRootPath() + KMManager.KMDefault_AssetPackages + File.separator + packageID + File.separator; } private String makeKeyboardUrl(String packageID, String keyboardID, String keyboardVersion) { - String keyboardUrl = getPackageRoot(); + String keyboardUrl = getPackageRootUrl(packageID); if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) { keyboardUrl += keyboardID + "-" + keyboardVersion + ".js"; } else { @@ -917,42 +925,23 @@ final class KMKeyboard extends WebView { } /** - * getFontFilename - * Parse a Font JSON object and return the font filename (ending in .ttf or .otf) - * @param fontObj JSONObject - Font JSON object - * @return String - Filename for the font. If font is invalid, return "" + * Return the full path to the font file. If the font is invalid, return empty string. + * @param font String - Font filename + * @param packageID String - Package ID + * @return String - Full path to the font file. If font is invalid, return "". */ - private String getFontFilename(JSONObject fontObj) { - String font = ""; - if (fontObj == null) { - return font; - } - try { - JSONArray sourceArray = fontObj.optJSONArray(KMManager.KMKey_FontFiles); - if (sourceArray != null) { - String fontFile; - int length = sourceArray.length(); - for (int i = 0; i < length; i++) { - fontFile = sourceArray.getString(i); - if (FileUtils.hasFontExtension(fontFile)) { - font = fontFile; - break; - } - } - } else { - String fontFile = fontObj.optString(KMManager.KMKey_FontFiles); - if (fontFile != null) { - if (FileUtils.hasFontExtension(fontFile)) { - font = fontFile; - } - } - } - } catch (JSONException e) { - KMLog.LogException(TAG, "", e); - font = ""; + private String getFontFilename(String font, String packageID) { + if(font == null || font.equals("")) { + return ""; } - return font; + if (!FileUtils.hasFontExtension(font)) { + // QUESTION: do we log this? + return ""; + } + + String fontRoot = KMManager.isDefaultFont(font) ? getDataRootPath() : getPackageRootPath(packageID); + return fontRoot + font; } @SuppressLint("InflateParams") @@ -1061,12 +1050,14 @@ final class KMKeyboard extends WebView { * the first file with a font extension which is then prefixed with the * path to the fonts. * - * @param font A string containing either the font filename or a font JSON - * object as a string + * @param font A string containing either the font filename or a font + * JSON object as a string + * @param packageID The package ID of the keyboard + * * @return JSONObject of modified font information with full paths. If font * is invalid, return `null`. */ - private JSONObject makeFontObject(String font) { + private JSONObject makeFontObject(String font, String packageID) { if(font == null || font.equals("")) { return null; @@ -1077,12 +1068,16 @@ final class KMKeyboard extends WebView { JSONObject jfont = new JSONObject(); jfont.put(KMManager.KMKey_FontFamily, font.substring(0, font.length()-4)); JSONArray jfiles = new JSONArray(); - String fontRoot = KMManager.isDefaultFont(font) ? getDataRoot() : getPackageRoot(); + String fontRoot = KMManager.isDefaultFont(font) ? getDataRootUrl() : getPackageRootUrl(packageID); jfiles.put(fontRoot + font); jfont.put(KMManager.KMKey_FontFiles, jfiles); return jfont; } + // REVIEW: Why do we need the complicated code below? Can this still + // happen, or can we remove it? (see also getFontFilename) + KMLog.LogInfo(TAG, "Got font without font extension: " + font); + JSONObject fontObj = new JSONObject(font); // Replace "sources" key with "files" @@ -1094,7 +1089,7 @@ final class KMKeyboard extends WebView { Object obj = fontObj.get(KMManager.KMKey_FontFiles); if (obj instanceof String) { String fontFile = fontObj.getString(KMManager.KMKey_FontFiles); - String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRoot() : getPackageRoot(); + String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRootUrl() : getPackageRootUrl(packageID); fontObj.put(KMManager.KMKey_FontFiles, fontRoot + obj); return fontObj; } else if (obj instanceof JSONArray) { @@ -1103,7 +1098,7 @@ final class KMKeyboard extends WebView { for (int i = 0; i < sourceArray.length(); i++) { String fontFile = sourceArray.getString(i); if (FileUtils.hasFontExtension(fontFile)) { - String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRoot() : getPackageRoot(); + String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRootUrl() : getPackageRootUrl(packageID); fontObj.put(KMManager.KMKey_FontFiles, fontRoot + fontFile); fontObj.remove(KMManager.KMKey_FontSource); return fontObj; 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 3ca6f53de0..e46041fddb 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 @@ -1629,6 +1629,16 @@ public final class KMManager { */ public static Typeface getFontTypeface(Context context, String fontFilename) { try { + if (fontFilename == null || fontFilename.isEmpty()) { + return null; + } + if (fontFilename.startsWith("http://") || fontFilename.startsWith("https://") + || fontFilename.startsWith("file://")) { + // Font file is not local, so cannot load Typeface + KMLog.LogError(TAG, "Font file is not local: " + fontFilename); + return null; + } + if ((fontFilename != null) && FileUtils.hasFontExtension(fontFilename)) { // Ignore .woff files if Android 7.0 / 7.1 (Issue #4896) if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) && diff --git a/android/docs/engine/KMManager/getFontTypeface.md b/android/docs/engine/KMManager/getFontTypeface.md index 4149d92b36..9dd86928e7 100644 --- a/android/docs/engine/KMManager/getFontTypeface.md +++ b/android/docs/engine/KMManager/getFontTypeface.md @@ -19,7 +19,7 @@ KMManager.getFontTypeface(Context context, String fontFilename) : The context. `fontFilename` -: The filename of the font. +: The filename and full path of the font. ### Returns @@ -29,7 +29,7 @@ if it exists, `null` otherwise. ## Description Use this method to create a new typeface from the font file with -specified filename if it exists in `assets/fonts/` folder. +specified filename if it exists. ## Examples @@ -37,9 +37,10 @@ specified filename if it exists in `assets/fonts/` folder. The following script illustrate the use of `getFontTypeface()`: -``` javascript +``` java KMTextView textView = (KMTextView) findViewById(R.id.kmTextView); - Typeface fontTypeface = KMManager.getFontTypeface(this, "aava1.ttf"); + String textFontFilename = KMManager.getKeyboardTextFontFilename(); + Typeface fontTypeface = KMManager.getFontTypeface(this, textFontFilename); textView.setTypeface(fontTypeface); ``` diff --git a/android/docs/engine/KMManager/getKeyboardOskFontFilename.md b/android/docs/engine/KMManager/getKeyboardOskFontFilename.md index 8465ea4e8c..7406effb9d 100644 --- a/android/docs/engine/KMManager/getKeyboardOskFontFilename.md +++ b/android/docs/engine/KMManager/getKeyboardOskFontFilename.md @@ -5,18 +5,25 @@ title: KMManager.getKeyboardOskFontFilename() ## Summary The **`getKeyboardOskFontFilename()`** method returns the selected -keyboard's OSK font filename. +keyboard's OSK font filename and full path. ## Syntax -``` javascript +``` java KMManager.getKeyboardOskFontFilename() ``` ### Returns -Returns the selected keyboard's OSK font filename as `String` if it has -any, empty string otherwise. +Returns the selected keyboard's OSK font filename and full path as +`String` if it has any, empty string otherwise. Note that the +on-screen keyboard will fallback to the keyboard text font if +no OSK font is specified. + +The OSK font should not be used for a text view, because some +OSK fonts are appropriate for use only in the on screen keyboard; +see [`&displayMap`](/developer/language/reference/displaymap) for +reference. ## Description @@ -29,8 +36,8 @@ Use this method to get the OSK font filename of the selected keyboard. The following script illustrate the use of `getKeyboardOskFontFilename()`: -``` javascript - String oskFontFilename = KMManager.getKeyboardOskFontFilename(); +``` java +String oskFontFilename = KMManager.getKeyboardOskFontFilename(); ``` ## See also diff --git a/android/docs/engine/KMManager/getKeyboardTextFontFilename.md b/android/docs/engine/KMManager/getKeyboardTextFontFilename.md index 5c381cc23a..f1e26e51a3 100644 --- a/android/docs/engine/KMManager/getKeyboardTextFontFilename.md +++ b/android/docs/engine/KMManager/getKeyboardTextFontFilename.md @@ -5,18 +5,18 @@ title: KMManager.getKeyboardTextFontFilename() ## Summary The **`getKeyboardTextFontFilename()`** method returns the selected -keyboard's text font filename. +keyboard's text font filename and full path. ## Syntax -``` javascript +``` java KMManager.getKeyboardTextFontFilename() ``` ### Returns -Returns the selected keyboard's text font filename as `String` if it has -any, empty string otherwise. +Returns the selected keyboard's text font filename and full path as +`String` if it has any, empty string otherwise. ## Description @@ -29,8 +29,8 @@ Use this method to get the text font filename of the selected keyboard. The following script illustrate the use of `getKeyboardTextFontFilename()`: -``` javascript - String textFontFilename = KMManager.getKeyboardTextFontFilename(); +``` java +String textFontFilename = KMManager.getKeyboardTextFontFilename(); ``` ## See also