1
0
Fork 0

Removed SnakeYAML to prevent crashes on older devices (#302)

This commit is contained in:
Dimo Karaivanov 2023-07-11 17:55:24 +03:00 committed by GitHub
parent ec8186b137
commit c4a78c1931
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 147 additions and 14 deletions

View file

@ -29,7 +29,6 @@ dependencies {
implementation 'androidx.preference:preference:1.2.0'
implementation 'androidx.room:room-runtime:2.5.1'
annotationProcessor 'androidx.room:room-compiler:2.5.1'
implementation 'org.yaml:snakeyaml:2.0'
}
repositories {

View file

@ -24,11 +24,3 @@
-keepclassmembers class io.github.sspanak.tt9.languages.LanguageDefinition {
public *;
}
# SnakeYAML shall not complain. As resolved by Mozilla:
# https://github.com/mozilla-mobile/focus-android/blob/main/app/proguard-rules.pro
-dontwarn java.beans.BeanInfo
-dontwarn java.beans.FeatureDescriptor
-dontwarn java.beans.IntrospectionException
-dontwarn java.beans.Introspector
-dontwarn java.beans.PropertyDescriptor

View file

@ -61,7 +61,7 @@ public class Language {
lang.locale = definitionLocale;
lang.name = definition.name.isEmpty() ? lang.name : definition.name;
for (int key = 0; key <= 9 || key < definition.layout.size(); key++) {
for (int key = 0; key <= 9 && key < definition.layout.size(); key++) {
lang.layout.add(keyCharsFromDefinition(key, definition.layout.get(key)));
}

View file

@ -2,13 +2,15 @@ package io.github.sspanak.tt9.languages;
import android.content.res.AssetManager;
import org.yaml.snakeyaml.Yaml;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import io.github.sspanak.tt9.Logger;
@ -23,12 +25,19 @@ public class LanguageDefinition {
public String locale = "";
public String name = "";
/**
* getAllFiles
* Returns a list of the paths of all language definition files in the assets folder or an empty list on error.
*/
public static ArrayList<String> getAllFiles(AssetManager assets) {
ArrayList<String> files = new ArrayList<>();
try {
for (String file : assets.list(definitionsDir)) {
files.add(definitionsDir + "/" + file);
}
Logger.d("LanguageDefinition", "Found: " + files.size() + " languages.");
} catch (IOException e) {
Logger.e("tt9.LanguageDefinition", "Failed reading language definitions from: '" + definitionsDir + "'. " + e.getMessage());
}
@ -36,11 +45,144 @@ public class LanguageDefinition {
return files;
}
public static LanguageDefinition fromFile(AssetManager assets, String definitionFile) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(assets.open(definitionFile), StandardCharsets.UTF_8));
return new Yaml().loadAs(reader, LanguageDefinition.class);
/**
* fromFile
* Takes the path to a language definition in the assets folder and parses that file into a LanguageDefinition
* or throws an IOException on error.
*/
public static LanguageDefinition fromFile(AssetManager assetManager, String definitionFile) throws IOException {
return parse(load(assetManager, definitionFile));
}
/**
* load
* Loads a language definition file from the assets folder into a String or throws an IOException on error.
*/
private static ArrayList<String> load(AssetManager assetManager, String definitionFile) throws IOException {
BufferedReader reader = new BufferedReader(new InputStreamReader(assetManager.open(definitionFile), StandardCharsets.UTF_8));
ArrayList<String> fileContents = new ArrayList<>();
String line;
while ((line = reader.readLine()) != null) {
fileContents.add(line);
}
return fileContents;
}
/**
* parse
* Converts "yaml" to a LanguageDefinition object. All properties in the YAML are considered optional,
* so the LanguageDefinition defaults will be used when some property is omitted.
*
* Had to write all this, because the only usable library, SnakeYAML, works fine on Android 10+,
* but causes crashes on older devices.
*/
@NonNull
private static LanguageDefinition parse(ArrayList<String> yaml) {
LanguageDefinition definition = new LanguageDefinition();
String value;
value = getPropertyFromYaml(yaml, "absString");
definition.abcString = value != null ? value : definition.abcString;
value = getPropertyFromYaml(yaml, "dictionaryFile");
definition.dictionaryFile = value != null ? value : definition.dictionaryFile;
value = getPropertyFromYaml(yaml, "locale");
definition.locale = value != null ? value : definition.locale;
value = getPropertyFromYaml(yaml, "name");
definition.name = value != null ? value : definition.name;
definition.layout = getLayoutFromYaml(yaml);
value = getPropertyFromYaml(yaml, "hasUpperCase");
if (value != null) {
value = value.toLowerCase();
definition.hasUpperCase = value.equals("true") || value.equals("on") || value.equals("yes") || value.equals("y");
}
return definition;
}
/**
* getPropertyFromYaml
* Finds "property" in the "yaml" and returns its value.
* Optional properties are allowed. NULL will be returned when they are missing.
*/
@Nullable
private static String getPropertyFromYaml(ArrayList<String> yaml, String property) {
for (String line : yaml) {
line = line.replaceAll("#.+$", "").trim();
String[] parts = line.split(":");
if (parts.length < 2) {
continue;
}
if (property.equals(parts[0].trim())) {
return parts[1].trim();
}
}
return null;
}
/**
* getLayoutFromYaml
* Finds and extracts the keypad layout. Less than 10 keys are accepted allowed leaving the ones up to 9-key empty.
*/
@NonNull
private static ArrayList<ArrayList<String>> getLayoutFromYaml(ArrayList<String> yaml) {
ArrayList<ArrayList<String>> layout = new ArrayList<>();
boolean inLayout = false;
for (int i = 0; i < yaml.size(); i++) {
if (yaml.get(i).contains("layout")) {
inLayout = true;
continue;
}
if (inLayout) {
ArrayList<String> lineChars = getLayoutEntryFromYamlLine(yaml.get(i));
if (lineChars != null) {
layout.add(lineChars);
} else {
break;
}
}
}
return layout;
}
/**
* getLayoutEntryFromYamlLine
* Validates a YAML line as an array and returns the character list to be assigned to a given key (a layout entry).
* If the YAML line is invalid, NULL will be returned.
*/
@Nullable
private static ArrayList<String> getLayoutEntryFromYamlLine(String yamlLine) {
if (!yamlLine.contains("[") || !yamlLine.contains("]")) {
return null;
}
String line = yamlLine
.replaceAll("#.+$", "")
.replace('-', ' ')
.replace('[', ' ')
.replace(']', ' ')
.replace(" ", "");
return new ArrayList<>(Arrays.asList(line.split(",")));
}
public String getDictionaryFile() {
return languagesDir + "/dictionaries/" + dictionaryFile;
}