Skip to content

Commit fcf8988

Browse files
authored
Merge pull request #16188 from keymanapp/fix/android/16187_font
fix(android): differentiate between fontPath and fontUrl in Keyman Engine for Android
2 parents 1aae71e + 71aefb8 commit fcf8988

6 files changed

Lines changed: 111 additions & 86 deletions

File tree

android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/WebBrowserActivity.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
/**
2-
* Copyright (C) 2017 SIL International. All rights reserved.
1+
/*
2+
* Keyman is copyright (C) SIL Global. MIT License.
33
*/
44

55
package com.tavultesoft.kmapro;
66

7+
import java.io.File;
78
import java.io.UnsupportedEncodingException;
89
import java.net.MalformedURLException;
910
import java.net.URL;
@@ -386,7 +387,7 @@ protected void onResume() {
386387
super.onResume();
387388
if (webView != null) {
388389
if (didFinishLoading) {
389-
String fontFilename = KMManager.getKeyboardTextFontFilename();
390+
String fontFilename = getKeyboardTextFontFilenameOnly();
390391
if (!loadedFont.equals(fontFilename)) {
391392
webView.reload();
392393
}
@@ -432,8 +433,19 @@ public void onBackPressed() {
432433
}
433434
}
434435

436+
/**
437+
* Returns the filename without path of the display font of the current keyboard.
438+
*/
439+
private String getKeyboardTextFontFilenameOnly() {
440+
String fontPath = KMManager.getKeyboardTextFontFilename();
441+
if (fontPath == null || fontPath.isEmpty()) {
442+
return "";
443+
}
444+
return new File(fontPath).getName();
445+
}
446+
435447
private void loadFont() {
436-
String font = KMManager.getKeyboardTextFontFilename();
448+
String font = getKeyboardTextFontFilenameOnly();
437449
if (!font.isEmpty()) {
438450
loadedFont = font;
439451
String fontUrl = String.format("%s%s", fontBaseUri, font);

android/KMEA/app/src/main/java/com/keyman/engine/KMKeyboard.java

Lines changed: 61 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,8 @@ final class KMKeyboard extends WebView {
8484
*/
8585
protected static KMManager.BannerType currentBanner = KMManager.BannerType.HTML;
8686

87-
private static String txtFont = "";
88-
private static String oskFont = null;
89-
private static String dataRoot = "";
90-
private static String packageRoot = "";
87+
private static String txtFontPath = "";
88+
private static String oskFontPath = "";
9189
private final String fontUndefined = "undefined";
9290
private GestureDetector gestureDetector;
9391
private static ArrayList<OnKeyboardEventListener> kbEventListeners = null;
@@ -551,18 +549,18 @@ protected void toggleSuggestionBanner(HashMap<String, String> associatedLexicalM
551549
* @return String
552550
*/
553551
public static String textFontFilename() {
554-
return txtFont;
552+
return txtFontPath;
555553
}
556554

557555
/**
558556
* Return the full path to the OSK font. Usually used for creating a Typeface font
559557
* @return String
560558
*/
561559
public static String oskFontFilename() {
562-
return oskFont;
560+
return oskFontPath;
563561
}
564562

565-
// REVIEW: this method seems to be unused
563+
// REVIEW: this method seems to be unused and undocumented. Can we remove it?
566564
/**
567565
* Return the full path to the special OSK font,
568566
* which is with all the keyboard assets at the root app_data folder
@@ -648,8 +646,6 @@ public boolean prepareKeyboardSwitch(String packageID, String keyboardID, String
648646
}
649647
String kbKey = KMString.format("%s_%s", languageID, keyboardID);
650648

651-
setPackageRoot(packageID);
652-
653649
// Escape single-quoted names for javascript call
654650
keyboardName = keyboardName.replaceAll("\'", "\\\\'"); // Double-escaped-backslash b/c regex.
655651

@@ -704,16 +700,14 @@ public boolean setKeyboard(String packageID, String keyboardID, String languageI
704700
KMManager.getLatestKeyboardFileVersion(getContext(), packageID, keyboardID) : null;
705701
}
706702

707-
setPackageRoot(packageID);
708-
709703
if(kOskFont == null || kOskFont.isEmpty())
710704
kOskFont = kFont;
711705

712-
JSONObject jDisplayFont = makeFontObject(kFont);
713-
JSONObject jOskFont = makeFontObject(kOskFont);
706+
JSONObject jDisplayFont = makeFontObject(kFont, packageID);
707+
JSONObject jOskFont = makeFontObject(kOskFont, packageID);
714708

715-
txtFont = getFontFilename(jDisplayFont);
716-
oskFont = getFontFilename(jOskFont);
709+
txtFontPath = getFontFilename(kFont, packageID);
710+
oskFontPath = getFontFilename(kOskFont, packageID);
717711

718712
String kbKey = KMString.format("%s_%s", languageID, keyboardID);
719713

@@ -810,26 +804,40 @@ private void sendError(String packageID, String keyboardID, String languageID, b
810804
}
811805
}
812806

813-
// Set the base path of the keyboard depending on the package ID
814-
private void setPackageRoot(String packageID) {
815-
this.dataRoot = WebViewUtils.buildAssetUrl("");
816-
if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) {
817-
this.packageRoot = this.dataRoot + KMManager.KMDefault_UndefinedPackageID + "/";
818-
} else {
819-
this.packageRoot = this.dataRoot + KMManager.KMDefault_AssetPackages + "/" + packageID + "/";
820-
}
807+
/**
808+
* Return the root URL for the data folder. Even though this is a local
809+
* location this returns a URL with a magic domain so that it can be
810+
* loaded with fetch() in the webview.
811+
*/
812+
private String getDataRootUrl() {
813+
return WebViewUtils.buildAssetUrl("");
821814
}
822815

823-
private String getDataRoot() {
824-
return this.dataRoot;
816+
/**
817+
* Return the root path for the data folder as a file path. This should be
818+
* used where the file is not loaded through the webview, but is instead
819+
* used by the app directly.
820+
*/
821+
private String getDataRootPath() {
822+
return context.getDir("data", Context.MODE_PRIVATE).toString() + File.separator;
825823
}
826824

827-
private String getPackageRoot() {
828-
return this.packageRoot;
825+
private String getPackageRootUrl(String packageID) {
826+
if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) {
827+
return getDataRootUrl() + KMManager.KMDefault_UndefinedPackageID + "/";
828+
}
829+
return getDataRootUrl() + KMManager.KMDefault_AssetPackages + "/" + packageID + "/";
830+
}
831+
832+
private String getPackageRootPath(String packageID) {
833+
if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) {
834+
return getDataRootPath() + KMManager.KMDefault_UndefinedPackageID + File.separator;
835+
}
836+
return getDataRootPath() + KMManager.KMDefault_AssetPackages + File.separator + packageID + File.separator;
829837
}
830838

831839
private String makeKeyboardUrl(String packageID, String keyboardID, String keyboardVersion) {
832-
String keyboardUrl = getPackageRoot();
840+
String keyboardUrl = getPackageRootUrl(packageID);
833841
if (packageID.equals(KMManager.KMDefault_UndefinedPackageID)) {
834842
keyboardUrl += keyboardID + "-" + keyboardVersion + ".js";
835843
} else {
@@ -917,42 +925,23 @@ private void saveCurrentKeyboardIndex() {
917925
}
918926

919927
/**
920-
* getFontFilename
921-
* Parse a Font JSON object and return the font filename (ending in .ttf or .otf)
922-
* @param fontObj JSONObject - Font JSON object
923-
* @return String - Filename for the font. If font is invalid, return ""
928+
* Return the full path to the font file. If the font is invalid, return empty string.
929+
* @param font String - Font filename
930+
* @param packageID String - Package ID
931+
* @return String - Full path to the font file. If font is invalid, return "".
924932
*/
925-
private String getFontFilename(JSONObject fontObj) {
926-
String font = "";
927-
if (fontObj == null) {
928-
return font;
933+
private String getFontFilename(String font, String packageID) {
934+
if(font == null || font.equals("")) {
935+
return "";
929936
}
930-
try {
931-
JSONArray sourceArray = fontObj.optJSONArray(KMManager.KMKey_FontFiles);
932-
if (sourceArray != null) {
933-
String fontFile;
934-
int length = sourceArray.length();
935-
for (int i = 0; i < length; i++) {
936-
fontFile = sourceArray.getString(i);
937-
if (FileUtils.hasFontExtension(fontFile)) {
938-
font = fontFile;
939-
break;
940-
}
941-
}
942-
} else {
943-
String fontFile = fontObj.optString(KMManager.KMKey_FontFiles);
944-
if (fontFile != null) {
945-
if (FileUtils.hasFontExtension(fontFile)) {
946-
font = fontFile;
947-
}
948-
}
949-
}
950-
} catch (JSONException e) {
951-
KMLog.LogException(TAG, "", e);
952-
font = "";
937+
938+
if (!FileUtils.hasFontExtension(font)) {
939+
// QUESTION: do we log this?
940+
return "";
953941
}
954942

955-
return font;
943+
String fontRoot = KMManager.isDefaultFont(font) ? getDataRootPath() : getPackageRootPath(packageID);
944+
return fontRoot + font;
956945
}
957946

958947
@SuppressLint("InflateParams")
@@ -1061,12 +1050,14 @@ public void onDismiss() {
10611050
* the first file with a font extension which is then prefixed with the
10621051
* path to the fonts.
10631052
*
1064-
* @param font A string containing either the font filename or a font JSON
1065-
* object as a string
1053+
* @param font A string containing either the font filename or a font
1054+
* JSON object as a string
1055+
* @param packageID The package ID of the keyboard
1056+
*
10661057
* @return JSONObject of modified font information with full paths. If font
10671058
* is invalid, return `null`.
10681059
*/
1069-
private JSONObject makeFontObject(String font) {
1060+
private JSONObject makeFontObject(String font, String packageID) {
10701061

10711062
if(font == null || font.equals("")) {
10721063
return null;
@@ -1077,12 +1068,16 @@ private JSONObject makeFontObject(String font) {
10771068
JSONObject jfont = new JSONObject();
10781069
jfont.put(KMManager.KMKey_FontFamily, font.substring(0, font.length()-4));
10791070
JSONArray jfiles = new JSONArray();
1080-
String fontRoot = KMManager.isDefaultFont(font) ? getDataRoot() : getPackageRoot();
1071+
String fontRoot = KMManager.isDefaultFont(font) ? getDataRootUrl() : getPackageRootUrl(packageID);
10811072
jfiles.put(fontRoot + font);
10821073
jfont.put(KMManager.KMKey_FontFiles, jfiles);
10831074
return jfont;
10841075
}
10851076

1077+
// REVIEW: Why do we need the complicated code below? Can this still
1078+
// happen, or can we remove it? (see also getFontFilename)
1079+
KMLog.LogInfo(TAG, "Got font without font extension: " + font);
1080+
10861081
JSONObject fontObj = new JSONObject(font);
10871082

10881083
// Replace "sources" key with "files"
@@ -1094,7 +1089,7 @@ private JSONObject makeFontObject(String font) {
10941089
Object obj = fontObj.get(KMManager.KMKey_FontFiles);
10951090
if (obj instanceof String) {
10961091
String fontFile = fontObj.getString(KMManager.KMKey_FontFiles);
1097-
String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRoot() : getPackageRoot();
1092+
String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRootUrl() : getPackageRootUrl(packageID);
10981093
fontObj.put(KMManager.KMKey_FontFiles, fontRoot + obj);
10991094
return fontObj;
11001095
} else if (obj instanceof JSONArray) {
@@ -1103,7 +1098,7 @@ private JSONObject makeFontObject(String font) {
11031098
for (int i = 0; i < sourceArray.length(); i++) {
11041099
String fontFile = sourceArray.getString(i);
11051100
if (FileUtils.hasFontExtension(fontFile)) {
1106-
String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRoot() : getPackageRoot();
1101+
String fontRoot = KMManager.isDefaultFont(fontFile) ? getDataRootUrl() : getPackageRootUrl(packageID);
11071102
fontObj.put(KMManager.KMKey_FontFiles, fontRoot + fontFile);
11081103
fontObj.remove(KMManager.KMKey_FontSource);
11091104
return fontObj;

android/KMEA/app/src/main/java/com/keyman/engine/KMManager.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1629,6 +1629,16 @@ public static void setMaySendCrashReport(boolean override) {
16291629
*/
16301630
public static Typeface getFontTypeface(Context context, String fontFilename) {
16311631
try {
1632+
if (fontFilename == null || fontFilename.isEmpty()) {
1633+
return null;
1634+
}
1635+
if (fontFilename.startsWith("http://") || fontFilename.startsWith("https://")
1636+
|| fontFilename.startsWith("file://")) {
1637+
// Font file is not local, so cannot load Typeface
1638+
KMLog.LogError(TAG, "Font file is not local: " + fontFilename);
1639+
return null;
1640+
}
1641+
16321642
if ((fontFilename != null) && FileUtils.hasFontExtension(fontFilename)) {
16331643
// Ignore .woff files if Android 7.0 / 7.1 (Issue #4896)
16341644
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) &&

android/docs/engine/KMManager/getFontTypeface.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ KMManager.getFontTypeface(Context context, String fontFilename)
1919
: The context.
2020

2121
`fontFilename`
22-
: The filename of the font.
22+
: The filename and full path of the font.
2323

2424
### Returns
2525

@@ -29,17 +29,18 @@ if it exists, `null` otherwise.
2929
## Description
3030

3131
Use this method to create a new typeface from the font file with
32-
specified filename if it exists in `assets/fonts/` folder.
32+
specified filename if it exists.
3333

3434
## Examples
3535

3636
### Example: Using `getFontTypeface()`
3737

3838
The following script illustrate the use of `getFontTypeface()`:
3939

40-
``` javascript
40+
``` java
4141
KMTextView textView = (KMTextView) findViewById(R.id.kmTextView);
42-
Typeface fontTypeface = KMManager.getFontTypeface(this, "aava1.ttf");
42+
String textFontFilename = KMManager.getKeyboardTextFontFilename();
43+
Typeface fontTypeface = KMManager.getFontTypeface(this, textFontFilename);
4344
textView.setTypeface(fontTypeface);
4445
```
4546

android/docs/engine/KMManager/getKeyboardOskFontFilename.md

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,25 @@ title: KMManager.getKeyboardOskFontFilename()
55
## Summary
66

77
The **`getKeyboardOskFontFilename()`** method returns the selected
8-
keyboard's OSK font filename.
8+
keyboard's OSK font filename and full path.
99

1010
## Syntax
1111

12-
``` javascript
12+
``` java
1313
KMManager.getKeyboardOskFontFilename()
1414
```
1515

1616
### Returns
1717

18-
Returns the selected keyboard's OSK font filename as `String` if it has
19-
any, empty string otherwise.
18+
Returns the selected keyboard's OSK font filename and full path as
19+
`String` if it has any, empty string otherwise. Note that the
20+
on-screen keyboard will fallback to the keyboard text font if
21+
no OSK font is specified.
22+
23+
The OSK font should not be used for a text view, because some
24+
OSK fonts are appropriate for use only in the on screen keyboard;
25+
see [`&displayMap`](/developer/language/reference/displaymap) for
26+
reference.
2027

2128
## Description
2229

@@ -29,8 +36,8 @@ Use this method to get the OSK font filename of the selected keyboard.
2936
The following script illustrate the use of
3037
`getKeyboardOskFontFilename()`:
3138

32-
``` javascript
33-
String oskFontFilename = KMManager.getKeyboardOskFontFilename();
39+
``` java
40+
String oskFontFilename = KMManager.getKeyboardOskFontFilename();
3441
```
3542

3643
## See also

android/docs/engine/KMManager/getKeyboardTextFontFilename.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,18 @@ title: KMManager.getKeyboardTextFontFilename()
55
## Summary
66

77
The **`getKeyboardTextFontFilename()`** method returns the selected
8-
keyboard's text font filename.
8+
keyboard's text font filename and full path.
99

1010
## Syntax
1111

12-
``` javascript
12+
``` java
1313
KMManager.getKeyboardTextFontFilename()
1414
```
1515

1616
### Returns
1717

18-
Returns the selected keyboard's text font filename as `String` if it has
19-
any, empty string otherwise.
18+
Returns the selected keyboard's text font filename and full path as
19+
`String` if it has any, empty string otherwise.
2020

2121
## Description
2222

@@ -29,8 +29,8 @@ Use this method to get the text font filename of the selected keyboard.
2929
The following script illustrate the use of
3030
`getKeyboardTextFontFilename()`:
3131

32-
``` javascript
33-
String textFontFilename = KMManager.getKeyboardTextFontFilename();
32+
``` java
33+
String textFontFilename = KMManager.getKeyboardTextFontFilename();
3434
```
3535

3636
## See also

0 commit comments

Comments
 (0)