mirror of
https://github.com/keymanapp/keyman.git
synced 2026-10-11 00:17:28 +00:00
Merge branch 'master' into ios-special-osk-font
This commit is contained in:
commit
60ccfa2896
34 changed files with 1390 additions and 1432 deletions
|
|
@ -14,13 +14,14 @@ import java.util.Arrays;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
import com.tavultesoft.kmea.KMKeyboardDownloaderActivity;
|
||||
import com.tavultesoft.kmea.KMManager;
|
||||
|
||||
import com.tavultesoft.kmea.KMManager.KeyboardType;
|
||||
import com.tavultesoft.kmea.KMTextView;
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener;
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener;
|
||||
|
||||
import android.app.FragmentManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -179,10 +180,43 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
}
|
||||
|
||||
KMManager.addKeyboardEventListener(this);
|
||||
KMManager.addKeyboardDownloadEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
|
||||
checkUrl();
|
||||
getIntent().setData(null);
|
||||
// If URL provided, start KMKeyboardDownloaderActivity
|
||||
Intent intent = getIntent();
|
||||
Uri data = intent.getData();
|
||||
if (data != null) {
|
||||
String directStr = data.getQueryParameter(KMKeyboardDownloaderActivity.KMKey_Direct);
|
||||
boolean isDirect = false;
|
||||
if (directStr != null && directStr.equals("true")) {
|
||||
isDirect = true;
|
||||
}
|
||||
|
||||
String url = data.getQueryParameter(KMKeyboardDownloaderActivity.KMKey_URL);
|
||||
if (url != null) {
|
||||
boolean isCustom = KMKeyboardDownloaderActivity.isCustom(url);
|
||||
|
||||
int index = url.lastIndexOf("/") + 1;
|
||||
String filename = "unknown:";
|
||||
if (index >= 0 && index <= url.length()) {
|
||||
filename = url.substring(index);
|
||||
}
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_KEYBOARD,
|
||||
data.getQueryParameter(KMKeyboardDownloaderActivity.KMKey_Keyboard));
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANGUAGE,
|
||||
data.getQueryParameter(KMKeyboardDownloaderActivity.KMKey_Language));
|
||||
bundle.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_CUSTOM, isCustom);
|
||||
bundle.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_DIRECT, isDirect);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_URL, url);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_FILENAME, filename);
|
||||
Intent i = new Intent(getApplicationContext(), KMKeyboardDownloaderActivity.class);
|
||||
i.putExtras(bundle);
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
intent.setData(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -190,7 +224,10 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
super.onPause();
|
||||
KMManager.onPause();
|
||||
KMManager.removeKeyboardEventListener(this);
|
||||
KMManager.removeKeyboardDownloadEventListener(this);
|
||||
|
||||
// Intentionally not removing KeyboardDownloadEventListener to
|
||||
// ensure onKeyboardDownloadFinished() gets called
|
||||
|
||||
SharedPreferences prefs = getSharedPreferences(getString(R.string.kma_prefs_name), Context.MODE_PRIVATE);
|
||||
SharedPreferences.Editor editor = prefs.edit();
|
||||
editor.putString(userTextKey, textView.getText().toString());
|
||||
|
|
@ -470,102 +507,6 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
startActivity(getStartedIntent);
|
||||
}
|
||||
|
||||
private boolean checkUrl() {
|
||||
// return true if requires user action (e.g. Download dialog)
|
||||
Intent i = getIntent();
|
||||
Uri data = i.getData();
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
final Context context = this;
|
||||
final String keyboard = data.getQueryParameter("keyboard");
|
||||
final String language = data.getQueryParameter("language");
|
||||
final String url = data.getQueryParameter("url");
|
||||
|
||||
if (url != null) {
|
||||
/*
|
||||
int kbIndex = -1;
|
||||
if (keyboard != null && language != null)
|
||||
kbIndex = KMManager.getKeyboardIndex(this, keyboard, language);
|
||||
|
||||
if (kbIndex >= 0) {
|
||||
KMManager.setKeyboard(context, kbIndex);
|
||||
return false;
|
||||
}*/
|
||||
|
||||
String direct = data.getQueryParameter("direct");
|
||||
final boolean isDirect;
|
||||
if (direct != null && direct.equals("true")) {
|
||||
isDirect = true;
|
||||
} else {
|
||||
isDirect = false;
|
||||
}
|
||||
|
||||
int index = url.lastIndexOf("/") + 1;
|
||||
String jsonFilename = "unknown";
|
||||
if (index >= 0 && index <= url.length()) {
|
||||
jsonFilename = url.substring(index);
|
||||
}
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
dialogBuilder.setTitle("Custom Keyboard: " + jsonFilename);
|
||||
dialogBuilder.setMessage("Would you like to download this keyboard?");
|
||||
dialogBuilder.setPositiveButton("Download", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Download custom keyboard
|
||||
if (KMManager.hasConnection(context)) {
|
||||
KMManager.KMCustomKeyboardDownloader.download(context, url, isDirect, true);
|
||||
} else {
|
||||
Toast.makeText(context, "No internet connection", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel
|
||||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = dialogBuilder.create();
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
} else if (keyboard != null && language != null && !keyboard.trim().isEmpty() && !language.trim().isEmpty()) {
|
||||
int kbIndex = KMManager.getKeyboardIndex(this, keyboard, language);
|
||||
|
||||
if (kbIndex >= 0) {
|
||||
KMManager.setKeyboard(context, kbIndex);
|
||||
return false;
|
||||
}
|
||||
|
||||
String kbKey = String.format("%s_%s", language, keyboard);
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
dialogBuilder.setTitle("Keyboard: " + kbKey);
|
||||
dialogBuilder.setMessage("Would you like to download this keyboard?");
|
||||
dialogBuilder.setPositiveButton("Download", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Download keyboard
|
||||
if (KMManager.hasConnection(context)) {
|
||||
KMManager.KMKeyboardDownloader.download(context, KMManager.KMDefault_LegacyPackageID, keyboard, language, true);
|
||||
} else {
|
||||
Toast.makeText(context, "No internet connection", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel
|
||||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = dialogBuilder.create();
|
||||
dialog.show();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Drawable getActionBarDrawable(Context context) {
|
||||
Point size = new Point();
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
|
|
|
|||
|
|
@ -28,6 +28,11 @@
|
|||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme.Holo.Light.Dialog" >
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.tavultesoft.kmea.KMKeyboardDownloaderActivity"
|
||||
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize"
|
||||
android:theme="@android:style/Theme.Holo.Light.Dialog">
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.tavultesoft.kmea;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.Dialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.widget.Toast;
|
||||
|
||||
/**
|
||||
* Confirmation dialog for downloading a Keyman keyboard
|
||||
*/
|
||||
public class ConfirmDialogFragment extends DialogFragment {
|
||||
public static String ARG_TITLE = "ConfirmDialogFragment.title";
|
||||
|
||||
@Override
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
Bundle args = getArguments();
|
||||
final String title = args.getString(ARG_TITLE);
|
||||
|
||||
return new AlertDialog.Builder(getActivity())
|
||||
.setTitle(title)
|
||||
.setMessage("Would you like to download this keyboard?")
|
||||
.setPositiveButton("Download", new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Download keyboard
|
||||
if (KMManager.hasConnection(getActivity())) {
|
||||
KMKeyboardDownloaderActivity.download(getActivity(), true);
|
||||
} else {
|
||||
Toast.makeText(getActivity(), "No internet connection", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
})
|
||||
.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel
|
||||
}
|
||||
})
|
||||
.create();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,447 @@
|
|||
package com.tavultesoft.kmea;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.tavultesoft.kmea.util.FileDownloader;
|
||||
|
||||
import static com.tavultesoft.kmea.KMManager.KMDefault_AssetPackages;
|
||||
|
||||
public class KMKeyboardDownloaderActivity extends Activity {
|
||||
// Bundle Keys
|
||||
// Cloud
|
||||
public static final String ARG_PKG_ID = "KMKeyboardActivity.pkgID";
|
||||
public static final String ARG_KB_ID = "KMKeyboardActivity.kbID";
|
||||
public static final String ARG_LANG_ID = "KMKeyboardActivity.langID";
|
||||
public static final String ARG_KB_NAME = "KMKeyboardActivity.kbName";
|
||||
public static final String ARG_LANG_NAME = "KMKeyboardActivity.langName";
|
||||
public static final String ARG_IS_CUSTOM = "KMKeyboardActivity.isCustom";
|
||||
|
||||
// custom keyboard
|
||||
public static final String ARG_KEYBOARD = "KMKeyboardActivity.keyboard";
|
||||
public static final String ARG_LANGUAGE = "KMKeyboardActivity.language";
|
||||
public static final String ARG_IS_DIRECT = "KMKeyboardActivity.isDirect";
|
||||
public static final String ARG_URL = "KMKeyboardActivity.url";
|
||||
public static final String ARG_FILENAME = "KMKeyboardActivity.filename";
|
||||
|
||||
public static final String kKeymanApiBaseURL = "https://r.keymanweb.com/api/3.0/";
|
||||
public static final String kKeymanApiRemoteURL = "https://r.keymanweb.com/api/2.0/remote?url=";
|
||||
|
||||
// Keyman public keys
|
||||
public static final String KMKey_Direct = "direct";
|
||||
public static final String KMKey_URL = "url";
|
||||
public static final String KMKey_Keyboard = "keyboard";
|
||||
public static final String KMKey_LanguageKeyboards = "keyboards";
|
||||
public static final String KMKey_Options = "options";
|
||||
public static final String KMKey_Language = "language";
|
||||
public static final String KMKey_Languages = "languages";
|
||||
public static final String KMKey_Filename = "filename";
|
||||
|
||||
// Keyman internal keys
|
||||
public static final String KMKey_KeyboardBaseURI = "keyboardBaseUri";
|
||||
public static final String KMKey_FontBaseURI = "fontBaseUri";
|
||||
|
||||
private static String pkgID;
|
||||
private static String kbID;
|
||||
private static String langID;
|
||||
private static String kbName;
|
||||
private static String langName;
|
||||
private static Boolean isCustom;
|
||||
|
||||
private static String customKeyboard;
|
||||
private static String customLanguage;
|
||||
private static Boolean isDirect;
|
||||
private static String url;
|
||||
private static String filename;
|
||||
|
||||
private static ArrayList<KeyboardEventHandler.OnKeyboardDownloadEventListener> kbDownloadEventListeners = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
Bundle bundle = getIntent().getExtras();
|
||||
if (bundle != null) {
|
||||
pkgID = bundle.getString(ARG_PKG_ID);
|
||||
if (pkgID == null || pkgID.isEmpty()) {
|
||||
pkgID = KMManager.KMDefault_LegacyPackageID;
|
||||
}
|
||||
kbID = bundle.getString(ARG_KB_ID);
|
||||
langID = bundle.getString(ARG_LANG_ID);
|
||||
kbName = bundle.getString(ARG_KB_NAME);
|
||||
langName = bundle.getString(ARG_LANG_NAME);
|
||||
isCustom = bundle.getBoolean(ARG_IS_CUSTOM);
|
||||
|
||||
// URL parameters for custom keyboard (if they exist)
|
||||
customKeyboard = bundle.getString(ARG_KEYBOARD);
|
||||
customLanguage = bundle.getString(ARG_LANGUAGE);
|
||||
isDirect = bundle.getBoolean(ARG_IS_DIRECT);
|
||||
url = bundle.getString(ARG_URL);
|
||||
filename = bundle.getString(ARG_FILENAME);
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
filename = "unknown";
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
Bundle args = new Bundle();
|
||||
String title = "";
|
||||
if (url != null) {
|
||||
title = "Custom Keyboard: " + filename;
|
||||
} else if (customKeyboard != null && customLanguage != null &&
|
||||
!customKeyboard.trim().isEmpty() && !customLanguage.trim().isEmpty()) {
|
||||
int kbIndex = KMManager.getKeyboardIndex(getApplicationContext(), customKeyboard, customLanguage);
|
||||
|
||||
if (kbIndex >= 0) {
|
||||
KMManager.setKeyboard(getApplicationContext(), kbIndex);
|
||||
// No interaction needed
|
||||
return; // false
|
||||
}
|
||||
|
||||
title = customLanguage + "_" + customKeyboard;
|
||||
} else {
|
||||
// Download keyboard from cloud server
|
||||
title = langName + ": " + kbName;
|
||||
}
|
||||
|
||||
DialogFragment dialog = new ConfirmDialogFragment();
|
||||
args.putString(ConfirmDialogFragment.ARG_TITLE, title);
|
||||
dialog.setArguments(args);
|
||||
dialog.show(getFragmentManager(), "dialog");
|
||||
}
|
||||
|
||||
/**
|
||||
* Async task to download a Keyman keyboard from either Keyman cloud server or custom url
|
||||
* @param context
|
||||
* @param showProgressDialog
|
||||
*/
|
||||
public static void download(final Context context, final boolean showProgressDialog) {
|
||||
|
||||
new AsyncTask<Void, Integer, Integer>() {
|
||||
private ProgressDialog progressDialog;
|
||||
//private String languageName = "";
|
||||
//private String keyboardName = "";
|
||||
private String kbVersion = "1.0";
|
||||
private String kbIsCustom = isCustom ? "Y" : "N";
|
||||
private String font = "";
|
||||
private String oskFont = "";
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (showProgressDialog) {
|
||||
progressDialog = new ProgressDialog(context);
|
||||
progressDialog.setMessage("Downloading keyboard...");
|
||||
progressDialog.setCancelable(false);
|
||||
if (!((Activity) context).isFinishing()) {
|
||||
progressDialog.show();
|
||||
} else {
|
||||
cancel(true);
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
int ret = -1;
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
|
||||
if (isCancelled())
|
||||
return ret;
|
||||
|
||||
try {
|
||||
String exceptionStr = "Invalid keyboard";
|
||||
if (pkgID == null || pkgID.trim().isEmpty() ||
|
||||
(!isCustom && (langID == null || langID.trim().isEmpty() || kbID == null || kbID.trim().isEmpty()))) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
String deviceType = context.getResources().getString(R.string.device_type);
|
||||
if (deviceType.equals("AndroidTablet")) {
|
||||
deviceType = "androidtablet";
|
||||
} else {
|
||||
deviceType = "androidphone";
|
||||
}
|
||||
|
||||
// Placeholder here to attempt to process .kmp keyboard first:
|
||||
|
||||
////
|
||||
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
JSONObject kbData = null;
|
||||
String remoteUrl = "";
|
||||
if (isCustom) {
|
||||
if (isDirect) {
|
||||
remoteUrl = url;
|
||||
} else {
|
||||
String encodedUrl = URLEncoder.encode(filename, "utf-8");
|
||||
remoteUrl = String.format("%s%s&device=%s", kKeymanApiRemoteURL, encodedUrl, deviceType);
|
||||
}
|
||||
} else {
|
||||
// Keyman cloud
|
||||
remoteUrl = String.format("%slanguages/%s/%s?device=%s", kKeymanApiBaseURL, langID, kbID, deviceType);
|
||||
}
|
||||
|
||||
kbData = jsonParser.getJSONObjectFromUrl(remoteUrl);
|
||||
|
||||
exceptionStr = "Could not reach server";
|
||||
if (kbData == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
exceptionStr = "The keyboard could not be installed";
|
||||
JSONObject options = kbData.optJSONObject(KMKey_Options);
|
||||
if (options == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
String kbBaseUri = options.optString(KMKey_KeyboardBaseURI, "");
|
||||
if (kbBaseUri.isEmpty()) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
String fontBaseUri = options.optString(KMKey_FontBaseURI, "");
|
||||
JSONObject language, keyboard;
|
||||
if (!isCustom) {
|
||||
// JSON from Keyman cloud server
|
||||
language = kbData.optJSONObject(KMKey_Language);
|
||||
if (language == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
langName = language.optString(KMManager.KMKey_Name, "");
|
||||
|
||||
JSONArray keyboards = language.getJSONArray(KMKey_LanguageKeyboards);
|
||||
if (keyboards == null ) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
keyboard = keyboards.getJSONObject(0);
|
||||
if (keyboard == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
// JSON from custom URL
|
||||
keyboard = kbData.optJSONObject(KMKey_Keyboard);
|
||||
if (keyboard == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
JSONArray languages = keyboard.optJSONArray(KMKey_Languages);
|
||||
if (languages == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
// Concatenate langID and langName
|
||||
langID = "";
|
||||
langName = "";
|
||||
int langCount = languages.length();
|
||||
for (int i=0; i < langCount; i++) {
|
||||
langID += languages.getJSONObject(i).getString(KMManager.KMKey_ID);
|
||||
langName += languages.getJSONObject(i).getString(KMManager.KMKey_Name);
|
||||
if (i < langCount -1) {
|
||||
langID += ";";
|
||||
langName += ";";
|
||||
}
|
||||
}
|
||||
pkgID = keyboard.optString(KMManager.KMKey_PackageID, KMManager.KMDefault_LegacyPackageID);
|
||||
kbID = keyboard.optString(KMManager.KMKey_ID, "");
|
||||
|
||||
}
|
||||
|
||||
kbName = keyboard.optString(KMManager.KMKey_Name, "");
|
||||
kbVersion = keyboard.optString(KMManager.KMKey_KeyboardVersion, "1.0");
|
||||
font = keyboard.optString(KMManager.KMKey_Font, "").replace(
|
||||
"\"" + KMKeyboardDownloaderActivity.KMKey_Filename + "\"",
|
||||
"\"" + KMManager.KMKey_FontSource + "\"");
|
||||
oskFont = keyboard.optString(KMManager.KMKey_OskFont, "").replace(
|
||||
"\"" + KMKeyboardDownloaderActivity.KMKey_Filename + "\"",
|
||||
"\"" + KMManager.KMKey_FontSource + "\"");
|
||||
String kbFilename = keyboard.optString(KMKey_Filename, "");
|
||||
|
||||
if (kbName.isEmpty() || langName.isEmpty() || kbFilename.isEmpty())
|
||||
throw new Exception(exceptionStr);
|
||||
|
||||
String kbUrl = kbBaseUri + kbFilename;
|
||||
urls.add(kbUrl);
|
||||
JSONObject jsonFont = keyboard.optJSONObject(KMManager.KMKey_Font);
|
||||
JSONObject jsonOskFont = keyboard.optJSONObject(KMManager.KMKey_OskFont);
|
||||
ArrayList<String> fontUrls = fontUrls(jsonFont, fontBaseUri, true);
|
||||
ArrayList<String> oskFontUrls = fontUrls(jsonOskFont, fontBaseUri, true);
|
||||
if (fontUrls != null)
|
||||
urls.addAll(fontUrls);
|
||||
if (oskFontUrls != null) {
|
||||
for (String url : oskFontUrls) {
|
||||
if (!urls.contains(url))
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
notifyListeners(KeyboardEventHandler.EventType.KEYBOARD_DOWNLOAD_STARTED, 0);
|
||||
|
||||
ret = 1;
|
||||
int result = 0;
|
||||
for (String url : urls) {
|
||||
String directory = KMDefault_AssetPackages + File.separator + pkgID;
|
||||
File dir = new File(directory);
|
||||
String filename = "";
|
||||
if (url.endsWith(".js")) {
|
||||
|
||||
int start = kbFilename.lastIndexOf("/");
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
} else {
|
||||
start++;
|
||||
}
|
||||
if (!kbFilename.contains("-")) {
|
||||
filename = kbFilename.substring(start, kbFilename.length() - 3) + "-" + kbVersion + ".js";
|
||||
} else {
|
||||
filename = kbFilename.substring(start);
|
||||
}
|
||||
}
|
||||
|
||||
result = FileDownloader.download(context, url, directory, filename);
|
||||
if (result < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e("Keyboard download", "Error: " + e);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... progress) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
if (showProgressDialog) {
|
||||
if (progressDialog != null && progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
progressDialog = null;
|
||||
} catch (Exception e) {
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
notifyListeners(KeyboardEventHandler.EventType.KEYBOARD_DOWNLOAD_FINISHED, result);
|
||||
super.onPostExecute(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify listeners when an event happens
|
||||
* @param eventType
|
||||
* @param result
|
||||
*/
|
||||
protected void notifyListeners(KeyboardEventHandler.EventType eventType, int result) {
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMManager.KMKey_PackageID, pkgID);
|
||||
keyboardInfo.put(KMManager.KMKey_KeyboardID, kbID);
|
||||
keyboardInfo.put(KMManager.KMKey_LanguageID, langID);
|
||||
keyboardInfo.put(KMManager.KMKey_KeyboardName, kbName);
|
||||
keyboardInfo.put(KMManager.KMKey_LanguageName, langName);
|
||||
keyboardInfo.put(KMManager.KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMManager.KMKey_CustomKeyboard, kbIsCustom);
|
||||
keyboardInfo.put(KMManager.KMKey_Font, font);
|
||||
if (oskFont != null)
|
||||
keyboardInfo.put(KMManager.KMKey_OskFont, oskFont);
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, eventType, keyboardInfo, result);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
public static boolean isCustom(String u) {
|
||||
boolean ret = false;
|
||||
if (u != null && !u.contains(KMKeyboardDownloaderActivity.kKeymanApiBaseURL) &&
|
||||
!u.contains(KMKeyboardDownloaderActivity.kKeymanApiRemoteURL)) {
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static ArrayList<String> fontUrls(JSONObject jsonFont, String baseUri, boolean isOskFont) {
|
||||
if (jsonFont == null)
|
||||
return null;
|
||||
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
JSONArray fontSource = jsonFont.optJSONArray(KMManager.KMKey_FontSource);
|
||||
if (fontSource != null) {
|
||||
int fcCount = fontSource.length();
|
||||
for (int i = 0; i < fcCount; i++) {
|
||||
String fontSourceString;
|
||||
try {
|
||||
fontSourceString = fontSource.getString(i);
|
||||
if (fontSourceString.endsWith(".ttf") || fontSourceString.endsWith(".otf")) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && (fontSourceString.endsWith(".svg") || fontSourceString.endsWith(".woff"))) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && fontSourceString.contains(".svg#")) {
|
||||
String fontFilename = fontSourceString.substring(0, fontSourceString.indexOf(".svg#") + 5);
|
||||
urls.add(baseUri + fontFilename);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String fontSourceString;
|
||||
try {
|
||||
fontSourceString = jsonFont.getString(KMManager.KMKey_FontSource);
|
||||
if (fontSourceString.endsWith(".ttf") || fontSourceString.endsWith(".otf")) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && (fontSourceString.endsWith(".svg") || fontSourceString.endsWith(".woff"))) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && fontSourceString.contains(".svg#")) {
|
||||
String fontFilename = fontSourceString.substring(0, fontSourceString.indexOf(".svg#") + 5);
|
||||
urls.add(baseUri + fontFilename);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
|
||||
public static void addKeyboardDownloadEventListener(KeyboardEventHandler.OnKeyboardDownloadEventListener listener) {
|
||||
if (kbDownloadEventListeners == null) {
|
||||
kbDownloadEventListeners = new ArrayList<KeyboardEventHandler.OnKeyboardDownloadEventListener>();
|
||||
}
|
||||
|
||||
if (listener != null && !kbDownloadEventListeners.contains(listener)) {
|
||||
kbDownloadEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeKeyboardDownloadEventListener(KeyboardEventHandler.OnKeyboardDownloadEventListener listener) {
|
||||
if (kbDownloadEventListeners != null) {
|
||||
kbDownloadEventListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,24 +4,15 @@
|
|||
|
||||
package com.tavultesoft.kmea;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
|
|
@ -33,7 +24,6 @@ import android.graphics.Typeface;
|
|||
import android.inputmethodservice.InputMethodService;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.text.InputType;
|
||||
|
|
@ -53,9 +43,7 @@ import android.widget.FrameLayout;
|
|||
import android.widget.RelativeLayout;
|
||||
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.EventType;
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener;
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener;
|
||||
import com.tavultesoft.kmea.util.Connection;
|
||||
|
||||
public final class KMManager {
|
||||
|
||||
|
|
@ -86,7 +74,6 @@ public final class KMManager {
|
|||
private static InputMethodService IMService;
|
||||
private static boolean debugMode = false;
|
||||
private static boolean shouldAllowSetKeyboard = true;
|
||||
private static ArrayList<OnKeyboardDownloadEventListener> kbDownloadEventListeners = null;
|
||||
private static boolean didCopyAssets = false;
|
||||
private static GlobeKeyAction inappKbGlobeKeyAction = GlobeKeyAction.GLOBE_KEY_ACTION_SHOW_MENU;
|
||||
private static GlobeKeyAction sysKbGlobeKeyAction = GlobeKeyAction.GLOBE_KEY_ACTION_SHOW_MENU;
|
||||
|
|
@ -100,9 +87,6 @@ public final class KMManager {
|
|||
protected static KMKeyboard InAppKeyboard = null;
|
||||
protected static KMKeyboard SystemKeyboard = null;
|
||||
|
||||
protected static final String kKeymanApiBaseURL = "https://r.keymanweb.com/api/3.0/";
|
||||
private static final String kKeymanApiRemoteURL = "https://r.keymanweb.com/api/2.0/remote?url=";
|
||||
|
||||
// Keyman public keys
|
||||
public static final String KMKey_ID = "id";
|
||||
public static final String KMKey_Name = "name";
|
||||
|
|
@ -112,18 +96,12 @@ public final class KMManager {
|
|||
public static final String KMKey_KeyboardID = "kbId";
|
||||
public static final String KMKey_KeyboardName = "kbName";
|
||||
public static final String KMKey_KeyboardVersion = "version";
|
||||
public static final String KMKey_Keyboard = "keyboard";
|
||||
public static final String KMKey_LanguageKeyboards = "keyboards";
|
||||
public static final String KMKey_KeyboardFileSize = "fileSize";
|
||||
public static final String KMKey_Font = "font";
|
||||
public static final String KMKey_OskFont = "oskFont";
|
||||
public static final String KMKey_FontFamily = "family";
|
||||
public static final String KMKey_FontSource = "source";
|
||||
public static final String KMKey_FontFiles = "files";
|
||||
public static final String KMKey_Options = "options";
|
||||
public static final String KMKey_Language = "language";
|
||||
public static final String KMKey_Languages = "languages";
|
||||
public static final String KMKey_Filename = "filename";
|
||||
public static final String KMKey_KeyboardModified = "lastModified";
|
||||
public static final String KMKey_KeyboardRTL = "rtl";
|
||||
public static final String KMKey_CustomKeyboard = "CustomKeyboard";
|
||||
|
|
@ -131,8 +109,6 @@ public final class KMManager {
|
|||
public static final String KMKey_UserKeyboardIndex = "UserKeyboardIndex";
|
||||
|
||||
// Keyman internal keys
|
||||
protected static final String KMKey_KeyboardBaseURI = "keyboardBaseUri";
|
||||
protected static final String KMKey_FontBaseURI = "fontBaseUri";
|
||||
protected static final String KMKey_ShouldShowHelpBubble = "ShouldShowHelpBubble";
|
||||
|
||||
// Default Asset Paths
|
||||
|
|
@ -465,47 +441,53 @@ public final class KMManager {
|
|||
}
|
||||
|
||||
String[] files = legacyLanguagesDir.list();
|
||||
for (String filename : files) {
|
||||
// Handle keyboards missing version number
|
||||
if (filename.lastIndexOf("-") < 0) {
|
||||
if (filename.equals("us.js")) {
|
||||
File kbFile = new File(legacyLanguagesPath, filename);
|
||||
kbFile.delete();
|
||||
} else if (filename.endsWith(".js")) {
|
||||
// Append default version number to keyboard and move
|
||||
String newFilename = filename.substring(0, filename.lastIndexOf(".js")) + "-1.0.js";
|
||||
File kbFile = new File(legacyLanguagesPath, filename);
|
||||
kbFile.renameTo(new File(migratedDir, newFilename));
|
||||
}
|
||||
// Handle keyboards with version number
|
||||
} else {
|
||||
// Remove legacy default keyboards
|
||||
if (filename.startsWith(KMDefault_KeyboardID + "-")) {
|
||||
File legacyKbFile = new File(legacyLanguagesDir, filename);
|
||||
if (legacyKbFile.exists()) {
|
||||
legacyKbFile.delete();
|
||||
continue;
|
||||
if (files != null) {
|
||||
for (String filename : files) {
|
||||
// Handle keyboards missing version number
|
||||
if (filename.lastIndexOf("-") < 0) {
|
||||
if (filename.equals("us.js")) {
|
||||
File kbFile = new File(legacyLanguagesPath, filename);
|
||||
kbFile.delete();
|
||||
} else if (filename.endsWith(".js")) {
|
||||
// Append default version number to keyboard and move
|
||||
String newFilename = filename.substring(0, filename.lastIndexOf(".js")) + "-1.0.js";
|
||||
File kbFile = new File(legacyLanguagesPath, filename);
|
||||
kbFile.renameTo(new File(migratedDir, newFilename));
|
||||
}
|
||||
// Handle keyboards with version number
|
||||
} else {
|
||||
// Remove legacy default keyboards
|
||||
if (filename.startsWith(KMDefault_KeyboardID + "-")) {
|
||||
File legacyKbFile = new File(legacyLanguagesDir, filename);
|
||||
if (legacyKbFile.exists()) {
|
||||
legacyKbFile.delete();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate /languages/*.js keyboards
|
||||
File kbFile = new File(legacyLanguagesPath, filename);
|
||||
kbFile.renameTo(new File(migratedDir, filename));
|
||||
// Migrate /languages/*.js keyboards
|
||||
File kbFile = new File(legacyLanguagesPath, filename);
|
||||
kbFile.renameTo(new File(migratedDir, filename));
|
||||
}
|
||||
}
|
||||
|
||||
// Cleanup empty directory
|
||||
if (legacyLanguagesDir.list().length == 0) {
|
||||
legacyLanguagesDir.delete();
|
||||
}
|
||||
}
|
||||
|
||||
files = legacyFontsDir.list();
|
||||
for (String filename : files) {
|
||||
File fontFile = new File(legacyFontsPath, filename);
|
||||
fontFile.renameTo(new File(migratedDir, filename));
|
||||
}
|
||||
if (files != null) {
|
||||
for (String filename : files) {
|
||||
File fontFile = new File(legacyFontsPath, filename);
|
||||
fontFile.renameTo(new File(migratedDir, filename));
|
||||
}
|
||||
|
||||
// Cleanup empty directories
|
||||
if (legacyLanguagesDir.list().length == 0) {
|
||||
legacyLanguagesDir.delete();
|
||||
}
|
||||
if (legacyFontsDir.list().length == 0) {
|
||||
legacyFontsDir.delete();
|
||||
// Cleanup empty directory
|
||||
if (legacyFontsDir.list().length == 0) {
|
||||
legacyFontsDir.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -636,783 +618,6 @@ public final class KMManager {
|
|||
return KeyboardPickerActivity.getKeyboardsList(context);
|
||||
}
|
||||
|
||||
public static final class KMKeyboardDownloader {
|
||||
|
||||
public static void download(final Context context, final int languageIndex, final int keyboardIndex, final boolean showProgressDialog) {
|
||||
new AsyncTask<Void, Integer, Integer>() {
|
||||
private ProgressDialog progressDialog;
|
||||
private String packageID = "";
|
||||
private String languageID = "";
|
||||
private String keyboardID = "";
|
||||
private String languageName = "";
|
||||
private String keyboardName = "";
|
||||
private String kbVersion = "1.0";
|
||||
private String isCustom = "N";
|
||||
private String font = "";
|
||||
private String oskFont = null;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (showProgressDialog) {
|
||||
progressDialog = new ProgressDialog(context);
|
||||
progressDialog.setMessage("Downloading keyboard...");
|
||||
progressDialog.setCancelable(false);
|
||||
if (!((Activity) context).isFinishing()) {
|
||||
progressDialog.show();
|
||||
} else {
|
||||
cancel(true);
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
int ret = -1;
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
|
||||
if (isCancelled())
|
||||
return ret;
|
||||
|
||||
try {
|
||||
JSONArray languages = LanguageListActivity.languages();
|
||||
JSONObject options = LanguageListActivity.options();
|
||||
|
||||
if (languages == null || options == null) {
|
||||
throw new Exception("Language list is empty");
|
||||
}
|
||||
|
||||
JSONObject language = languages.getJSONObject(languageIndex);
|
||||
JSONArray keyboards = language.getJSONArray(KMKey_LanguageKeyboards);
|
||||
JSONObject keyboard = keyboards.getJSONObject(keyboardIndex);
|
||||
|
||||
if (keyboard.has(KMKey_PackageID)) {
|
||||
packageID = keyboard.getString(KMKey_PackageID);
|
||||
} else {
|
||||
packageID = KMDefault_LegacyPackageID;
|
||||
}
|
||||
keyboardID = keyboard.getString(KMKey_ID);
|
||||
languageID = language.getString(KMKey_ID);
|
||||
keyboardName = keyboard.getString(KMKey_Name);
|
||||
languageName = language.getString(KMKey_Name);
|
||||
kbVersion = keyboard.optString(KMKey_KeyboardVersion, "1.0");
|
||||
font = keyboard.optString(KMKey_Font, "");
|
||||
oskFont = keyboard.optString(KMKey_OskFont, null);
|
||||
String kbFilename = keyboard.optString(KMKey_Filename, "");
|
||||
|
||||
String kbUrl = options.getString(KMKey_KeyboardBaseURI) + kbFilename;
|
||||
urls.add(kbUrl);
|
||||
JSONObject jsonFont = keyboard.optJSONObject(KMKey_Font);
|
||||
JSONObject jsonOskFont = keyboard.optJSONObject(KMKey_OskFont);
|
||||
String fontBaseUri = options.getString(KMKey_FontBaseURI);
|
||||
ArrayList<String> fontUrls = fontUrls(jsonFont, fontBaseUri, true);
|
||||
ArrayList<String> oskFontUrls = fontUrls(jsonOskFont, fontBaseUri, true);
|
||||
if (fontUrls != null)
|
||||
urls.addAll(fontUrls);
|
||||
if (oskFontUrls != null) {
|
||||
for (String url : oskFontUrls) {
|
||||
if (!urls.contains(url))
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners: onDownloadStarted
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMKey_PackageID, packageID);
|
||||
keyboardInfo.put(KMKey_KeyboardID, keyboardID);
|
||||
keyboardInfo.put(KMKey_LanguageID, languageID);
|
||||
keyboardInfo.put(KMKey_KeyboardName, keyboardName);
|
||||
keyboardInfo.put(KMKey_LanguageName, languageName);
|
||||
keyboardInfo.put(KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMKey_CustomKeyboard, isCustom);
|
||||
keyboardInfo.put(KMKey_Font, font);
|
||||
if (oskFont != null)
|
||||
keyboardInfo.put(KMKey_OskFont, oskFont);
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, EventType.KEYBOARD_DOWNLOAD_STARTED, keyboardInfo, 0);
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
int result = 0;
|
||||
for (String url : urls) {
|
||||
String directory = KMDefault_AssetPackages + File.separator + packageID;
|
||||
File dir = new File(directory);
|
||||
String filename = "";
|
||||
if (url.endsWith(".js")) {
|
||||
int start = kbFilename.lastIndexOf("/");
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
} else {
|
||||
start++;
|
||||
}
|
||||
if (!kbFilename.contains("-")) {
|
||||
filename = kbFilename.substring(start, kbFilename.length() - 3) + "-" + kbVersion + ".js";
|
||||
} else {
|
||||
filename = kbFilename.substring(start);
|
||||
}
|
||||
}
|
||||
|
||||
result = FileDownloader.download(context, url, directory, filename);
|
||||
if (result < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e("Keyboard download", "Error: " + e);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... progress) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
if (showProgressDialog) {
|
||||
if (progressDialog != null && progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
progressDialog = null;
|
||||
} catch (Exception e) {
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners: onDownloadFinished
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMKey_PackageID, packageID);
|
||||
keyboardInfo.put(KMKey_KeyboardID, keyboardID);
|
||||
keyboardInfo.put(KMKey_LanguageID, languageID);
|
||||
keyboardInfo.put(KMKey_KeyboardName, keyboardName);
|
||||
keyboardInfo.put(KMKey_LanguageName, languageName);
|
||||
keyboardInfo.put(KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMKey_CustomKeyboard, isCustom);
|
||||
keyboardInfo.put(KMKey_Font, font);
|
||||
if (oskFont != null)
|
||||
keyboardInfo.put(KMKey_OskFont, oskFont);
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, EventType.KEYBOARD_DOWNLOAD_FINISHED, keyboardInfo, result);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
public static void download(final Context context, final String packageID, final String keyboardID, final String languageID, final boolean showProgressDialog) {
|
||||
new AsyncTask<Void, Integer, Integer>() {
|
||||
private ProgressDialog progressDialog;
|
||||
private String languageName = "";
|
||||
private String keyboardName = "";
|
||||
private String kbVersion = "1.0";
|
||||
private String isCustom = "N";
|
||||
private String font = "";
|
||||
private String oskFont = "";
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (showProgressDialog) {
|
||||
progressDialog = new ProgressDialog(context);
|
||||
progressDialog.setMessage("Downloading keyboard...");
|
||||
progressDialog.setCancelable(false);
|
||||
if (!((Activity) context).isFinishing()) {
|
||||
progressDialog.show();
|
||||
} else {
|
||||
cancel(true);
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
int ret = -1;
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
|
||||
if (isCancelled())
|
||||
return ret;
|
||||
|
||||
try {
|
||||
String exceptionStr = "Invalid keyboard";
|
||||
if (packageID == null || packageID.trim().isEmpty() ||
|
||||
languageID == null || languageID.trim().isEmpty() ||
|
||||
keyboardID == null || keyboardID.trim().isEmpty())
|
||||
throw new Exception(exceptionStr);
|
||||
|
||||
String deviceType = context.getResources().getString(R.string.device_type);
|
||||
if (deviceType.equals("AndroidTablet")) {
|
||||
deviceType = "androidtablet";
|
||||
} else {
|
||||
deviceType = "androidphone";
|
||||
}
|
||||
|
||||
String jsonUrl = String.format("%slanguages/%s/%s?device=%s", kKeymanApiBaseURL, languageID, keyboardID, deviceType);
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
JSONObject kbData = jsonParser.getJSONObjectFromUrl(jsonUrl);
|
||||
|
||||
exceptionStr = "Could not reach Keyman server";
|
||||
if (kbData == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
JSONObject options = kbData.optJSONObject(KMKey_Options);
|
||||
JSONObject language = kbData.optJSONObject(KMKey_Language);
|
||||
exceptionStr = "The keyboard could not be installed";
|
||||
if (options == null || language == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
JSONArray keyboards = language.getJSONArray(KMKey_LanguageKeyboards);
|
||||
String kbBaseUri = options.optString(KMKey_KeyboardBaseURI, "");
|
||||
String fontBaseUri = options.optString(KMKey_FontBaseURI, "");
|
||||
|
||||
if (keyboards == null || kbBaseUri.isEmpty())
|
||||
throw new Exception(exceptionStr);
|
||||
|
||||
JSONObject keyboard = keyboards.getJSONObject(0);
|
||||
if (keyboard == null)
|
||||
throw new Exception(exceptionStr);
|
||||
|
||||
languageName = language.optString(KMKey_Name, "");
|
||||
keyboardName = keyboard.optString(KMKey_Name, "");
|
||||
kbVersion = keyboard.optString(KMKey_KeyboardVersion, "1.0");
|
||||
font = keyboard.optString(KMKey_Font, "");
|
||||
oskFont = keyboard.optString(KMKey_OskFont, null);
|
||||
String kbFilename = keyboard.optString(KMKey_Filename, "");
|
||||
|
||||
if (keyboardName.isEmpty() || languageName.isEmpty() || kbFilename.isEmpty())
|
||||
throw new Exception(exceptionStr);
|
||||
|
||||
String kbUrl = kbBaseUri + kbFilename;
|
||||
urls.add(kbUrl);
|
||||
JSONObject jsonFont = keyboard.optJSONObject(KMKey_Font);
|
||||
JSONObject jsonOskFont = keyboard.optJSONObject(KMKey_OskFont);
|
||||
ArrayList<String> fontUrls = fontUrls(jsonFont, fontBaseUri, true);
|
||||
ArrayList<String> oskFontUrls = fontUrls(jsonOskFont, fontBaseUri, true);
|
||||
if (fontUrls != null)
|
||||
urls.addAll(fontUrls);
|
||||
if (oskFontUrls != null) {
|
||||
for (String url : oskFontUrls) {
|
||||
if (!urls.contains(url))
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners: onDownloadStarted
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMKey_PackageID, packageID);
|
||||
keyboardInfo.put(KMKey_KeyboardID, keyboardID);
|
||||
keyboardInfo.put(KMKey_LanguageID, languageID);
|
||||
keyboardInfo.put(KMKey_KeyboardName, keyboardName);
|
||||
keyboardInfo.put(KMKey_LanguageName, languageName);
|
||||
keyboardInfo.put(KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMKey_CustomKeyboard, isCustom);
|
||||
keyboardInfo.put(KMKey_Font, font);
|
||||
if (oskFont != null)
|
||||
keyboardInfo.put(KMKey_OskFont, oskFont);
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, EventType.KEYBOARD_DOWNLOAD_STARTED, keyboardInfo, 0);
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
int result = 0;
|
||||
for (String url : urls) {
|
||||
String directory = KMDefault_AssetPackages + File.separator + packageID;
|
||||
File dir = new File(directory);
|
||||
String filename = "";
|
||||
if (url.endsWith(".js")) {
|
||||
|
||||
int start = kbFilename.lastIndexOf("/");
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
} else {
|
||||
start++;
|
||||
}
|
||||
if (!kbFilename.contains("-")) {
|
||||
filename = kbFilename.substring(start, kbFilename.length() - 3) + "-" + kbVersion + ".js";
|
||||
} else {
|
||||
filename = kbFilename.substring(start);
|
||||
}
|
||||
}
|
||||
|
||||
result = FileDownloader.download(context, url, directory, filename);
|
||||
if (result < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e("Keyboard download", "Error: " + e);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... progress) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
if (showProgressDialog) {
|
||||
if (progressDialog != null && progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
progressDialog = null;
|
||||
} catch (Exception e) {
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners: onDownloadFinished
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMKey_KeyboardID, keyboardID);
|
||||
keyboardInfo.put(KMKey_LanguageID, languageID);
|
||||
keyboardInfo.put(KMKey_KeyboardName, keyboardName);
|
||||
keyboardInfo.put(KMKey_LanguageName, languageName);
|
||||
keyboardInfo.put(KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMKey_CustomKeyboard, isCustom);
|
||||
keyboardInfo.put(KMKey_Font, font);
|
||||
if (oskFont != null)
|
||||
keyboardInfo.put(KMKey_OskFont, oskFont);
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, EventType.KEYBOARD_DOWNLOAD_FINISHED, keyboardInfo, result);
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private static ArrayList<String> fontUrls(JSONObject jsonFont, String baseUri, boolean isOskFont) {
|
||||
if (jsonFont == null)
|
||||
return null;
|
||||
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
JSONArray fontSource = jsonFont.optJSONArray(KMKey_FontSource);
|
||||
if (fontSource != null) {
|
||||
int fcCount = fontSource.length();
|
||||
for (int i = 0; i < fcCount; i++) {
|
||||
String fontSourceString;
|
||||
try {
|
||||
fontSourceString = fontSource.getString(i);
|
||||
if (fontSourceString.endsWith(".ttf") || fontSourceString.endsWith(".otf")) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && (fontSourceString.endsWith(".svg") || fontSourceString.endsWith(".woff"))) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && fontSourceString.contains(".svg#")) {
|
||||
String fontFilename = fontSourceString.substring(0, fontSourceString.indexOf(".svg#") + 5);
|
||||
urls.add(baseUri + fontFilename);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String fontSourceString;
|
||||
try {
|
||||
fontSourceString = jsonFont.getString(KMKey_FontSource);
|
||||
if (fontSourceString.endsWith(".ttf") || fontSourceString.endsWith(".otf")) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && (fontSourceString.endsWith(".svg") || fontSourceString.endsWith(".woff"))) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && fontSourceString.contains(".svg#")) {
|
||||
String fontFilename = fontSourceString.substring(0, fontSourceString.indexOf(".svg#") + 5);
|
||||
urls.add(baseUri + fontFilename);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
|
||||
public static final class KMCustomKeyboardDownloader {
|
||||
|
||||
public static void download(final Context context, final String jsonUrl, final boolean isDirect, final boolean showProgressDialog) {
|
||||
new AsyncTask<Void, Integer, Integer>() {
|
||||
private ProgressDialog progressDialog;
|
||||
private String packageID = "";
|
||||
private String keyboardID = "";
|
||||
private String languageID = "";
|
||||
private String keyboardName = "";
|
||||
private String languageName = "";
|
||||
private String kbVersion = "1.0";
|
||||
private String isCustom = "Y";
|
||||
private String font = "";
|
||||
private String oskFont = "";
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
if (showProgressDialog) {
|
||||
progressDialog = new ProgressDialog(context);
|
||||
progressDialog.setMessage("Downloading keyboard...");
|
||||
progressDialog.setCancelable(false);
|
||||
if (!((Activity) context).isFinishing()) {
|
||||
progressDialog.show();
|
||||
} else {
|
||||
cancel(true);
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Integer doInBackground(Void... voids) {
|
||||
int ret = -1;
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
|
||||
if (isCancelled())
|
||||
return ret;
|
||||
|
||||
try {
|
||||
JSONParser jsonParser = new JSONParser();
|
||||
JSONObject customKb = null;
|
||||
if (isDirect) {
|
||||
customKb = jsonParser.getJSONObjectFromUrl(jsonUrl);
|
||||
} else {
|
||||
String deviceType = context.getResources().getString(R.string.device_type);
|
||||
if (deviceType.equals("AndroidTablet")) {
|
||||
deviceType = "androidtablet";
|
||||
} else {
|
||||
deviceType = "androidphone";
|
||||
}
|
||||
|
||||
String encodedUrl = URLEncoder.encode(jsonUrl, "utf-8");
|
||||
String remoteUrl = String.format("%s%s&device=%s", kKeymanApiRemoteURL, encodedUrl, deviceType);
|
||||
customKb = jsonParser.getJSONObjectFromUrl(remoteUrl);
|
||||
}
|
||||
|
||||
String exceptionStr = "Failed to fetch JSON object from the URL";
|
||||
if (customKb == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
JSONObject options = customKb.optJSONObject(KMKey_Options);
|
||||
exceptionStr = "The keyboard could not be installed";
|
||||
if (options == null) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
String kbBaseUri = options.optString(KMKey_KeyboardBaseURI, "");
|
||||
String fontBaseUri = options.optString(KMKey_FontBaseURI, "");
|
||||
|
||||
JSONObject keyboard = customKb.getJSONObject(KMKey_Keyboard);
|
||||
|
||||
if (keyboard == null || kbBaseUri.isEmpty()) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
JSONArray languages = keyboard.optJSONArray(KMKey_Languages);
|
||||
|
||||
packageID = keyboard.optString(KMKey_PackageID, "");
|
||||
if (packageID == null || packageID.isEmpty()) {
|
||||
packageID = KMDefault_LegacyPackageID;
|
||||
}
|
||||
keyboardID = keyboard.optString(KMKey_ID, "");
|
||||
keyboardName = keyboard.optString(KMKey_Name, "");
|
||||
kbVersion = keyboard.optString(KMKey_KeyboardVersion, "1.0");
|
||||
font = keyboard.optString(KMKey_Font, "").replace("\"" + KMManager.KMKey_Filename + "\"", "\"" + KMManager.KMKey_FontSource + "\"");
|
||||
oskFont = keyboard.optString(KMKey_OskFont, "").replace("\"" + KMManager.KMKey_Filename + "\"", "\"" + KMManager.KMKey_FontSource + "\"");
|
||||
if (oskFont.isEmpty()) {
|
||||
oskFont = null;
|
||||
}
|
||||
String kbFilename = keyboard.optString(KMKey_Filename, "");
|
||||
|
||||
if (packageID == null || packageID.isEmpty() ||
|
||||
languages == null || keyboardID.isEmpty() ||
|
||||
keyboardName.isEmpty() || kbFilename.isEmpty()) {
|
||||
throw new Exception(exceptionStr);
|
||||
}
|
||||
|
||||
String kbUrl = kbBaseUri + kbFilename;
|
||||
urls.add(kbUrl);
|
||||
JSONObject jsonFont = keyboard.optJSONObject(KMKey_Font);
|
||||
JSONObject jsonOskFont = keyboard.optJSONObject(KMKey_OskFont);
|
||||
ArrayList<String> fontUrls = fontUrls(jsonFont, fontBaseUri, true);
|
||||
ArrayList<String> oskFontUrls = fontUrls(jsonOskFont, fontBaseUri, true);
|
||||
if (fontUrls != null) {
|
||||
urls.addAll(fontUrls);
|
||||
}
|
||||
if (oskFontUrls != null) {
|
||||
for (String url : oskFontUrls) {
|
||||
if (!urls.contains(url)) {
|
||||
urls.add(url);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
languageID = "";
|
||||
languageName = "";
|
||||
int langCount = languages.length();
|
||||
for (int i = 0; i < langCount; i++) {
|
||||
languageID += languages.getJSONObject(i).getString(KMKey_ID);
|
||||
languageName += languages.getJSONObject(i).getString(KMKey_Name);
|
||||
if (i < langCount - 1) {
|
||||
languageID += ";";
|
||||
languageName += ";";
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners: onDownloadStarted
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMKey_PackageID, packageID);
|
||||
keyboardInfo.put(KMKey_KeyboardID, keyboardID);
|
||||
keyboardInfo.put(KMKey_LanguageID, languageID);
|
||||
keyboardInfo.put(KMKey_KeyboardName, keyboardName);
|
||||
keyboardInfo.put(KMKey_LanguageName, languageName);
|
||||
keyboardInfo.put(KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMKey_CustomKeyboard, isCustom);
|
||||
keyboardInfo.put(KMKey_Font, font);
|
||||
if (oskFont != null) {
|
||||
keyboardInfo.put(KMKey_OskFont, oskFont);
|
||||
}
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, EventType.KEYBOARD_DOWNLOAD_STARTED, keyboardInfo, 0);
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
int result = 0;
|
||||
for (String url : urls) {
|
||||
String directory = KMDefault_AssetPackages + File.separator + packageID;
|
||||
File dir = new File(directory);
|
||||
String filename = "";
|
||||
if (url.endsWith(".js")) {
|
||||
int start = kbFilename.lastIndexOf("/");
|
||||
if (start < 0) {
|
||||
start = 0;
|
||||
} else {
|
||||
start++;
|
||||
}
|
||||
if (!kbFilename.contains("-")) {
|
||||
filename = kbFilename.substring(start, kbFilename.length() - 3) + "-" + kbVersion + ".js";
|
||||
} else {
|
||||
filename = kbFilename.substring(start);
|
||||
}
|
||||
}
|
||||
|
||||
result = FileDownloader.download(context, url, directory, filename);
|
||||
if (result < 0) {
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e("Keyboard download", "Error: " + e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(Integer... progress) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Integer result) {
|
||||
if (showProgressDialog) {
|
||||
if (progressDialog != null && progressDialog.isShowing()) {
|
||||
try {
|
||||
progressDialog.dismiss();
|
||||
progressDialog = null;
|
||||
} catch (Exception e) {
|
||||
progressDialog = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Notify listeners: onDownloadFinished
|
||||
if (kbDownloadEventListeners != null) {
|
||||
HashMap<String, String> keyboardInfo = new HashMap<String, String>();
|
||||
keyboardInfo.put(KMKey_PackageID, packageID);
|
||||
keyboardInfo.put(KMKey_KeyboardID, keyboardID);
|
||||
keyboardInfo.put(KMKey_LanguageID, languageID);
|
||||
keyboardInfo.put(KMKey_KeyboardName, keyboardName);
|
||||
keyboardInfo.put(KMKey_LanguageName, languageName);
|
||||
keyboardInfo.put(KMKey_KeyboardVersion, kbVersion);
|
||||
keyboardInfo.put(KMKey_CustomKeyboard, isCustom);
|
||||
keyboardInfo.put(KMKey_Font, font);
|
||||
if (oskFont != null)
|
||||
keyboardInfo.put(KMKey_OskFont, oskFont);
|
||||
KeyboardEventHandler.notifyListeners(kbDownloadEventListeners, EventType.KEYBOARD_DOWNLOAD_FINISHED, keyboardInfo, result);
|
||||
}
|
||||
|
||||
if (result > 0) {
|
||||
if (KMManager.InAppKeyboard != null) {
|
||||
InAppKeyboard.loadKeyboard();
|
||||
}
|
||||
if ( KMManager.SystemKeyboard != null) {
|
||||
SystemKeyboard.loadKeyboard();
|
||||
}
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
|
||||
private static ArrayList<String> fontUrls(JSONObject jsonFont, String baseUri, boolean isOskFont) {
|
||||
if (jsonFont == null)
|
||||
return null;
|
||||
|
||||
ArrayList<String> urls = new ArrayList<String>();
|
||||
JSONArray fontSource = jsonFont.optJSONArray(KMKey_FontSource);
|
||||
if (fontSource == null)
|
||||
fontSource = jsonFont.optJSONArray(KMKey_Filename); // Font filename is deprecated
|
||||
|
||||
if (fontSource != null) {
|
||||
int fcCount = fontSource.length();
|
||||
for (int i = 0; i < fcCount; i++) {
|
||||
String fontSourceString;
|
||||
try {
|
||||
fontSourceString = fontSource.getString(i);
|
||||
if (fontSourceString.endsWith(".ttf") || fontSourceString.endsWith(".otf")) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && (fontSourceString.endsWith(".svg") || fontSourceString.endsWith(".woff"))) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && fontSourceString.contains(".svg#")) {
|
||||
String fontFilename = fontSourceString.substring(0, fontSourceString.indexOf(".svg#") + 5);
|
||||
urls.add(baseUri + fontFilename);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String fontSourceString;
|
||||
try {
|
||||
fontSourceString = jsonFont.optString(KMKey_FontSource, null);
|
||||
if (fontSourceString == null)
|
||||
fontSourceString = jsonFont.getString(KMKey_Filename); // Font filename is deprecated
|
||||
|
||||
if (fontSourceString.endsWith(".ttf") || fontSourceString.endsWith(".otf")) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && (fontSourceString.endsWith(".svg") || fontSourceString.endsWith(".woff"))) {
|
||||
urls.add(baseUri + fontSourceString);
|
||||
} else if (isOskFont && fontSourceString.contains(".svg#")) {
|
||||
String fontFilename = fontSourceString.substring(0, fontSourceString.indexOf(".svg#") + 5);
|
||||
urls.add(baseUri + fontFilename);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return urls;
|
||||
}
|
||||
}
|
||||
|
||||
private static final class FileDownloader {
|
||||
|
||||
/**
|
||||
* Utility to download a file from urlStr and store it at directory/filename
|
||||
* @param context
|
||||
* @param urlStr URL of the file to download
|
||||
* @param directory Path to store the file. If directory does not exist, it will be created
|
||||
* @param filename Destination filename. If blank, it will use the filename from the URL
|
||||
* @return
|
||||
*/
|
||||
public static int download(Context context, String urlStr, String directory, String filename) {
|
||||
int ret = -1;
|
||||
String fileName = "";
|
||||
String tmpFileName = "";
|
||||
File tmpFile = null;
|
||||
File file = null;
|
||||
|
||||
try {
|
||||
if (directory == null) {
|
||||
directory = "";
|
||||
}
|
||||
directory = directory.trim();
|
||||
|
||||
String dirPath;
|
||||
if (directory.length() != 0) {
|
||||
directory = directory + "/";
|
||||
dirPath = context.getDir("data", Context.MODE_PRIVATE) + "/" + directory;
|
||||
} else {
|
||||
dirPath = context.getDir("data", Context.MODE_PRIVATE).toString();
|
||||
}
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdir();
|
||||
}
|
||||
|
||||
if (Connection.initialize(urlStr)) {
|
||||
InputStream binStream = new BufferedInputStream(Connection.getInputStream(), 4096);
|
||||
byte[] buff = new byte[4096];
|
||||
|
||||
filename = filename.trim();
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
fileName = Connection.getFile().substring(Connection.getFile().lastIndexOf('/') + 1);
|
||||
if (fileName.lastIndexOf(".js") > 0 && !fileName.contains("-")) {
|
||||
fileName = fileName.substring(0, filename.lastIndexOf(".js")) + "-1.0.js";
|
||||
}
|
||||
} else {
|
||||
fileName = filename;
|
||||
}
|
||||
tmpFileName = String.format("%s.tmp", fileName);
|
||||
file = new File(dirPath, fileName);
|
||||
tmpFile = new File(dirPath, tmpFileName);
|
||||
FileOutputStream fos = new FileOutputStream(tmpFile);
|
||||
|
||||
int len;
|
||||
while ((len = binStream.read(buff)) != -1) {
|
||||
fos.write(buff, 0, len);
|
||||
}
|
||||
|
||||
fos.flush();
|
||||
fos.close();
|
||||
binStream.close();
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e("FD: Download failed!", "Error: " + e);
|
||||
} finally {
|
||||
if (ret > 0) {
|
||||
if (tmpFile.exists() && tmpFile.length() > 0) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
if (!tmpFile.renameTo(file)) {
|
||||
ret = -1;
|
||||
} else if (isDebugMode()) {
|
||||
Log.d("FD: Download finished", "Filename = " + file.toString());
|
||||
}
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
if (tmpFile.exists()) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
if (isDebugMode()) {
|
||||
Log.d("FD: Could not download", "Filename = " + file.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Connection.disconnect();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean addKeyboard(Context context, HashMap<String, String> keyboardInfo) {
|
||||
return KeyboardPickerActivity.addKeyboard(context, keyboardInfo);
|
||||
}
|
||||
|
|
@ -1731,22 +936,6 @@ public final class KMManager {
|
|||
KMKeyboard.removeOnKeyboardEventListener(listener);
|
||||
}
|
||||
|
||||
public static void addKeyboardDownloadEventListener(OnKeyboardDownloadEventListener listener) {
|
||||
if (kbDownloadEventListeners == null) {
|
||||
kbDownloadEventListeners = new ArrayList<OnKeyboardDownloadEventListener>();
|
||||
}
|
||||
|
||||
if (listener != null && !kbDownloadEventListeners.contains(listener)) {
|
||||
kbDownloadEventListeners.add(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeKeyboardDownloadEventListener(OnKeyboardDownloadEventListener listener) {
|
||||
if (kbDownloadEventListeners != null) {
|
||||
kbDownloadEventListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
public static int getKeyboardHeight(Context context) {
|
||||
return (int) context.getResources().getDimension(R.dimen.keyboard_height);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,8 @@ import org.json.JSONObject;
|
|||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.DialogFragment;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
|
|
@ -73,7 +72,7 @@ public final class KeyboardListActivity extends Activity implements OnKeyboardDo
|
|||
final String langName = language.getString(KMManager.KMKey_Name);
|
||||
textView.setText(langName);
|
||||
|
||||
keyboards = language.getJSONArray(KMManager.KMKey_LanguageKeyboards);
|
||||
keyboards = language.getJSONArray(KMKeyboardDownloaderActivity.KMKey_LanguageKeyboards);
|
||||
keyboardsArrayList = new ArrayList<HashMap<String, String>>();
|
||||
|
||||
int length = keyboards.length();
|
||||
|
|
@ -103,45 +102,23 @@ public final class KeyboardListActivity extends Activity implements OnKeyboardDo
|
|||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, final int position, long id) {
|
||||
HashMap<String, String> kbInfo = LanguageListActivity.getKeyboardInfo(langIndex, position);
|
||||
String pkgID = kbInfo.get(KMManager.KMKey_PackageID);
|
||||
String kbID = kbInfo.get(KMManager.KMKey_KeyboardID);
|
||||
String langID = kbInfo.get(KMManager.KMKey_LanguageID);
|
||||
final String pkgID = kbInfo.get(KMManager.KMKey_PackageID);
|
||||
final String kbID = kbInfo.get(KMManager.KMKey_KeyboardID);
|
||||
final 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);
|
||||
KMManager.KeyboardState kbState = KMManager.getKeyboardState(context, pkgID, kbID, langID);
|
||||
//if (kbState == KMManager.KeyboardState.KEYBOARD_STATE_NEEDS_DOWNLOAD) {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
dialogBuilder.setTitle(langName + ": " + kbName);
|
||||
dialogBuilder.setMessage("Would you like to download this keyboard?");
|
||||
dialogBuilder.setPositiveButton("Download", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Download keyboard
|
||||
if (KMManager.hasConnection(context)) {
|
||||
KMManager.KMKeyboardDownloader.download(context, langIndex, position, true);
|
||||
} else {
|
||||
Toast.makeText(context, "No internet connection", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel
|
||||
}
|
||||
});
|
||||
Bundle args = new Bundle();
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_PKG_ID, pkgID);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_KB_ID, kbID);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_LANG_ID, langID);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_KB_NAME, kbName);
|
||||
args.putString(KMKeyboardDownloaderActivity.ARG_LANG_NAME, langName);
|
||||
args.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_CUSTOM, false);
|
||||
Intent i = new Intent(getApplicationContext(), KMKeyboardDownloaderActivity.class);
|
||||
i.putExtras(args);
|
||||
startActivity(i);
|
||||
|
||||
AlertDialog dialog = dialogBuilder.create();
|
||||
dialog.show();
|
||||
/*} else {
|
||||
KeyboardPickerActivity.addKeyboard(context, kbInfo);
|
||||
if (KMManager.InAppKeyboard != null)
|
||||
KMManager.InAppKeyboard.setKeyboard(kbID, langID, kbName, langName, kFont, kOskFont);
|
||||
if (KMManager.SystemKeyboard != null)
|
||||
KMManager.SystemKeyboard.setKeyboard(kbID, langID, kbName, langName, kFont, kOskFont);
|
||||
finish();
|
||||
}*/
|
||||
}
|
||||
});
|
||||
} catch (JSONException e) {
|
||||
|
|
@ -152,13 +129,15 @@ public final class KeyboardListActivity extends Activity implements OnKeyboardDo
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
KMManager.addKeyboardDownloadEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
KMManager.removeKeyboardDownloadEventListener(this);
|
||||
|
||||
// Intentionally not removing KeyboardDownloadEventListener to
|
||||
// ensure onKeyboardDownloadFinished() gets called
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -180,7 +180,7 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
KMManager.addKeyboardDownloadEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
BaseAdapter adapter = (BaseAdapter) listAdapter;
|
||||
adapter.notifyDataSetChanged();
|
||||
int curKbPos = getCurrentKeyboardIndex();
|
||||
|
|
@ -234,7 +234,10 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
KMManager.removeKeyboardDownloadEventListener(this);
|
||||
|
||||
// Intentionally not removing KeyboardDownloadEventListener to
|
||||
// ensure onKeyboardDownloadFinished() gets called
|
||||
|
||||
if (didUpdate) {
|
||||
if (KMManager.InAppKeyboard != null) {
|
||||
KMManager.InAppKeyboard.loadKeyboard();
|
||||
|
|
@ -400,7 +403,7 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
list = (ArrayList<HashMap<String, String>>) inputStream.readObject();
|
||||
inputStream.close();
|
||||
} catch (Exception e) {
|
||||
Log.e("Failed to read keyboards list", "Error: " + e);
|
||||
Log.e("KeyboardPickerActivity", "Failed to read keyboards list. Error: " + e);
|
||||
list = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -563,10 +566,10 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
String languageID = keyboardsList.get(i).get(KMManager.KMKey_LanguageID);
|
||||
String keyboardID = keyboardsList.get(i).get(KMManager.KMKey_KeyboardID);
|
||||
String kbVersion = keyboardsList.get(i).get(KMManager.KMKey_KeyboardVersion);
|
||||
String url = String.format("%slanguages/%s/%s?device=%s", KMManager.kKeymanApiBaseURL, languageID, keyboardID, deviceType);
|
||||
String url = String.format("%slanguages/%s/%s?device=%s", KMKeyboardDownloaderActivity.kKeymanApiBaseURL, languageID, keyboardID, deviceType);
|
||||
JSONObject kbData = jsonParser.getJSONObjectFromUrl(url);
|
||||
JSONObject language = kbData.optJSONObject(KMManager.KMKey_Language);
|
||||
JSONArray keyboards = language.getJSONArray(KMManager.KMKey_LanguageKeyboards);
|
||||
JSONObject language = kbData.optJSONObject(KMKeyboardDownloaderActivity.KMKey_Language);
|
||||
JSONArray keyboards = language.getJSONArray(KMKeyboardDownloaderActivity.KMKey_LanguageKeyboards);
|
||||
JSONObject keyboard = keyboards.getJSONObject(0);
|
||||
String newKbVersion = keyboard.optString(KMManager.KMKey_KeyboardVersion, "1.0");
|
||||
String kbKey = String.format("%s_%s", languageID, keyboardID);
|
||||
|
|
@ -615,10 +618,12 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
if (KMManager.hasConnection(context)) {
|
||||
int len = keyboardsList.size();
|
||||
for (int i = 0; i < len; i++) {
|
||||
String packageID = keyboardsList.get(i).get(KMManager.KMKey_PackageID);
|
||||
String languageID = keyboardsList.get(i).get(KMManager.KMKey_LanguageID);
|
||||
String keyboardID = keyboardsList.get(i).get(KMManager.KMKey_KeyboardID);
|
||||
String kbKey = String.format("%s_%s", languageID, keyboardID);
|
||||
String pkgID = keyboardsList.get(i).get(KMManager.KMKey_PackageID);
|
||||
String kbID = keyboardsList.get(i).get(KMManager.KMKey_KeyboardID);
|
||||
String langID = keyboardsList.get(i).get(KMManager.KMKey_LanguageID);
|
||||
String kbKey = String.format("%s_%s", langID, kbID);
|
||||
String langName = keyboardsList.get(i).get(KMManager.KMKey_LanguageName);
|
||||
String kbName = keyboardsList.get(i).get(KMManager.KMKey_KeyboardName);
|
||||
String kbVersion = keyboardsList.get(i).get(KMManager.KMKey_KeyboardVersion);
|
||||
String newKbVersion = keyboardVersions.get(kbKey);
|
||||
if (newKbVersion != null) {
|
||||
|
|
@ -631,7 +636,16 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
updateProgress.show();
|
||||
}
|
||||
|
||||
KMManager.KMKeyboardDownloader.download(context, packageID, keyboardID, languageID, false);
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_PKG_ID, pkgID);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_KB_ID, kbID);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANG_ID, langID);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_KB_NAME, kbName);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANG_NAME, langName);
|
||||
bundle.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_CUSTOM, false);
|
||||
Intent intent = new Intent(context, KMKeyboardDownloaderActivity.class);
|
||||
intent.putExtras(bundle);
|
||||
context.startActivity(intent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -702,6 +716,11 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
String languageID = keyboardInfo.get(KMManager.KMKey_LanguageID);
|
||||
String kbKey = String.format("%s_%s", languageID, keyboardID);
|
||||
int index = getKeyboardIndex(this, kbKey);
|
||||
if (index == -1) {
|
||||
// Add the downloaded keyboard if not found
|
||||
addKeyboard(this, keyboardInfo);
|
||||
index = getKeyboardIndex(this, kbKey);
|
||||
}
|
||||
keyboardsList.set(index, keyboardInfo);
|
||||
saveKeyboardsList(this);
|
||||
} else if (result < 0) {
|
||||
|
|
@ -738,5 +757,8 @@ public final class KeyboardPickerActivity extends Activity implements OnKeyboard
|
|||
checkingUpdates = false;
|
||||
}
|
||||
}
|
||||
if (updateProgress != null && updateProgress.isShowing()) {
|
||||
updateProgress.dismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,10 +24,8 @@ import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.ProgressDialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Bundle;
|
||||
|
|
@ -97,7 +95,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
KMManager.addKeyboardDownloadEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
if (!didExecuteParser) {
|
||||
didExecuteParser = true;
|
||||
new JSONParse().execute();
|
||||
|
|
@ -107,7 +105,9 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
KMManager.removeKeyboardDownloadEventListener(this);
|
||||
|
||||
// Intentionally not removing KeyboardDownloadEventListener to
|
||||
// ensure onKeyboardDownloadFinished() gets called
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -148,7 +148,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
String langName = language.getString(KMManager.KMKey_Name);
|
||||
String pkgID;
|
||||
|
||||
JSONArray keyboards = language.getJSONArray(KMManager.KMKey_LanguageKeyboards);
|
||||
JSONArray keyboards = language.getJSONArray(KMKeyboardDownloaderActivity.KMKey_LanguageKeyboards);
|
||||
if (keyboards.getJSONObject(keyboardIndex).has(KMManager.KMKey_PackageID)) {
|
||||
pkgID = keyboards.getJSONObject(keyboardIndex).getString(KMManager.KMKey_PackageID);
|
||||
} else {
|
||||
|
|
@ -187,8 +187,8 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
return null;
|
||||
}
|
||||
|
||||
languages = jsonObj.getJSONObject(KMManager.KMKey_Languages).getJSONArray(KMManager.KMKey_Languages);
|
||||
options = jsonObj.getJSONObject(KMManager.KMKey_Options);
|
||||
languages = jsonObj.getJSONObject(KMKeyboardDownloaderActivity.KMKey_Languages).getJSONArray(KMKeyboardDownloaderActivity.KMKey_Languages);
|
||||
options = jsonObj.getJSONObject(KMKeyboardDownloaderActivity.KMKey_Options);
|
||||
keyboardsInfo = new HashMap<String, HashMap<String, String>>();
|
||||
keyboardModifiedDates = new HashMap<String, String>();
|
||||
|
||||
|
|
@ -204,7 +204,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
String kbVersion = "1.0";
|
||||
String isCustom = "N";
|
||||
String kbFont = "";
|
||||
JSONArray langKeyboards = language.getJSONArray(KMManager.KMKey_LanguageKeyboards);
|
||||
JSONArray langKeyboards = language.getJSONArray(KMKeyboardDownloaderActivity.KMKey_LanguageKeyboards);
|
||||
JSONObject keyboard = null;
|
||||
|
||||
int kbLength = langKeyboards.length();
|
||||
|
|
@ -272,7 +272,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
jsonObj = new JSONObject(objInput.readObject().toString());
|
||||
objInput.close();
|
||||
} catch (Exception e) {
|
||||
Log.e("Failed to read from cache file", "Error: " + e);
|
||||
Log.e("LanguageListActivity", "Failed to read from cache file. Error: " + e);
|
||||
jsonObj = null;
|
||||
}
|
||||
|
||||
|
|
@ -287,7 +287,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
objOutput.writeObject(jsonObj.toString());
|
||||
objOutput.close();
|
||||
} catch (Exception e) {
|
||||
Log.e("Failed to save to cache file", "Error: " + e);
|
||||
Log.e("LanguageListActivity", "Failed to save to cache file. Error: " + e);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -361,7 +361,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
deviceType = "androidphone";
|
||||
}
|
||||
|
||||
jsonObj = jsonParser.getJSONObjectFromUrl(KMManager.kKeymanApiBaseURL + "languages?device=" + deviceType);
|
||||
jsonObj = jsonParser.getJSONObjectFromUrl(KMKeyboardDownloaderActivity.kKeymanApiBaseURL + "languages?device=" + deviceType);
|
||||
} catch (Exception e) {
|
||||
jsonObj = null;
|
||||
}
|
||||
|
|
@ -392,8 +392,8 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
}
|
||||
|
||||
try {
|
||||
languages = jsonObj.getJSONObject(KMManager.KMKey_Languages).getJSONArray(KMManager.KMKey_Languages);
|
||||
options = jsonObj.getJSONObject(KMManager.KMKey_Options);
|
||||
languages = jsonObj.getJSONObject(KMKeyboardDownloaderActivity.KMKey_Languages).getJSONArray(KMKeyboardDownloaderActivity.KMKey_Languages);
|
||||
options = jsonObj.getJSONObject(KMKeyboardDownloaderActivity.KMKey_Options);
|
||||
keyboardsInfo = new HashMap<String, HashMap<String, String>>();
|
||||
keyboardModifiedDates = new HashMap<String, String>();
|
||||
|
||||
|
|
@ -411,7 +411,7 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
String kbFont = "";
|
||||
String icon = "0";
|
||||
String isEnabled = "true";
|
||||
JSONArray langKeyboards = language.getJSONArray(KMManager.KMKey_LanguageKeyboards);
|
||||
JSONArray langKeyboards = language.getJSONArray(KMKeyboardDownloaderActivity.KMKey_LanguageKeyboards);
|
||||
JSONObject keyboard = null;
|
||||
|
||||
int kbLength = langKeyboards.length();
|
||||
|
|
@ -494,44 +494,20 @@ public final class LanguageListActivity extends Activity implements OnKeyboardDo
|
|||
startActivity(i);
|
||||
} else {
|
||||
HashMap<String, String> kbInfo = getKeyboardInfo(selectedIndex, 0);
|
||||
String pkgID = kbInfo.get(KMManager.KMKey_PackageID);
|
||||
String kbID = kbInfo.get(KMManager.KMKey_KeyboardID);
|
||||
String langID = kbInfo.get(KMManager.KMKey_LanguageID);
|
||||
String kFont = kbInfo.get(KMManager.KMKey_Font);
|
||||
String kOskFont = kbInfo.get(KMManager.KMKey_OskFont);
|
||||
KMManager.KeyboardState kbState = KMManager.getKeyboardState(context, pkgID, kbID, langID);
|
||||
//if (kbState == KMManager.KeyboardState.KEYBOARD_STATE_NEEDS_DOWNLOAD) {
|
||||
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
|
||||
dialogBuilder.setTitle(langName + ": " + kbName);
|
||||
dialogBuilder.setMessage("Would you like to download this keyboard?");
|
||||
dialogBuilder.setPositiveButton("Download", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Download keyboard
|
||||
if (KMManager.hasConnection(context)) {
|
||||
KMManager.KMKeyboardDownloader.download(context, position, 0, true);
|
||||
} else {
|
||||
Toast.makeText(context, "No internet connection", Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
});
|
||||
final String pkgID = kbInfo.get(KMManager.KMKey_PackageID);
|
||||
final String kbID = kbInfo.get(KMManager.KMKey_KeyboardID);
|
||||
final String langID = kbInfo.get(KMManager.KMKey_LanguageID);
|
||||
|
||||
dialogBuilder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Cancel
|
||||
}
|
||||
});
|
||||
|
||||
AlertDialog dialog = dialogBuilder.create();
|
||||
dialog.show();
|
||||
/*}
|
||||
else {
|
||||
KeyboardPickerActivity.addKeyboard(context, kbInfo);
|
||||
if (KMManager.InAppKeyboard != null)
|
||||
KMManager.InAppKeyboard.setKeyboard(kbID, langID, kbName, langName, kFont, kOskFont);
|
||||
if (KMManager.SystemKeyboard != null)
|
||||
KMManager.SystemKeyboard.setKeyboard(kbID, langID, kbName, langName, kFont, kOskFont);
|
||||
finish();
|
||||
}*/
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_PKG_ID, pkgID);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_KB_ID, kbID);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANG_ID, langID);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_KB_NAME, kbName);
|
||||
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANG_NAME, langName);
|
||||
bundle.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_CUSTOM, false);
|
||||
Intent i = new Intent(getApplicationContext(), KMKeyboardDownloaderActivity.class);
|
||||
i.putExtras(bundle);
|
||||
startActivity(i);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
package com.tavultesoft.kmea.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import com.tavultesoft.kmea.KMManager;
|
||||
|
||||
import java.io.BufferedInputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
|
||||
public final class FileDownloader {
|
||||
|
||||
/**
|
||||
* Utility to download a file from urlStr and store it at directory/filename.
|
||||
* If the directory does not exist, it will be created.
|
||||
* @param context
|
||||
* @param urlStr Source
|
||||
* @param directory Destination path.
|
||||
* @param filename Destination filename. If blank, it will use the filename from the URL
|
||||
* @return
|
||||
*/
|
||||
public static int download(Context context, String urlStr, String directory, String filename) {
|
||||
final int BUFFER_SIZE = 4096;
|
||||
int ret = -1;
|
||||
String fileName = "";
|
||||
String tmpFileName = "";
|
||||
File tmpFile = null;
|
||||
File file = null;
|
||||
|
||||
try {
|
||||
if (directory == null) {
|
||||
directory = "";
|
||||
}
|
||||
directory = directory.trim();
|
||||
|
||||
String dirPath;
|
||||
if (directory.length() != 0) {
|
||||
directory = directory + "/";
|
||||
dirPath = context.getDir("data", Context.MODE_PRIVATE) + "/" + directory;
|
||||
} else {
|
||||
dirPath = context.getDir("data", Context.MODE_PRIVATE).toString();
|
||||
}
|
||||
File dir = new File(dirPath);
|
||||
if (!dir.exists()) {
|
||||
dir.mkdir();
|
||||
}
|
||||
|
||||
if (Connection.initialize(urlStr)) {
|
||||
InputStream binStream = new BufferedInputStream(Connection.getInputStream(), BUFFER_SIZE);
|
||||
byte[] buff = new byte[BUFFER_SIZE];
|
||||
|
||||
filename = filename.trim();
|
||||
if (filename == null || filename.isEmpty()) {
|
||||
fileName = Connection.getFile().substring(Connection.getFile().lastIndexOf('/') + 1);
|
||||
if (fileName.lastIndexOf(".js") > 0 && !fileName.contains("-")) {
|
||||
fileName = fileName.substring(0, filename.lastIndexOf(".js")) + "-1.0.js";
|
||||
}
|
||||
} else {
|
||||
fileName = filename;
|
||||
}
|
||||
tmpFileName = String.format("%s.tmp", fileName);
|
||||
file = new File(dirPath, fileName);
|
||||
tmpFile = new File(dirPath, tmpFileName);
|
||||
FileOutputStream fos = new FileOutputStream(tmpFile);
|
||||
|
||||
int len;
|
||||
while ((len = binStream.read(buff)) != -1) {
|
||||
fos.write(buff, 0, len);
|
||||
}
|
||||
|
||||
fos.flush();
|
||||
fos.close();
|
||||
binStream.close();
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ret = -1;
|
||||
Log.e("FileDownloader", "Download failed! Error: " + e);
|
||||
} finally {
|
||||
if (ret > 0) {
|
||||
if (tmpFile.exists() && tmpFile.length() > 0) {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
if (!tmpFile.renameTo(file)) {
|
||||
ret = -1;
|
||||
} else if (KMManager.isDebugMode()) {
|
||||
Log.d("FileDownloader", "Download finished for filename " + file.toString());
|
||||
}
|
||||
} else {
|
||||
ret = -1;
|
||||
}
|
||||
} else {
|
||||
if (file.exists()) {
|
||||
file.delete();
|
||||
}
|
||||
if (tmpFile.exists()) {
|
||||
tmpFile.delete();
|
||||
}
|
||||
if (KMManager.isDebugMode()) {
|
||||
Log.d("FileDownloader", "Could not download filename " + file.toString());
|
||||
}
|
||||
}
|
||||
|
||||
Connection.disconnect();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@ import android.util.Log;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.tavultesoft.kmea.KMKeyboardDownloaderActivity;
|
||||
import com.tavultesoft.kmea.KMManager;
|
||||
import com.tavultesoft.kmea.KMTextView;
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener;
|
||||
|
|
@ -38,6 +39,7 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
kbInfo.put(KMManager.KMKey_LanguageName, "Tamil");
|
||||
kbInfo.put(KMManager.KMKey_KeyboardVersion, "1.1");
|
||||
kbInfo.put(KMManager.KMKey_Font, "aava1.ttf");
|
||||
//kbInfo.put(KMManager.KMKey_Font, KMManager.KMDefault_KeyboardFont); // Use the default font
|
||||
KMManager.addKeyboard(this, kbInfo);
|
||||
}
|
||||
|
||||
|
|
@ -68,7 +70,7 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
super.onResume();
|
||||
KMManager.onResume();
|
||||
KMManager.addKeyboardEventListener(this);
|
||||
KMManager.addKeyboardDownloadEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -76,7 +78,9 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
super.onPause();
|
||||
KMManager.onPause();
|
||||
KMManager.removeKeyboardEventListener(this);
|
||||
KMManager.removeKeyboardDownloadEventListener(this);
|
||||
|
||||
// Intentionally not removing KeyboardDownloadEventListener to
|
||||
// ensure onKeyboardDownloadFinished() gets called
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ public class SystemKeyboard extends InputMethodService implements OnKeyboardEven
|
|||
kbInfo.put(KMManager.KMKey_LanguageName, "Tamil");
|
||||
kbInfo.put(KMManager.KMKey_KeyboardVersion, "1.1");
|
||||
kbInfo.put(KMManager.KMKey_Font, "aava1.ttf");
|
||||
//kbInfo.put(KMManager.KMKey_Font, KMManager.KMDefault_KeyboardFont); // Use the default font
|
||||
KMManager.addKeyboard(this, kbInfo);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import android.util.Log;
|
|||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
import com.tavultesoft.kmea.KMKeyboardDownloaderActivity;
|
||||
import com.tavultesoft.kmea.KMManager;
|
||||
import com.tavultesoft.kmea.KMTextView;
|
||||
import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener;
|
||||
|
|
@ -82,7 +83,7 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
super.onResume();
|
||||
KMManager.onResume();
|
||||
KMManager.addKeyboardEventListener(this);
|
||||
KMManager.addKeyboardDownloadEventListener(this);
|
||||
KMKeyboardDownloaderActivity.addKeyboardDownloadEventListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -90,7 +91,9 @@ public class MainActivity extends Activity implements OnKeyboardEventListener, O
|
|||
super.onPause();
|
||||
KMManager.onPause();
|
||||
KMManager.removeKeyboardEventListener(this);
|
||||
KMManager.removeKeyboardDownloadEventListener(this);
|
||||
|
||||
// Intentionally not removing KeyboardDownloadEventListener to
|
||||
// ensure onKeyboardDownloadFinished() gets called
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
C040E5101F8606E300901EE4 /* TextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E50F1F8606E300901EE4 /* TextField.swift */; };
|
||||
C040E5121F86107E00901EE4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E5111F86107E00901EE4 /* AppDelegate.swift */; };
|
||||
C040E5141F86108900901EE4 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C040E5131F86108900901EE4 /* MainViewController.swift */; };
|
||||
C042ED5D1FC6A65A001D82F4 /* Version.swift in Sources */ = {isa = PBXBuildFile; fileRef = C042ED5C1FC6A65A001D82F4 /* Version.swift */; };
|
||||
C04514881F85D7F500D88416 /* KeyboardViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04514871F85D7F500D88416 /* KeyboardViewController.swift */; };
|
||||
C045148A1F85DF9100D88416 /* InputViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04514891F85DF9000D88416 /* InputViewController.swift */; };
|
||||
C0452BAB1F9F1FE10064431A /* Language.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0452BAA1F9F1FE10064431A /* Language.swift */; };
|
||||
|
|
@ -87,6 +88,8 @@
|
|||
C07A9D8C1FD176AB00828ADD /* KeyboardRepositoryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A9D8B1FD176AB00828ADD /* KeyboardRepositoryDelegate.swift */; };
|
||||
C07A9D8E1FD1798900828ADD /* APIKeyboardRepository.swift in Sources */ = {isa = PBXBuildFile; fileRef = C07A9D8D1FD1798900828ADD /* APIKeyboardRepository.swift */; };
|
||||
C082CE151F90AFD400860F02 /* Collection+SafeAccess.swift in Sources */ = {isa = PBXBuildFile; fileRef = C082CE141F90AFD400860F02 /* Collection+SafeAccess.swift */; };
|
||||
C08E698D1FDA392D0026056B /* Migrations.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08E698C1FDA392D0026056B /* Migrations.swift */; };
|
||||
C08E69911FDA6F6F0026056B /* FullKeyboardID.swift in Sources */ = {isa = PBXBuildFile; fileRef = C08E69901FDA6F6F0026056B /* FullKeyboardID.swift */; };
|
||||
C0959CD41F99C44E00B616BC /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0959CD31F99C44E00B616BC /* Constants.swift */; };
|
||||
C0A93A541F8B21240079948B /* Manager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0A93A531F8B21240079948B /* Manager.swift */; };
|
||||
C0B09EAE1FCFD10F002F39AF /* FontManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C0B09EAD1FCFD10F002F39AF /* FontManager.swift */; };
|
||||
|
|
@ -196,6 +199,7 @@
|
|||
C040E50F1F8606E300901EE4 /* TextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextField.swift; sourceTree = "<group>"; };
|
||||
C040E5111F86107E00901EE4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
|
||||
C040E5131F86108900901EE4 /* MainViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainViewController.swift; sourceTree = "<group>"; };
|
||||
C042ED5C1FC6A65A001D82F4 /* Version.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Version.swift; sourceTree = "<group>"; };
|
||||
C04514861F85D7F500D88416 /* SystemKeyboard-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SystemKeyboard-Bridging-Header.h"; sourceTree = "<group>"; };
|
||||
C04514871F85D7F500D88416 /* KeyboardViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardViewController.swift; sourceTree = "<group>"; };
|
||||
C04514891F85DF9000D88416 /* InputViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputViewController.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -222,6 +226,8 @@
|
|||
C08C62121F67C31100268D03 /* KeyboardNameTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardNameTableViewCell.swift; sourceTree = "<group>"; };
|
||||
C08C62141F67C8D500268D03 /* KeyboardInfoViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardInfoViewController.swift; sourceTree = "<group>"; };
|
||||
C08C62161F67CFB800268D03 /* KeyboardPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardPickerViewController.swift; sourceTree = "<group>"; };
|
||||
C08E698C1FDA392D0026056B /* Migrations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Migrations.swift; sourceTree = "<group>"; };
|
||||
C08E69901FDA6F6F0026056B /* FullKeyboardID.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullKeyboardID.swift; sourceTree = "<group>"; };
|
||||
C092D8381F6A70C8005C5485 /* LanguageDetailViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LanguageDetailViewController.swift; sourceTree = "<group>"; };
|
||||
C0959CD31F99C44E00B616BC /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
C0A5FF361F6682EB00BE740C /* PopoverView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PopoverView.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -442,6 +448,8 @@
|
|||
C055E6EA1F99ED090035C2DD /* RegisteredFont.swift */,
|
||||
C007C4641F9F52D8006461B9 /* LanguagesAPICall.swift */,
|
||||
C05F432C1FBD5A4C0058CBD4 /* KeyboardAPICall.swift */,
|
||||
C042ED5C1FC6A65A001D82F4 /* Version.swift */,
|
||||
C08E69901FDA6F6F0026056B /* FullKeyboardID.swift */,
|
||||
);
|
||||
path = Model;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -588,6 +596,7 @@
|
|||
C0E30C8B1FC40D0400C80416 /* Storage.swift */,
|
||||
C0EF3E7A1F95B65300CE9BD4 /* KeymanWebDelegate.swift */,
|
||||
C05B14321FD914870082A316 /* Log.swift */,
|
||||
C08E698C1FDA392D0026056B /* Migrations.swift */,
|
||||
);
|
||||
path = Classes;
|
||||
sourceTree = "<group>";
|
||||
|
|
@ -833,9 +842,11 @@
|
|||
C06D37341F81F5C300F61AE0 /* HTTPDownloader.swift in Sources */,
|
||||
C0452BAF1F9F22A80064431A /* Font.swift in Sources */,
|
||||
C0D3F3601F9F3AD80055C7CF /* InstallableKeyboard.swift in Sources */,
|
||||
C042ED5D1FC6A65A001D82F4 /* Version.swift in Sources */,
|
||||
C0D3F35E1F9F33490055C7CF /* Options.swift in Sources */,
|
||||
C06D37351F81F5C300F61AE0 /* HTTPDownloadRequest.swift in Sources */,
|
||||
C0324B8F1F8750B700AF3785 /* TextView.swift in Sources */,
|
||||
C08E698D1FDA392D0026056B /* Migrations.swift in Sources */,
|
||||
C07A9D8C1FD176AB00828ADD /* KeyboardRepositoryDelegate.swift in Sources */,
|
||||
C024C9961FA6EC650060583B /* NotificationCenter+Typed.swift in Sources */,
|
||||
C06D37361F81F5C300F61AE0 /* KeyboardMenuView.swift in Sources */,
|
||||
|
|
@ -862,6 +873,7 @@
|
|||
C082CE151F90AFD400860F02 /* Collection+SafeAccess.swift in Sources */,
|
||||
C06D37441F81F5C400F61AE0 /* KeyboardNameTableViewCell.swift in Sources */,
|
||||
C07A9D8A1FD1762700828ADD /* KeyboardRepository.swift in Sources */,
|
||||
C08E69911FDA6F6F0026056B /* FullKeyboardID.swift in Sources */,
|
||||
C040E5101F8606E300901EE4 /* TextField.swift in Sources */,
|
||||
C0324B8D1F87480700AF3785 /* TextFieldDelegateProxy.swift in Sources */,
|
||||
C075EB061F8EFF870041F4BD /* String+Helpers.swift in Sources */,
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ public enum Key {
|
|||
static let engineVersion = "KeymanEngineVersion"
|
||||
static let keyboardPickerDisplayed = "KeyboardPickerDisplayed"
|
||||
static let synchronizeSWKeyboard = "KeymanSynchronizeSWKeyboard"
|
||||
static let migrationLevel = "KeymanEngineMigrationLevel"
|
||||
|
||||
// JSON keys for language REST calls
|
||||
static let options = "options"
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ public extension UserDefaults {
|
|||
do {
|
||||
return try array.map { try decoder.decode(InstallableKeyboard.self, from: $0) }
|
||||
} catch {
|
||||
log.error("UserDefaults: Error decoding keyboards: \(error)")
|
||||
log.error("Error decoding keyboards: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
|
@ -32,32 +32,32 @@ public extension UserDefaults {
|
|||
let array = try keyboards.map { try encoder.encode($0) }
|
||||
set(array, forKey: key)
|
||||
} catch {
|
||||
log.error("UserDefaults: Error encoding keyboards: \(error)")
|
||||
log.error("Error encoding keyboards: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
public func installableKeyboard(forKey key: String) -> InstallableKeyboard? {
|
||||
public func fullKeyboardID(forKey key: String) -> FullKeyboardID? {
|
||||
guard let data = data(forKey: key) else {
|
||||
return nil
|
||||
}
|
||||
do {
|
||||
return try PropertyListDecoder().decode(InstallableKeyboard.self, from: data)
|
||||
return try PropertyListDecoder().decode(FullKeyboardID.self, from: data)
|
||||
} catch {
|
||||
log.error("UserDefaults: Error decoding keyboard: \(error)")
|
||||
log.error("Error decoding FullKeyboardID: \(error)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func set(_ keyboard: InstallableKeyboard?, forKey key: String) {
|
||||
guard let keyboard = keyboard else {
|
||||
public func set(_ fullKeyboardID: FullKeyboardID?, forKey key: String) {
|
||||
guard let id = fullKeyboardID else {
|
||||
removeObject(forKey: key)
|
||||
return
|
||||
}
|
||||
do {
|
||||
let data = try PropertyListEncoder().encode(keyboard)
|
||||
let data = try PropertyListEncoder().encode(id)
|
||||
set(data, forKey: key)
|
||||
} catch {
|
||||
log.error("UserDefaults: Error encoding keyboard: \(error)")
|
||||
log.error("Error encoding FullKeyboardID: \(error)")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -71,17 +71,27 @@ public extension UserDefaults {
|
|||
}
|
||||
}
|
||||
|
||||
public var currentKeyboard: InstallableKeyboard? {
|
||||
public var currentKeyboardID: FullKeyboardID? {
|
||||
get {
|
||||
return installableKeyboard(forKey: Key.userCurrentKeyboard)
|
||||
return fullKeyboardID(forKey: Key.userCurrentKeyboard)
|
||||
}
|
||||
|
||||
set(keyboard) {
|
||||
set(keyboard, forKey: Key.userCurrentKeyboard)
|
||||
set(fullKeyboardID) {
|
||||
set(fullKeyboardID, forKey: Key.userCurrentKeyboard)
|
||||
}
|
||||
}
|
||||
|
||||
public func userKeyboard(withID keyboardID: String, languageID: String) -> InstallableKeyboard? {
|
||||
return userKeyboards?.first { $0.id == keyboardID && $0.languageID == languageID }
|
||||
public func userKeyboard(withFullID fullID: FullKeyboardID) -> InstallableKeyboard? {
|
||||
return userKeyboards?.first { $0.fullID == fullID }
|
||||
}
|
||||
|
||||
var migrationLevel: Int {
|
||||
get {
|
||||
return integer(forKey: Key.migrationLevel)
|
||||
}
|
||||
|
||||
set(level) {
|
||||
set(level, forKey: Key.migrationLevel)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,38 +28,24 @@ public class FontManager {
|
|||
/// Registers all new fonts found in the font path. Call this after you have preloaded all your font files
|
||||
/// with `preloadFontFile(atPath:shouldOverwrite:)`
|
||||
public func registerCustomFonts() {
|
||||
guard let customFonts = customFonts() else {
|
||||
guard let keyboardDirs = Storage.active.keyboardDirs else {
|
||||
return
|
||||
}
|
||||
|
||||
for fontURL in customFonts {
|
||||
_ = registerFont(at: fontURL)
|
||||
for dir in keyboardDirs {
|
||||
registerFonts(in: dir)
|
||||
}
|
||||
}
|
||||
|
||||
/// Unregisters all registered fonts in the font path.
|
||||
public func unregisterCustomFonts() {
|
||||
guard let customFonts = customFonts() else {
|
||||
guard let keyboardDirs = Storage.active.keyboardDirs else {
|
||||
return
|
||||
}
|
||||
|
||||
for fontURL in customFonts {
|
||||
_ = unregisterFont(at: fontURL)
|
||||
for dir in keyboardDirs {
|
||||
unregisterFonts(in: dir)
|
||||
}
|
||||
}
|
||||
|
||||
private func customFonts() -> [URL]? {
|
||||
let urls: [URL]
|
||||
do {
|
||||
urls = try FileManager.default.contentsOfDirectory(at: Storage.active.fontDir,
|
||||
includingPropertiesForKeys: nil)
|
||||
} catch {
|
||||
log.error("Failed to list font dir contents: \(error)")
|
||||
return nil
|
||||
}
|
||||
return urls.filter { $0.lastPathComponent.hasFontExtension }
|
||||
}
|
||||
|
||||
private func readFontName(at url: URL) -> String? {
|
||||
guard let provider = CGDataProvider(url: url as CFURL) else {
|
||||
log.error("Failed to open \(url)")
|
||||
|
|
@ -139,6 +125,26 @@ public class FontManager {
|
|||
return font.isRegistered
|
||||
}
|
||||
|
||||
public func registerFonts(in directory: URL) {
|
||||
guard let urls = try? FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) else {
|
||||
log.error("Could not list contents of directory \(directory)")
|
||||
return
|
||||
}
|
||||
for url in urls where url.lastPathComponent.hasFontExtension {
|
||||
_ = registerFont(at: url)
|
||||
}
|
||||
}
|
||||
|
||||
public func unregisterFonts(in directory: URL, fromSystemOnly: Bool = true) {
|
||||
guard let urls = try? FileManager.default.contentsOfDirectory(at: directory, includingPropertiesForKeys: nil) else {
|
||||
log.error("Could not list contents of directory \(directory)")
|
||||
return
|
||||
}
|
||||
for url in urls where url.lastPathComponent.hasFontExtension {
|
||||
_ = unregisterFont(at: url, fromSystemOnly: fromSystemOnly)
|
||||
}
|
||||
}
|
||||
|
||||
private func fontExists(_ fontName: String) -> Bool {
|
||||
return UIFont.familyNames.contains { familyName in
|
||||
UIFont.fontNames(forFamilyName: familyName).contains(fontName)
|
||||
|
|
|
|||
|
|
@ -49,11 +49,7 @@ class KeyboardMenuView: UIView, UITableViewDelegate, UITableViewDataSource, UIGe
|
|||
_tableList = keyboardList
|
||||
_tableList!.append(titleCloseButton)
|
||||
} else {
|
||||
var keyboard = Defaults.keyboard
|
||||
if let version = Manager.shared.latestKeyboardFileVersion(withID: Defaults.keyboard.id) {
|
||||
keyboard.version = version
|
||||
}
|
||||
_tableList = [keyboard]
|
||||
_tableList = [Defaults.keyboard]
|
||||
_tableList!.append(titleCloseButton)
|
||||
}
|
||||
return _tableList!
|
||||
|
|
@ -284,7 +280,7 @@ class KeyboardMenuView: UIView, UITableViewDelegate, UITableViewDataSource, UIGe
|
|||
let keyboard = tableList[indexPath.row] as! InstallableKeyboard
|
||||
cell.textLabel?.text = keyboard.name
|
||||
cell.tag = indexPath.row
|
||||
if (Manager.shared.languageID == keyboard.languageID) && (Manager.shared.keyboardID == keyboard.id) {
|
||||
if Manager.shared.currentKeyboardID == keyboard.fullID {
|
||||
cell.selectionStyle = .none
|
||||
cell.isSelected = true
|
||||
cell.accessoryType = .checkmark
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ public extension KeyboardRepository {
|
|||
guard let keyboard = language.keyboards?.first(where: { $0.id == keyboardID }) else {
|
||||
return nil
|
||||
}
|
||||
return InstallableKeyboard(keyboard: keyboard, language: language)
|
||||
return InstallableKeyboard(keyboard: keyboard, language: language, isCustom: false)
|
||||
}
|
||||
|
||||
public func fetch(completionHandler: CompletionHandler? = nil) {
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import WebKit
|
|||
|
||||
// MARK: - UIViewController
|
||||
class KeymanWebViewController: UIViewController {
|
||||
let storage: Storage
|
||||
weak var delegate: KeymanWebDelegate?
|
||||
var webView: WKWebView!
|
||||
|
||||
|
|
@ -22,6 +23,15 @@ class KeymanWebViewController: UIViewController {
|
|||
}
|
||||
}
|
||||
|
||||
init(storage: Storage) {
|
||||
self.storage = storage
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
required init?(coder aDecoder: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
override func loadView() {
|
||||
let config = WKWebViewConfiguration()
|
||||
let prefs = WKPreferences()
|
||||
|
|
@ -62,10 +72,7 @@ extension KeymanWebViewController {
|
|||
let y = CGFloat(Float(components[1])!)
|
||||
let w = CGFloat(Float(components[2])!)
|
||||
let h = CGFloat(Float(components[3])!)
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
let adjY: CGFloat = isPad ? -0.5 : -1.0
|
||||
let frame = CGRect(x: x - w / 2.0, y: y - adjY, width: w, height: h)
|
||||
completion(frame)
|
||||
completion(KeymanWebViewController.keyFrame(x: x, y: y, w: w, h: h))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -121,26 +128,20 @@ extension KeymanWebViewController {
|
|||
// family does not have to match the name in the font file. It only has to be unique.
|
||||
return [
|
||||
"family": "\(keyboardID)__\(isOsk ? "osk" : "display")",
|
||||
"files": font.source
|
||||
"files": font.source.map { storage.fontURL(forKeyboardID: keyboardID, filename: $0).absoluteString }
|
||||
]
|
||||
}
|
||||
|
||||
func setKeyboard(id: String,
|
||||
name: String,
|
||||
languageID: String,
|
||||
languageName: String,
|
||||
fileURL: URL,
|
||||
font: Font?,
|
||||
oskFont: Font?) {
|
||||
func setKeyboard(_ keyboard: InstallableKeyboard) {
|
||||
var stub: [String: Any] = [
|
||||
"KI": "Keyboard_\(id)",
|
||||
"KN": name,
|
||||
"KLC": languageID,
|
||||
"KL": languageName,
|
||||
"KF": fileURL.absoluteString
|
||||
"KI": "Keyboard_\(keyboard.id)",
|
||||
"KN": keyboard.name,
|
||||
"KLC": keyboard.languageID,
|
||||
"KL": keyboard.languageName,
|
||||
"KF": storage.keyboardURL(for: keyboard).absoluteString
|
||||
]
|
||||
let displayFont = fontObject(from: font, keyboardID: id, isOsk: false)
|
||||
let oskFont = fontObject(from: oskFont, keyboardID: id, isOsk: true) ?? displayFont
|
||||
let displayFont = fontObject(from: keyboard.font, keyboardID: keyboard.id, isOsk: false)
|
||||
let oskFont = fontObject(from: keyboard.oskFont, keyboardID: keyboard.id, isOsk: true) ?? displayFont
|
||||
if let displayFont = displayFont {
|
||||
stub["KFont"] = displayFont
|
||||
}
|
||||
|
|
@ -160,6 +161,7 @@ extension KeymanWebViewController {
|
|||
return
|
||||
}
|
||||
|
||||
log.debug("Keyboard stub: \(stubString)")
|
||||
webView.evaluateJavaScript("setKeymanLanguage(\(stubString));", completionHandler: nil)
|
||||
}
|
||||
}
|
||||
|
|
@ -198,7 +200,7 @@ extension KeymanWebViewController: WKScriptMessageHandler {
|
|||
let h = CGFloat(Float(fragment[hKey.upperBound..<tKey.lowerBound])!)
|
||||
let t = String(fragment[tKey.upperBound...])
|
||||
|
||||
let frame = keyFrame(x: x, y: y, w: w, h: h)
|
||||
let frame = KeymanWebViewController.keyFrame(x: x, y: y, w: w, h: h)
|
||||
let preview = t.stringFromUTF16CodeUnits() ?? ""
|
||||
showKeyPreview(self, keyFrame: frame, preview: preview)
|
||||
delegate?.showKeyPreview(self, keyFrame: frame, preview: preview)
|
||||
|
|
@ -218,7 +220,7 @@ extension KeymanWebViewController: WKScriptMessageHandler {
|
|||
let y = CGFloat(Float(frameComponents[1])!)
|
||||
let w = CGFloat(Float(frameComponents[2])!)
|
||||
let h = CGFloat(Float(frameComponents[3])!)
|
||||
let frame = keyFrame(x: x, y: y, w: w, h: h)
|
||||
let frame = KeymanWebViewController.keyFrame(x: x, y: y, w: w, h: h)
|
||||
|
||||
let keyArray = keys.components(separatedBy: ";")
|
||||
var subkeyIDs: [String] = []
|
||||
|
|
@ -273,10 +275,9 @@ extension KeymanWebViewController: WKScriptMessageHandler {
|
|||
}
|
||||
}
|
||||
|
||||
private func keyFrame(x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat) -> CGRect {
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
let adjY: CGFloat = isPad ? -0.5 : -1.0
|
||||
return CGRect(x: x - w / 2.0, y: y - adjY, width: w, height: h)
|
||||
private static func keyFrame(x: CGFloat, y: CGFloat, w: CGFloat, h: CGFloat) -> CGRect {
|
||||
// kmw adds w/2 to x.
|
||||
return CGRect(x: x - w / 2.0, y: y, width: w, height: h)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -164,7 +164,7 @@ class KeyboardPickerViewController: UITableViewController, UIAlertViewDelegate {
|
|||
cell.detailTextLabel?.text = kb.name
|
||||
cell.tag = indexPath.row
|
||||
|
||||
if isCurrentKeyboard(languageID: kb.languageID, keyboardID: kb.id) {
|
||||
if Manager.shared.currentKeyboardID == kb.fullID {
|
||||
cell.selectionStyle = .blue
|
||||
cell.isSelected = true
|
||||
cell.accessoryType = .detailDisclosureButton
|
||||
|
|
@ -273,16 +273,7 @@ class KeyboardPickerViewController: UITableViewController, UIAlertViewDelegate {
|
|||
}
|
||||
|
||||
private func loadUserKeyboards() {
|
||||
let userData = Storage.active.userDefaults
|
||||
|
||||
if let userKeyboards = userData.userKeyboards {
|
||||
self.userKeyboards = userKeyboards
|
||||
} else {
|
||||
userKeyboards = [Defaults.keyboard]
|
||||
userData.userKeyboards = userKeyboards
|
||||
userData.synchronize()
|
||||
}
|
||||
|
||||
userKeyboards = Storage.active.userDefaults.userKeyboards ?? []
|
||||
tableView.reloadData()
|
||||
}
|
||||
|
||||
|
|
@ -365,7 +356,7 @@ class KeyboardPickerViewController: UITableViewController, UIAlertViewDelegate {
|
|||
|
||||
private func scroll(toSelectedKeyboard animated: Bool) {
|
||||
let index = userKeyboards.index { kb in
|
||||
return isCurrentKeyboard(languageID: kb.languageID, keyboardID: kb.id)
|
||||
return Manager.shared.currentKeyboardID == kb.fullID
|
||||
}
|
||||
|
||||
if let index = index {
|
||||
|
|
@ -388,11 +379,6 @@ class KeyboardPickerViewController: UITableViewController, UIAlertViewDelegate {
|
|||
}
|
||||
}
|
||||
|
||||
private func isCurrentKeyboard(languageID: String?, keyboardID: String?) -> Bool {
|
||||
return Manager.shared.keyboardID == keyboardID &&
|
||||
Manager.shared.languageID == languageID
|
||||
}
|
||||
|
||||
@objc func hideToolbarDelayed(_ timer: Timer) {
|
||||
navigationController?.setToolbarHidden(true, animated: true)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,8 +91,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
/// Set this to `UIApplication.shared.openURL` in your application.
|
||||
public var openURL: ((URL) -> Bool)?
|
||||
|
||||
var keyboardID: String?
|
||||
var languageID: String?
|
||||
var currentKeyboardID: FullKeyboardID?
|
||||
weak var keymanWebDelegate: KeymanWebDelegate?
|
||||
var currentRequest: HTTPDownloadRequest?
|
||||
var shouldReloadKeyboard = false
|
||||
|
|
@ -139,24 +138,12 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
URLProtocol.registerClass(KeymanURLProtocol.self)
|
||||
|
||||
if !Util.isSystemKeyboard {
|
||||
if let shared = Storage.shared,
|
||||
let nonShared = Storage.nonShared {
|
||||
let keysToCopy = [Key.userKeyboardsList, Key.userCurrentKeyboard,
|
||||
Key.engineVersion, Key.keyboardPickerDisplayed]
|
||||
nonShared.copyUserDefaults(to: shared, withKeys: keysToCopy, shouldOverwrite: false)
|
||||
do {
|
||||
try nonShared.copyFiles(to: shared)
|
||||
} catch {
|
||||
log.error("Failed to copy files to shared container: \(error)")
|
||||
}
|
||||
}
|
||||
let userData = Storage.active.userDefaults
|
||||
let isKPDisplayed = userData.bool(forKey: Key.keyboardPickerDisplayed)
|
||||
if isKPDisplayed {
|
||||
isKeymanHelpOn = false
|
||||
}
|
||||
} else {
|
||||
Migrations.migrate(storage: Storage.active)
|
||||
if Storage.active.userDefaults.userKeyboards?.isEmpty ?? true {
|
||||
Storage.active.userDefaults.userKeyboards = [Defaults.keyboard]
|
||||
}
|
||||
|
||||
if Util.isSystemKeyboard || Storage.active.userDefaults.bool(forKey: Key.keyboardPickerDisplayed) {
|
||||
isKeymanHelpOn = false
|
||||
}
|
||||
|
||||
|
|
@ -173,7 +160,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
updateUserKeyboards(with: Defaults.keyboard)
|
||||
|
||||
keymanWeb = KeymanWebViewController(nibName: nil, bundle: nil)
|
||||
keymanWeb = KeymanWebViewController(storage: Storage.active)
|
||||
keymanWeb.frame = CGRect(origin: .zero, size: keyboardSize)
|
||||
keymanWeb.delegate = self
|
||||
reloadKeyboard(in: keymanWeb)
|
||||
|
|
@ -206,8 +193,8 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
/// - SeeAlso:
|
||||
/// - addKeyboard()
|
||||
/// - Returns: Whether the keyboard was set successfully
|
||||
public func setKeyboard(withID keyboardID: String, languageID: String) -> Bool {
|
||||
if let keyboard = Storage.active.userDefaults.userKeyboard(withID: keyboardID, languageID: languageID) {
|
||||
public func setKeyboard(withFullID fullID: FullKeyboardID) -> Bool {
|
||||
if let keyboard = Storage.active.userDefaults.userKeyboard(withFullID: fullID) {
|
||||
return setKeyboard(keyboard)
|
||||
}
|
||||
return false
|
||||
|
|
@ -217,29 +204,26 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
///
|
||||
/// - Returns: Whether the keyboard was set successfully
|
||||
public func setKeyboard(_ kb: InstallableKeyboard) -> Bool {
|
||||
if kb.languageID == self.languageID && kb.id == self.keyboardID {
|
||||
log.info("Keyboard unchanged: \(kb.languageID)_\(kb.id)")
|
||||
if kb.fullID == currentKeyboardID {
|
||||
log.info("Keyboard unchanged: \(kb.fullID)")
|
||||
return false
|
||||
}
|
||||
|
||||
log.info("Setting language: \(kb.languageID)_\(kb.id)")
|
||||
log.info("Setting language: \(kb.fullID)")
|
||||
|
||||
self.languageID = kb.languageID
|
||||
self.keyboardID = kb.id
|
||||
currentKeyboardID = kb.fullID
|
||||
|
||||
if let fontFilename = kb.font?.source.first(where: { $0.hasFontExtension }) {
|
||||
_ = FontManager.shared.registerFont(at: Storage.active.fontURL(forFilename: fontFilename))
|
||||
_ = FontManager.shared.registerFont(at: Storage.active.fontURL(forKeyboardID: kb.id, filename: fontFilename))
|
||||
}
|
||||
if let oskFontFilename = kb.oskFont?.source.first(where: { $0.hasFontExtension }) {
|
||||
_ = FontManager.shared.registerFont(at: Storage.active.fontURL(forFilename: oskFontFilename))
|
||||
_ = FontManager.shared.registerFont(at: Storage.active.fontURL(forKeyboardID: kb.id, filename: oskFontFilename))
|
||||
}
|
||||
|
||||
keymanWeb.setKeyboard(id: kb.id, name: kb.name, languageID: kb.languageID, languageName: kb.languageName,
|
||||
fileURL: Storage.active.keyboardURL(for: kb), font: kb.font, oskFont: kb.oskFont)
|
||||
keymanWeb.setKeyboard(kb)
|
||||
|
||||
let userData = Util.isSystemKeyboard ? UserDefaults.standard : Storage.active.userDefaults
|
||||
|
||||
userData.currentKeyboard = kb
|
||||
userData.currentKeyboardID = kb.fullID
|
||||
userData.synchronize()
|
||||
|
||||
if isKeymanHelpOn {
|
||||
|
|
@ -269,7 +253,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
var userKeyboards = userDefaults.userKeyboards ?? []
|
||||
|
||||
// Update keyboard if it exists
|
||||
if let index = userKeyboards.index(where: { $0.id == keyboard.id && $0.languageID == keyboard.languageID }) {
|
||||
if let index = userKeyboards.index(where: { $0.fullID == keyboard.fullID }) {
|
||||
userKeyboards[index] = keyboard
|
||||
} else {
|
||||
userKeyboards.append(keyboard)
|
||||
|
|
@ -282,9 +266,9 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
/// Removes a keyboard from the list in the keyboard picker if it exists.
|
||||
/// - Returns: The keyboard exists and was removed
|
||||
public func removeKeyboard(withID keyboardID: String, languageID: String) -> Bool {
|
||||
public func removeKeyboard(withFullID fullID: FullKeyboardID) -> Bool {
|
||||
// Remove keyboard from the list if it exists
|
||||
let index = Storage.active.userDefaults.userKeyboards?.index { $0.id == keyboardID && $0.languageID == languageID }
|
||||
let index = Storage.active.userDefaults.userKeyboards?.index { $0.fullID == fullID }
|
||||
if let index = index {
|
||||
return removeKeyboard(at: index)
|
||||
}
|
||||
|
|
@ -311,28 +295,42 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
userData.set([Date()], forKey: Key.synchronizeSWKeyboard)
|
||||
userData.synchronize()
|
||||
|
||||
log.info("Removing keyboard with ID \(kb.id) and languageID \(kb.languageID)")
|
||||
|
||||
// Set a new keyboard if deleting the current one
|
||||
if kb.id == keyboardID && kb.languageID == languageID {
|
||||
if kb.fullID == currentKeyboardID {
|
||||
setKeyboard(userKeyboards[0])
|
||||
}
|
||||
|
||||
if !userKeyboards.contains(where: { $0.id == kb.id }) {
|
||||
let keyboardDir = Storage.active.keyboardDir(forID: kb.id)
|
||||
FontManager.shared.unregisterFonts(in: keyboardDir, fromSystemOnly: false)
|
||||
log.info("Deleting directory \(keyboardDir)")
|
||||
if (try? FileManager.default.removeItem(at: keyboardDir)) == nil {
|
||||
log.error("Failed to delete \(keyboardDir)")
|
||||
}
|
||||
} else {
|
||||
log.info("User has another language installed. Skipping delete of keyboard files.")
|
||||
}
|
||||
|
||||
NotificationCenter.default.post(name: Notifications.keyboardRemoved, object: self, value: kb)
|
||||
return true
|
||||
}
|
||||
|
||||
/// - Returns: Info for the current keyboard, if a keyboard is set
|
||||
public var currentKeyboardInfo: InstallableKeyboard? {
|
||||
guard let keyboardID = keyboardID, let languageID = languageID else {
|
||||
public var currentKeyboard: InstallableKeyboard? {
|
||||
guard let fullID = currentKeyboardID else {
|
||||
return nil
|
||||
}
|
||||
return Storage.active.userDefaults.userKeyboard(withID: keyboardID, languageID: languageID)
|
||||
return Storage.active.userDefaults.userKeyboard(withFullID: fullID)
|
||||
}
|
||||
|
||||
/// Switch to the next keyboard.
|
||||
/// - Returns: Index of the newly selected keyboard.
|
||||
public func switchToNextKeyboard() -> Int? {
|
||||
guard let userKeyboards = Storage.active.userDefaults.userKeyboards,
|
||||
let index = userKeyboards.index(where: { isCurrentKeyboard($0) }) else {
|
||||
let index = userKeyboards.index(where: { self.currentKeyboardID == $0.fullID })
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
let newIndex = (index + 1) % userKeyboards.count
|
||||
|
|
@ -340,21 +338,13 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
return newIndex
|
||||
}
|
||||
|
||||
func isCurrentKeyboard(withID keyboardID: String?, languageID: String?) -> Bool {
|
||||
return self.keyboardID == keyboardID && self.languageID == languageID
|
||||
}
|
||||
|
||||
func isCurrentKeyboard(_ keyboard: InstallableKeyboard) -> Bool {
|
||||
return keyboard.id == self.keyboardID && keyboard.languageID == self.languageID
|
||||
}
|
||||
|
||||
/// - Returns: The font name for the given keyboard ID and languageID, or returns nil if
|
||||
/// - The keyboard doesn't have a font
|
||||
/// - The keyboard info is not available in the user keyboards list
|
||||
public func fontNameForKeyboard(withID keyboardID: String, languageID: String) -> String? {
|
||||
let kb = Storage.active.userDefaults.userKeyboard(withID: keyboardID, languageID: languageID)
|
||||
public func fontNameForKeyboard(withFullID fullID: FullKeyboardID) -> String? {
|
||||
let kb = Storage.active.userDefaults.userKeyboard(withFullID: fullID)
|
||||
if let filename = kb?.font?.source.first(where: { $0.hasFontExtension }) {
|
||||
let fontURL = Storage.active.fontURL(forFilename: filename)
|
||||
let fontURL = Storage.active.fontURL(forKeyboardID: fullID.keyboardID, filename: filename)
|
||||
return FontManager.shared.fontName(at: fontURL)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -363,10 +353,10 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
/// - Returns: the OSK font name for the given keyboard ID and languageID, or returns nil if
|
||||
/// - The keyboard doesn't have an OSK font
|
||||
/// - The keyboard info is not available in the user keyboards list
|
||||
func oskFontNameForKeyboard(withID keyboardID: String, languageID: String) -> String? {
|
||||
let kb = Storage.active.userDefaults.userKeyboard(withID: keyboardID, languageID: languageID)
|
||||
func oskFontNameForKeyboard(withFullID fullID: FullKeyboardID) -> String? {
|
||||
let kb = Storage.active.userDefaults.userKeyboard(withFullID: fullID)
|
||||
if let filename = kb?.oskFont?.source.first(where: { $0.hasFontExtension }) {
|
||||
let fontURL = Storage.active.fontURL(forFilename: filename)
|
||||
let fontURL = Storage.active.fontURL(forKeyboardID: fullID.keyboardID, filename: filename)
|
||||
return FontManager.shared.fontName(at: fontURL)
|
||||
}
|
||||
return nil
|
||||
|
|
@ -431,8 +421,15 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
return
|
||||
}
|
||||
|
||||
let keyboardURL = options.keyboardBaseURL.appendingPathComponent(filename)
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: Storage.active.keyboardDir(forID: keyboardID),
|
||||
withIntermediateDirectories: true)
|
||||
} catch {
|
||||
log.error("Could not create dir for download: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
let keyboardURL = options.keyboardBaseURL.appendingPathComponent(filename)
|
||||
let fontURLs = Array(Set(keyboardFontURLs(forFont: keyboard.font, options: options) +
|
||||
keyboardFontURLs(forFont: keyboard.oskFont, options: options)))
|
||||
|
||||
|
|
@ -451,7 +448,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
for (i, url) in fontURLs.enumerated() {
|
||||
request = HTTPDownloadRequest(url: url, userInfo: commonUserData)
|
||||
request.destinationFile = Storage.active.fontURL(forFilename: url.lastPathComponent).path
|
||||
request.destinationFile = Storage.active.fontURL(forKeyboardID: keyboardID, filename: url.lastPathComponent).path
|
||||
request.tag = i + 1
|
||||
downloadQueue!.addRequest(request)
|
||||
}
|
||||
|
|
@ -499,7 +496,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
private func downloadKeyboard(_ keyboardAPI: KeyboardAPICall) {
|
||||
let keyboard = keyboardAPI.keyboard
|
||||
let installableKeyboards = keyboard.languages!.map { language in
|
||||
InstallableKeyboard(keyboard: keyboard, language: language)
|
||||
InstallableKeyboard(keyboard: keyboard, language: language, isCustom: true)
|
||||
}
|
||||
|
||||
let filename = keyboard.filename
|
||||
|
|
@ -522,9 +519,17 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
return
|
||||
}
|
||||
|
||||
let isUpdate = latestKeyboardFileVersion(withID: keyboard.id) != nil
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: Storage.active.keyboardDir(forID: keyboard.id),
|
||||
withIntermediateDirectories: true)
|
||||
} catch {
|
||||
log.error("Could not create dir for download: \(error)")
|
||||
return
|
||||
}
|
||||
|
||||
downloadQueue = HTTPDownloader.init(self)
|
||||
let isUpdate = Storage.active.userDefaults.userKeyboards?.contains { $0.id == keyboard.id } ?? false
|
||||
|
||||
downloadQueue = HTTPDownloader(self)
|
||||
let commonUserData: [String: Any] = [
|
||||
Key.keyboardInfo: installableKeyboards,
|
||||
Key.update: isUpdate
|
||||
|
|
@ -538,7 +543,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
downloadQueue!.addRequest(request)
|
||||
for (i, url) in fontURLs.enumerated() {
|
||||
request = HTTPDownloadRequest(url: url, userInfo: commonUserData)
|
||||
request.destinationFile = Storage.active.fontURL(forFilename: url.lastPathComponent).path
|
||||
request.destinationFile = Storage.active.fontURL(forKeyboardID: keyboard.id, filename: url.lastPathComponent).path
|
||||
request.tag = i + 1
|
||||
downloadQueue!.addRequest(request)
|
||||
}
|
||||
|
|
@ -550,14 +555,18 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
if keyboardIdForCurrentRequest() == keyboardID {
|
||||
return .downloading
|
||||
}
|
||||
guard let latestDownloadedVersion = latestKeyboardFileVersion(withID: keyboardID) else {
|
||||
let userKeyboards = Storage.active.userDefaults.userKeyboards
|
||||
guard let userKeyboard = userKeyboards?.first(where: { $0.id == keyboardID }) else {
|
||||
return .needsDownload
|
||||
}
|
||||
|
||||
// Check version
|
||||
if let latestRepositoryVersion = apiKeyboardRepository.keyboards?[keyboardID]?.version,
|
||||
compareVersions(latestDownloadedVersion, latestRepositoryVersion) == .orderedAscending {
|
||||
return .needsUpdate
|
||||
if let repositoryVersionString = apiKeyboardRepository.keyboards?[keyboardID]?.version {
|
||||
let downloadedVersion = Version(userKeyboard.version) ?? Version.fallback
|
||||
let repositoryVersion = Version(repositoryVersionString) ?? Version.fallback
|
||||
if downloadedVersion < repositoryVersion {
|
||||
return .needsUpdate
|
||||
}
|
||||
}
|
||||
return .upToDate
|
||||
}
|
||||
|
|
@ -594,16 +603,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
// MARK: - HTTPDownloadDelegate methods
|
||||
|
||||
func downloadQueueFinished(_ queue: HTTPDownloader) {
|
||||
log.debug {
|
||||
let fontContents = try? FileManager.default.contentsOfDirectory(atPath: Storage.active.fontDir.path)
|
||||
return "Font Directory contents: \(fontContents ?? [])"
|
||||
}
|
||||
log.debug {
|
||||
let langContents = try? FileManager.default.contentsOfDirectory(atPath: Storage.active.languageDir.path)
|
||||
return "Language Directory contents: \(langContents ?? [])"
|
||||
}
|
||||
}
|
||||
func downloadQueueFinished(_ queue: HTTPDownloader) { }
|
||||
|
||||
func downloadRequestStarted(_ request: HTTPDownloadRequest) {
|
||||
// If we're downloading a new keyboard.
|
||||
|
|
@ -688,79 +688,18 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
}
|
||||
|
||||
// MARK: - Loading custom keyboards
|
||||
|
||||
/// Preloads a .js file for a language so that the keyboard is available without downloading.
|
||||
/// - Precondition:
|
||||
/// - The .js filename must remain the same as when obtained from Keyman.
|
||||
/// - The .js file must be bundled in your application.
|
||||
public func preloadKeyboardFile(at url: URL, shouldOverwrite: Bool) throws {
|
||||
try Storage.copyAndExcludeFromBackup(at: url,
|
||||
to: Storage.active.languageDir.appendingPathComponent(url.lastPathComponent),
|
||||
shouldOverwrite: shouldOverwrite)
|
||||
}
|
||||
|
||||
/// Preloads a .ttf or .otf file to be available without downloading.
|
||||
/// - Precondition:
|
||||
/// - The font file must be bundled in your application.
|
||||
/// - SeeAlso: `registerCustomFonts()`
|
||||
public func preloadFontFile(at url: URL, shouldOverwrite: Bool) throws {
|
||||
try Storage.copyAndExcludeFromBackup(at: url,
|
||||
to: Storage.active.fontDir.appendingPathComponent(url.lastPathComponent),
|
||||
shouldOverwrite: shouldOverwrite)
|
||||
/// Preloads the JS and font files required for a keyboard.
|
||||
public func preloadFiles(forKeyboardID keyboardID: String, at urls: [URL], shouldOverwrite: Bool) throws {
|
||||
let keyboardDir = Storage.active.keyboardDir(forID: keyboardID)
|
||||
try FileManager.default.createDirectory(at: keyboardDir, withIntermediateDirectories: true)
|
||||
for url in urls {
|
||||
try Storage.copyAndExcludeFromBackup(at: url,
|
||||
to: keyboardDir.appendingPathComponent(url.lastPathComponent),
|
||||
shouldOverwrite: shouldOverwrite)
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - File system and UserData management
|
||||
func latestKeyboardFileVersion(withID keyboardID: String) -> String? {
|
||||
guard let dirContents = try? FileManager.default.contentsOfDirectory(atPath: Storage.active.languageDir.path) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var latestVersion: String?
|
||||
for filename in dirContents where filename.hasPrefix("\(keyboardID)-") && filename.hasJavaScriptExtension {
|
||||
let dashRange = filename.range(of: "-", options: .backwards)!
|
||||
let extensionRange = filename.range(of: ".js", options: .backwards)!
|
||||
let version = String(filename[dashRange.upperBound..<extensionRange.lowerBound])
|
||||
|
||||
if let previousMax = latestVersion {
|
||||
if compareVersions(previousMax, version) == .orderedAscending {
|
||||
latestVersion = version
|
||||
}
|
||||
} else if compareVersions(version, version) != nil { // Ensure that the version number is valid
|
||||
latestVersion = version
|
||||
}
|
||||
}
|
||||
return latestVersion
|
||||
}
|
||||
|
||||
/// Compares version numbers in dotted numberic format.
|
||||
/// - Returns: ComparisonResult if both version numbers are valid.
|
||||
func compareVersions(_ v1: String, _ v2: String) -> ComparisonResult? {
|
||||
if v1.isEmpty || v2.isEmpty {
|
||||
return nil
|
||||
}
|
||||
let components1 = v1.components(separatedBy: ".")
|
||||
let components2 = v2.components(separatedBy: ".")
|
||||
|
||||
let len = max(components1.count, components2.count)
|
||||
for i in 0..<len {
|
||||
// Shorter version number padded with trailing zero components
|
||||
let component1 = components1[safe: i] ?? "0"
|
||||
let component2 = components2[safe: i] ?? "0"
|
||||
guard let val1 = Int(component1), val1 >= 0 else {
|
||||
return nil
|
||||
}
|
||||
guard let val2 = Int(component2), val2 >= 0 else {
|
||||
return nil
|
||||
}
|
||||
if val1 < val2 {
|
||||
return .orderedAscending
|
||||
}
|
||||
if val1 > val2 {
|
||||
return .orderedDescending
|
||||
}
|
||||
}
|
||||
return .orderedSame
|
||||
}
|
||||
|
||||
/// Updates the user's installed keyboards and current keyboard with information in newKeyboard.
|
||||
/// - Parameter newKeyboard: Info for updated keyboard.
|
||||
|
|
@ -777,27 +716,13 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
if kb.languageID == newKeyboard.languageID {
|
||||
kb = newKeyboard
|
||||
} else {
|
||||
kb.version = newKeyboard.id
|
||||
kb.version = newKeyboard.version
|
||||
}
|
||||
userKeyboards[i] = kb
|
||||
}
|
||||
}
|
||||
userData.userKeyboards = userKeyboards
|
||||
userData.synchronize()
|
||||
|
||||
// Set version for current keyboard
|
||||
let currentUserData = Util.isSystemKeyboard ? UserDefaults.standard : Storage.active.userDefaults
|
||||
if var kb = currentUserData.currentKeyboard {
|
||||
if kb.id == newKeyboard.id {
|
||||
if kb.languageID == newKeyboard.languageID {
|
||||
kb = newKeyboard
|
||||
} else {
|
||||
kb.version = newKeyboard.id
|
||||
}
|
||||
currentUserData.currentKeyboard = kb
|
||||
currentUserData.synchronize()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func synchronizeSWKeyboard() {
|
||||
|
|
@ -964,9 +889,8 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
}
|
||||
|
||||
@objc func resetKeyboard() {
|
||||
let keyboard = currentKeyboardInfo
|
||||
keyboardID = nil
|
||||
languageID = nil
|
||||
let keyboard = currentKeyboard
|
||||
currentKeyboardID = nil
|
||||
|
||||
if let keyboard = keyboard {
|
||||
setKeyboard(keyboard)
|
||||
|
|
@ -984,12 +908,12 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
}
|
||||
|
||||
keymanWeb.languageMenuPosition { keyFrame in
|
||||
self.showHelpBubble(at: keyFrame.origin)
|
||||
self.showHelpBubble(for: keyFrame)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: The bulk of this should be moved to PopoverView
|
||||
func showHelpBubble(at point: CGPoint) {
|
||||
func showHelpBubble(for keyFrame: CGRect) {
|
||||
self.helpBubbleView?.removeFromSuperview()
|
||||
let helpBubbleView = PopoverView(frame: CGRect.zero)
|
||||
self.helpBubbleView = helpBubbleView
|
||||
|
|
@ -1001,48 +925,24 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
let sizeMultiplier = CGFloat(isPad ? 1.5 : 1.0)
|
||||
let frameWidth = 90.0 * sizeMultiplier
|
||||
let frameHeight = (40.0 + helpBubbleView.arrowHeight) * sizeMultiplier
|
||||
let popupWidth = 90.0 * sizeMultiplier
|
||||
let popupHeight = 40.0 * sizeMultiplier + helpBubbleView.arrowHeight
|
||||
let fontSize = 10.0 * sizeMultiplier
|
||||
|
||||
let inputViewFrame = keymanWeb.view.frame
|
||||
let screenWidth = inputViewFrame.size.width
|
||||
|
||||
// TODO: Refactor this out
|
||||
let isPortrait: Bool
|
||||
if Util.isSystemKeyboard {
|
||||
isPortrait = InputViewController.isPortrait
|
||||
} else {
|
||||
isPortrait = UIDevice.current.orientation.isPortrait
|
||||
}
|
||||
let x = CGFloat.maximum(0, CGFloat.minimum(screenWidth - popupWidth, keyFrame.midX - popupWidth / 2))
|
||||
let adjY = CGFloat(3.0) // Tweak the positioning of the popup
|
||||
let y = keyFrame.minY - popupHeight + adjY
|
||||
|
||||
let adjY: CGFloat
|
||||
if isPortrait {
|
||||
adjY = Util.isSystemKeyboard ? 9.0 : 4.0
|
||||
} else {
|
||||
adjY = Util.isSystemKeyboard ? 3.0 : 4.0
|
||||
}
|
||||
let px = point.x
|
||||
let py = point.y + adjY + (isPad ? 2.0 : 1.0)
|
||||
var x = px - frameWidth / 2
|
||||
let y = py - frameHeight
|
||||
if x < 0 {
|
||||
x = 0
|
||||
} else if x + frameWidth > screenWidth {
|
||||
x = screenWidth - frameWidth
|
||||
}
|
||||
helpBubbleView.frame = CGRect(x: x, y: y, width: popupWidth, height: popupHeight)
|
||||
helpBubbleView.arrowPosX = keyFrame.midX - x
|
||||
|
||||
helpBubbleView.frame = CGRect(x: x, y: y, width: frameWidth, height: frameHeight)
|
||||
if x == 0 {
|
||||
helpBubbleView.arrowPosX = px
|
||||
} else if x == screenWidth - frameWidth {
|
||||
helpBubbleView.arrowPosX = (px - x)
|
||||
} else {
|
||||
helpBubbleView.arrowPosX = frameWidth / 2
|
||||
}
|
||||
|
||||
let helpText = UILabel(frame: CGRect(x: 5, y: 0,
|
||||
width: frameWidth - 10, height: frameHeight - helpBubbleView.arrowHeight))
|
||||
let helpText = UILabel(frame: CGRect(x: 5,
|
||||
y: 0,
|
||||
width: popupWidth - 10,
|
||||
height: popupHeight - helpBubbleView.arrowHeight))
|
||||
helpText.backgroundColor = UIColor.clear
|
||||
helpText.font = helpText.font.withSize(fontSize)
|
||||
helpText.textAlignment = .center
|
||||
|
|
@ -1134,13 +1034,11 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
keymanWeb.setDeviceType(UIDevice.current.userInterfaceIdiom)
|
||||
|
||||
var newKb = Defaults.keyboard
|
||||
if (keyboardID == nil || languageID == nil) && !shouldReloadKeyboard {
|
||||
if currentKeyboardID == nil && !shouldReloadKeyboard {
|
||||
let userData = Util.isSystemKeyboard ? UserDefaults.standard : Storage.active.userDefaults
|
||||
if let currentKb = userData.currentKeyboard {
|
||||
let kbID = currentKb.id
|
||||
let langID = currentKb.languageID
|
||||
if Storage.active.userDefaults.userKeyboard(withID: kbID, languageID: langID) != nil {
|
||||
newKb = currentKb
|
||||
if let id = userData.currentKeyboardID {
|
||||
if let kb = Storage.active.userDefaults.userKeyboard(withFullID: id) {
|
||||
newKb = kb
|
||||
}
|
||||
} else if let userKbs = Storage.active.userDefaults.userKeyboards, !userKbs.isEmpty {
|
||||
newKb = userKbs[0]
|
||||
|
|
@ -1178,8 +1076,8 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
keyPreviewView = KeyPreviewView(frame: keyFrame)
|
||||
|
||||
keyPreviewView!.setLabelText(preview)
|
||||
var oskFontName = oskFontNameForKeyboard(withID: keyboardID!, languageID: languageID!)
|
||||
oskFontName = oskFontName ?? fontNameForKeyboard(withID: keyboardID!, languageID: languageID!)
|
||||
var oskFontName = oskFontNameForKeyboard(withFullID: currentKeyboardID!)
|
||||
oskFontName = oskFontName ?? fontNameForKeyboard(withFullID: currentKeyboardID!)
|
||||
keyPreviewView!.setLabelFont(oskFontName)
|
||||
keymanWeb.view.addSubview(keyPreviewView!)
|
||||
}
|
||||
|
|
@ -1308,9 +1206,9 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
let isPad = UIDevice.current.userInterfaceIdiom == .pad
|
||||
let fontSize = isPad ? UIFont.buttonFontSize * 2 : UIFont.buttonFontSize
|
||||
|
||||
var oskFontName = oskFontNameForKeyboard(withID: keyboardID!, languageID: languageID!)
|
||||
var oskFontName = oskFontNameForKeyboard(withFullID: currentKeyboardID!)
|
||||
if oskFontName == nil {
|
||||
oskFontName = fontNameForKeyboard(withID: keyboardID!, languageID: languageID!)
|
||||
oskFontName = fontNameForKeyboard(withFullID: currentKeyboardID!)
|
||||
}
|
||||
|
||||
if subKeyIDs.isEmpty {
|
||||
|
|
@ -1397,7 +1295,7 @@ public class Manager: NSObject, HTTPDownloadDelegate, UIGestureRecognizerDelegat
|
|||
|
||||
if (!didSynchronize || shouldSynchronize) && Storage.shared != nil {
|
||||
synchronizeSWKeyboard()
|
||||
if keyboardID != nil && languageID != nil {
|
||||
if currentKeyboardID != nil {
|
||||
shouldReloadKeyboard = true
|
||||
reloadKeyboard(in: keymanWeb)
|
||||
}
|
||||
|
|
|
|||
224
ios/engine/KMEI/KeymanEngine/Classes/Migrations.swift
Normal file
224
ios/engine/KMEI/KeymanEngine/Classes/Migrations.swift
Normal file
|
|
@ -0,0 +1,224 @@
|
|||
//
|
||||
// Migrations.swift
|
||||
// KeymanEngine
|
||||
//
|
||||
// Created by Gabriel Wong on 2017-12-08.
|
||||
// Copyright © 2017 SIL International. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
private enum MigrationLevel {
|
||||
static let initial = 0
|
||||
static let migratedUserDefaultsToStructs = 10
|
||||
static let migratedForKMP = 20
|
||||
}
|
||||
|
||||
enum Migrations {
|
||||
static func migrate(storage: Storage) {
|
||||
if storage.userDefaults.migrationLevel < MigrationLevel.migratedUserDefaultsToStructs {
|
||||
migrateUserDefaultsToStructs(storage: storage)
|
||||
storage.userDefaults.migrationLevel = MigrationLevel.migratedUserDefaultsToStructs
|
||||
} else {
|
||||
log.info("UserDefaults migration to structs already performed. Skipping.")
|
||||
}
|
||||
if storage.userDefaults.migrationLevel < MigrationLevel.migratedForKMP {
|
||||
migrateForKMP(storage: storage)
|
||||
storage.userDefaults.migrationLevel = MigrationLevel.migratedForKMP
|
||||
} else {
|
||||
log.info("KMP directory migration already performed. Skipping.")
|
||||
}
|
||||
storage.userDefaults.synchronize()
|
||||
}
|
||||
|
||||
static func migrateUserDefaultsToStructs(storage: Storage) {
|
||||
guard let userKeyboardObject = storage.userDefaults.object(forKey: Key.userKeyboardsList),
|
||||
let currentKeyboardObject = storage.userDefaults.object(forKey: Key.userCurrentKeyboard)
|
||||
else {
|
||||
log.info("User keyboard list or current keyboard missing. Skipping migration.")
|
||||
return
|
||||
}
|
||||
guard let oldUserKeyboards = userKeyboardObject as? [[String: String]],
|
||||
let oldCurrentKeyboard = currentKeyboardObject as? [String: String]
|
||||
else {
|
||||
log.error("User keyboard list or current keyboard has an unexpected type")
|
||||
return
|
||||
}
|
||||
|
||||
let userKeyboards = oldUserKeyboards.flatMap { installableKeyboard(from: $0) }
|
||||
let currentKeyboardID = fullKeyboardID(from: oldCurrentKeyboard)
|
||||
|
||||
storage.userDefaults.userKeyboards = userKeyboards
|
||||
if userKeyboards.contains(where: { $0.fullID == currentKeyboardID }) {
|
||||
storage.userDefaults.currentKeyboardID = currentKeyboardID
|
||||
} else {
|
||||
storage.userDefaults.currentKeyboardID = nil
|
||||
}
|
||||
}
|
||||
|
||||
private static func installableKeyboard(from kbDict: [String: String]) -> InstallableKeyboard? {
|
||||
log.debug("Migrating keyboard dictionary: \(kbDict)")
|
||||
guard let id = kbDict["kbId"],
|
||||
let name = kbDict["kbName"],
|
||||
let languageID = kbDict["langId"],
|
||||
let languageName = kbDict["langName"],
|
||||
let version = kbDict["version"]
|
||||
else {
|
||||
log.error("Missing required fields in keyboard dictionary: \(kbDict)")
|
||||
return nil
|
||||
}
|
||||
let rtl = kbDict["rtl"] == "Y"
|
||||
let isCustom = kbDict["CustomKeyboard"] == "Y"
|
||||
let displayFont = font(from: kbDict["font"])
|
||||
let oskFont = font(from: kbDict["oskFont"])
|
||||
let kb = InstallableKeyboard(id: id,
|
||||
name: name,
|
||||
languageID: languageID,
|
||||
languageName: languageName,
|
||||
version: version,
|
||||
isRTL: rtl,
|
||||
font: displayFont,
|
||||
oskFont: oskFont,
|
||||
isCustom: isCustom)
|
||||
log.debug("Migrated keyboard dictionary to keyboard \(kb)")
|
||||
return kb
|
||||
}
|
||||
|
||||
private static func fullKeyboardID(from kbDict: [String: String]) -> FullKeyboardID? {
|
||||
log.debug("Migrating keyboard dictionary to FullKeyboardID: \(kbDict)")
|
||||
guard let keyboardID = kbDict["kbId"],
|
||||
let languageID = kbDict["langId"]
|
||||
else {
|
||||
log.error("Missing required fields in keyboard dictionary for FullKeyboardID: \(kbDict)")
|
||||
return nil
|
||||
}
|
||||
let id = FullKeyboardID(keyboardID: keyboardID, languageID: languageID)
|
||||
log.debug("Migrated keyboard dictionary to \(id)")
|
||||
return id
|
||||
}
|
||||
|
||||
private static func font(from jsonString: String?) -> Font? {
|
||||
guard let jsonString = jsonString else {
|
||||
return nil
|
||||
}
|
||||
guard let data = jsonString.data(using: .utf8) else {
|
||||
log.error("Failed to encode string: \(jsonString)")
|
||||
return nil
|
||||
}
|
||||
guard let fontDict = (try? JSONSerialization.jsonObject(with: data, options: [])) as? [String: Any] else {
|
||||
log.error("Error parsing String as JSON: \(jsonString)")
|
||||
return nil
|
||||
}
|
||||
guard let family = fontDict["family"] as? String else {
|
||||
log.error("Missing 'family' String: \(fontDict)")
|
||||
return nil
|
||||
}
|
||||
let files: [String]
|
||||
if let filesString = fontDict["files"] as? String {
|
||||
files = [filesString]
|
||||
} else if let filesArray = fontDict["files"] as? [String] {
|
||||
files = filesArray
|
||||
} else {
|
||||
log.error("Missing 'files': \(fontDict)")
|
||||
return nil
|
||||
}
|
||||
return Font(family: family, source: files)
|
||||
}
|
||||
|
||||
static func migrateForKMP(storage: Storage) {
|
||||
let languageDir = storage.baseDir.appendingPathComponent("languages")
|
||||
let fontDir = storage.baseDir.appendingPathComponent("fonts")
|
||||
|
||||
log.info("Migrating from base directory: \(storage.baseDir)")
|
||||
|
||||
guard var userKeyboards = storage.userDefaults.userKeyboards else {
|
||||
log.info("No user keyboards to migrate")
|
||||
return
|
||||
}
|
||||
|
||||
var urlsForKeyboard: [String: Set<URL>] = [:]
|
||||
for i in userKeyboards.indices {
|
||||
let keyboard = userKeyboards[i]
|
||||
guard let version = latestKeyboardFileVersion(withID: keyboard.id, dirPath: languageDir.path) else {
|
||||
log.warning("Could not find JS file for keyboard \(keyboard.id) in \(languageDir.path)")
|
||||
continue
|
||||
}
|
||||
var urls = urlsForKeyboard[keyboard.id] ?? Set()
|
||||
urls.insert(languageDir.appendingPathComponent("\(keyboard.id)-\(version.string).js"))
|
||||
|
||||
let fontFiles = (keyboard.font?.source ?? []) + (keyboard.oskFont?.source ?? [])
|
||||
for file in fontFiles {
|
||||
guard file.hasFontExtension else {
|
||||
log.info("Skipping copy of \(file) for keyboard \(keyboard.id) since it is not a font file.")
|
||||
continue
|
||||
}
|
||||
let url = fontDir.appendingPathComponent(file)
|
||||
guard FileManager.default.fileExists(atPath: url.path) else {
|
||||
log.warning("Font file \(url) for keyboard \(keyboard.id) does not exist")
|
||||
continue
|
||||
}
|
||||
urls.insert(url)
|
||||
}
|
||||
urlsForKeyboard[keyboard.id] = urls
|
||||
userKeyboards[i].version = version.string
|
||||
}
|
||||
|
||||
var successfulKeyboards: [String] = []
|
||||
|
||||
// Copy files
|
||||
for (keyboardID, urls) in urlsForKeyboard {
|
||||
let keyboardDir = storage.keyboardDir(forID: keyboardID)
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: keyboardDir,
|
||||
withIntermediateDirectories: true,
|
||||
attributes: nil)
|
||||
} catch {
|
||||
log.error("Failed to create keyboard directory at \(keyboardDir)")
|
||||
continue
|
||||
}
|
||||
|
||||
var successful = true
|
||||
for srcURL in urls {
|
||||
let dstURL = keyboardDir.appendingPathComponent(srcURL.lastPathComponent)
|
||||
do {
|
||||
try FileManager.default.copyItem(at: srcURL, to: dstURL)
|
||||
} catch {
|
||||
log.error("Failed to copy from \(srcURL) to \(dstURL) for keyboard \(keyboardID)")
|
||||
successful = false
|
||||
}
|
||||
}
|
||||
if successful {
|
||||
successfulKeyboards.append(keyboardID)
|
||||
log.info("Succesfully copied keyboard files for keyboard \(keyboardID)")
|
||||
}
|
||||
}
|
||||
|
||||
// Remove keyboards that were not copied successfully
|
||||
let filteredUserKeyboards = userKeyboards.filter { successfulKeyboards.contains($0.id) }
|
||||
storage.userDefaults.userKeyboards = filteredUserKeyboards
|
||||
|
||||
// TODO: Remove old directory
|
||||
}
|
||||
|
||||
private static func latestKeyboardFileVersion(withID keyboardID: String, dirPath: String) -> Version? {
|
||||
guard let dirContents = try? FileManager.default.contentsOfDirectory(atPath: dirPath) else {
|
||||
return nil
|
||||
}
|
||||
|
||||
var latestVersion: Version?
|
||||
for filename in dirContents where filename.hasPrefix("\(keyboardID)-") && filename.hasJavaScriptExtension {
|
||||
let dashRange = filename.range(of: "-", options: .backwards)!
|
||||
let extensionRange = filename.range(of: ".js", options: .backwards)!
|
||||
guard let version = Version(String(filename[dashRange.upperBound..<extensionRange.lowerBound])) else {
|
||||
continue
|
||||
}
|
||||
|
||||
if let previousMax = latestVersion {
|
||||
latestVersion = max(version, previousMax)
|
||||
} else {
|
||||
latestVersion = version
|
||||
}
|
||||
}
|
||||
return latestVersion
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// FullKeyboardID.swift
|
||||
// KeymanEngine
|
||||
//
|
||||
// Created by Gabriel Wong on 2017-12-08.
|
||||
// Copyright © 2017 SIL International. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// A complete identifier for an `InstallableKeyboard`. Keyboards must have unique `FullKeyboardID`s.
|
||||
public struct FullKeyboardID: Codable {
|
||||
public var keyboardID: String
|
||||
public var languageID: String
|
||||
}
|
||||
|
||||
// MARK: - Equatable
|
||||
extension FullKeyboardID: Equatable {
|
||||
public static func ==(lhs: FullKeyboardID, rhs: FullKeyboardID) -> Bool {
|
||||
return lhs.keyboardID == rhs.keyboardID && lhs.languageID == rhs.languageID
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - CustomStringConvertible
|
||||
extension FullKeyboardID: CustomStringConvertible {
|
||||
public var description: String {
|
||||
return "<keyboardID: \"\(keyboardID)\", languageID: \"\(languageID)\">"
|
||||
}
|
||||
}
|
||||
|
|
@ -20,6 +20,10 @@ public struct InstallableKeyboard: Codable {
|
|||
public var oskFont: Font?
|
||||
public var isCustom: Bool
|
||||
|
||||
public var fullID: FullKeyboardID {
|
||||
return FullKeyboardID(keyboardID: id, languageID: languageID)
|
||||
}
|
||||
|
||||
public init(id: String,
|
||||
name: String,
|
||||
languageID: String,
|
||||
|
|
@ -40,7 +44,7 @@ public struct InstallableKeyboard: Codable {
|
|||
self.isCustom = isCustom
|
||||
}
|
||||
|
||||
public init(keyboard: Keyboard, language: Language) {
|
||||
public init(keyboard: Keyboard, language: Language, isCustom: Bool) {
|
||||
self.id = keyboard.id
|
||||
self.name = keyboard.name
|
||||
self.languageID = language.id
|
||||
|
|
@ -49,6 +53,6 @@ public struct InstallableKeyboard: Codable {
|
|||
self.isRTL = keyboard.isRTL
|
||||
self.font = keyboard.font
|
||||
self.oskFont = keyboard.oskFont
|
||||
self.isCustom = false
|
||||
self.isCustom = isCustom
|
||||
}
|
||||
}
|
||||
|
|
|
|||
50
ios/engine/KMEI/KeymanEngine/Classes/Model/Version.swift
Normal file
50
ios/engine/KMEI/KeymanEngine/Classes/Model/Version.swift
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
//
|
||||
// Version.swift
|
||||
// KeymanEngine
|
||||
//
|
||||
// Created by Gabriel Wong on 2017-11-23.
|
||||
// Copyright © 2017 SIL International. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
/// Dotted-decimal version.
|
||||
public struct Version: Comparable {
|
||||
public static let fallback = Version("1.0")!
|
||||
|
||||
private let components: [Int]
|
||||
public let string: String
|
||||
|
||||
public init?(_ string: String) {
|
||||
let stringComponents = string.components(separatedBy: ".")
|
||||
var components: [Int] = []
|
||||
for s in stringComponents {
|
||||
guard let i = Int(s), i >= 0 else {
|
||||
return nil
|
||||
}
|
||||
components.append(i)
|
||||
}
|
||||
|
||||
self.string = string
|
||||
self.components = components
|
||||
}
|
||||
|
||||
public static func <(lhs: Version, rhs: Version) -> Bool {
|
||||
let len = max(lhs.components.count, rhs.components.count)
|
||||
for i in 0..<len {
|
||||
let leftComponent = lhs.components[safe: i] ?? 0
|
||||
let rightComponent = rhs.components[safe: i] ?? 0
|
||||
if leftComponent < rightComponent {
|
||||
return true
|
||||
}
|
||||
if leftComponent > rightComponent {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
public static func ==(lhs: Version, rhs: Version) -> Bool {
|
||||
return lhs.components == rhs.components
|
||||
}
|
||||
}
|
||||
|
|
@ -47,8 +47,7 @@ extension Storage {
|
|||
|
||||
class Storage {
|
||||
let baseDir: URL
|
||||
let languageDir: URL
|
||||
let fontDir: URL
|
||||
let keyboardDir: URL
|
||||
let userDefaults: UserDefaults
|
||||
|
||||
let kmwURL: URL
|
||||
|
|
@ -57,23 +56,19 @@ class Storage {
|
|||
private init?(baseURL: URL, userDefaults: UserDefaults) {
|
||||
guard
|
||||
let baseDir = Storage.createSubdirectory(baseDir: baseURL, name: "keyman"),
|
||||
let languageDir = Storage.createSubdirectory(baseDir: baseDir, name: "languages"),
|
||||
let fontDir = Storage.createSubdirectory(baseDir: baseDir, name: "fonts") else {
|
||||
let keyboardDir = Storage.createSubdirectory(baseDir: baseDir, name: "keyboards")
|
||||
else {
|
||||
return nil
|
||||
}
|
||||
|
||||
self.baseDir = baseDir
|
||||
self.languageDir = languageDir
|
||||
self.fontDir = fontDir
|
||||
self.keyboardDir = keyboardDir
|
||||
self.userDefaults = userDefaults
|
||||
kmwURL = baseDir.appendingPathComponent(Resources.kmwFilename)
|
||||
specialOSKFontURL = baseDir.appendingPathComponent(Resources.oskFontFilename)
|
||||
}
|
||||
|
||||
private static func createSubdirectory(baseDir: URL?, name: String) -> URL? {
|
||||
guard let baseDir = baseDir else {
|
||||
return nil
|
||||
}
|
||||
private static func createSubdirectory(baseDir: URL, name: String) -> URL? {
|
||||
let newDir = baseDir.appendingPathComponent(name)
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: newDir,
|
||||
|
|
@ -81,20 +76,45 @@ class Storage {
|
|||
attributes: nil)
|
||||
return newDir
|
||||
} catch {
|
||||
log.error("Failed to create subdirectory at \(newDir)")
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func keyboardDir(forID keyboardID: String) -> URL {
|
||||
return keyboardDir.appendingPathComponent(keyboardID)
|
||||
}
|
||||
|
||||
func keyboardURL(for keyboard: InstallableKeyboard) -> URL {
|
||||
return keyboardURL(forID: keyboard.id, version: keyboard.version)
|
||||
}
|
||||
|
||||
func keyboardURL(forID keyboardID: String, version: String) -> URL {
|
||||
return languageDir.appendingPathComponent("\(keyboardID)-\(version).js")
|
||||
return keyboardDir(forID: keyboardID).appendingPathComponent("\(keyboardID)-\(version).js")
|
||||
}
|
||||
|
||||
func fontURL(forFilename filename: String) -> URL {
|
||||
return fontDir.appendingPathComponent(filename)
|
||||
func fontURL(forKeyboardID keyboardID: String, filename: String) -> URL {
|
||||
return keyboardDir(forID: keyboardID).appendingPathComponent(filename)
|
||||
}
|
||||
|
||||
var keyboardDirs: [URL]? {
|
||||
let contents: [URL]
|
||||
do {
|
||||
contents = try FileManager.default.contentsOfDirectory(at: keyboardDir,
|
||||
includingPropertiesForKeys: [.isDirectoryKey])
|
||||
} catch {
|
||||
log.error("Failed to list contents at \(keyboardDir) with error \(error)")
|
||||
return nil
|
||||
}
|
||||
return contents.filter { url in
|
||||
do {
|
||||
let values = try url.resourceValues(forKeys: [.isDirectoryKey])
|
||||
return values.isDirectory ?? false
|
||||
} catch {
|
||||
log.error(error)
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,28 +123,32 @@ extension Storage {
|
|||
func copyKMWFiles(from bundle: Bundle) throws {
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: Resources.kmwFilename,
|
||||
dstDir: Storage.active.baseDir)
|
||||
dstDir: baseDir)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: "keymanios.js",
|
||||
dstDir: Storage.active.baseDir)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: "\(Defaults.keyboard.id)-\(Defaults.keyboard.version).js",
|
||||
dstDir: Storage.active.languageDir)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: "DejaVuSans.ttf",
|
||||
dstDir: Storage.active.fontDir)
|
||||
dstDir: baseDir)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: "kmwosk.css",
|
||||
dstDir: Storage.active.baseDir)
|
||||
dstDir: baseDir)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: Resources.oskFontFilename,
|
||||
dstDir: Storage.active.baseDir)
|
||||
resourceName: "keymanweb-osk.ttf",
|
||||
dstDir: baseDir)
|
||||
let defaultKeyboardDir = self.keyboardDir(forID: Defaults.keyboard.id)
|
||||
try FileManager.default.createDirectory(at: defaultKeyboardDir, withIntermediateDirectories: true)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: "\(Defaults.keyboard.id)-\(Defaults.keyboard.version).js",
|
||||
dstDir: defaultKeyboardDir)
|
||||
try Storage.copy(from: bundle,
|
||||
resourceName: "DejaVuSans.ttf",
|
||||
dstDir: defaultKeyboardDir)
|
||||
}
|
||||
|
||||
func copyFiles(to dst: Storage) throws {
|
||||
try Storage.copyDirectoryContents(at: baseDir, to: dst.baseDir)
|
||||
try Storage.copyDirectoryContents(at: languageDir, to: dst.languageDir)
|
||||
try Storage.copyDirectoryContents(at: fontDir, to: dst.fontDir)
|
||||
if FileManager.default.fileExists(atPath: dst.baseDir.path) {
|
||||
log.info("Deleting \(dst.baseDir) for copy from \(baseDir) to \(dst.baseDir)")
|
||||
try FileManager.default.removeItem(at: dst.baseDir)
|
||||
}
|
||||
try FileManager.default.copyItem(at: baseDir, to: dst.baseDir)
|
||||
}
|
||||
|
||||
func copyUserDefaults(to dst: Storage, withKeys keys: [String], shouldOverwrite: Bool) {
|
||||
|
|
|
|||
|
|
@ -144,8 +144,7 @@ public class TextField: UITextField {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: Get font name directly from keyboard object
|
||||
let fontName = Manager.shared.fontNameForKeyboard(withID: kb.id, languageID: kb.languageID)
|
||||
let fontName = Manager.shared.fontNameForKeyboard(withFullID: kb.fullID)
|
||||
let fontSize = font?.pointSize ?? UIFont.systemFontSize
|
||||
if let fontName = fontName {
|
||||
font = UIFont(name: fontName, size: fontSize)
|
||||
|
|
@ -240,10 +239,8 @@ extension TextField: UITextFieldDelegate {
|
|||
let textWD = baseWritingDirection(for: beginningOfDocument, in: .forward)
|
||||
|
||||
let isRTL: Bool
|
||||
if let keyboardID = Manager.shared.keyboardID,
|
||||
let languageID = Manager.shared.languageID {
|
||||
let keyboard = Storage.active.userDefaults.userKeyboard(withID: keyboardID, languageID: languageID)
|
||||
isRTL = keyboard?.isRTL ?? false
|
||||
if let keyboard = Manager.shared.currentKeyboard {
|
||||
isRTL = keyboard.isRTL
|
||||
} else {
|
||||
isRTL = false
|
||||
}
|
||||
|
|
@ -278,9 +275,8 @@ extension TextField: UITextFieldDelegate {
|
|||
Manager.shared.keymanWebDelegate = self
|
||||
|
||||
let fontName: String?
|
||||
if let keyboardID = Manager.shared.keyboardID,
|
||||
let languageID = Manager.shared.languageID {
|
||||
fontName = Manager.shared.fontNameForKeyboard(withID: keyboardID, languageID: languageID)
|
||||
if let id = Manager.shared.currentKeyboardID {
|
||||
fontName = Manager.shared.fontNameForKeyboard(withFullID: id)
|
||||
} else {
|
||||
fontName = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -133,8 +133,7 @@ public class TextView: UITextView {
|
|||
return
|
||||
}
|
||||
|
||||
// TODO: Get font name directly from keyboard
|
||||
let fontName = Manager.shared.fontNameForKeyboard(withID: kb.id, languageID: kb.languageID)
|
||||
let fontName = Manager.shared.fontNameForKeyboard(withFullID: kb.fullID)
|
||||
let fontSize = font?.pointSize ?? UIFont.systemFontSize
|
||||
if let fontName = fontName {
|
||||
font = UIFont(name: fontName, size: fontSize)
|
||||
|
|
@ -239,10 +238,8 @@ extension TextView: UITextViewDelegate {
|
|||
let textWD = baseWritingDirection(for: beginningOfDocument, in: .forward)
|
||||
|
||||
let isRTL: Bool
|
||||
if let keyboardID = Manager.shared.keyboardID,
|
||||
let languageID = Manager.shared.languageID {
|
||||
let keyboard = Storage.active.userDefaults.userKeyboard(withID: keyboardID, languageID: languageID)
|
||||
isRTL = keyboard?.isRTL ?? false
|
||||
if let keyboard = Manager.shared.currentKeyboard {
|
||||
isRTL = keyboard.isRTL
|
||||
} else {
|
||||
isRTL = false
|
||||
}
|
||||
|
|
@ -279,9 +276,8 @@ extension TextView: UITextViewDelegate {
|
|||
Manager.shared.keymanWebDelegate = self
|
||||
|
||||
let fontName: String?
|
||||
if let keyboardID = Manager.shared.keyboardID,
|
||||
let languageID = Manager.shared.languageID {
|
||||
fontName = Manager.shared.fontNameForKeyboard(withID: keyboardID, languageID: languageID)
|
||||
if let id = Manager.shared.currentKeyboardID {
|
||||
fontName = Manager.shared.fontNameForKeyboard(withFullID: id)
|
||||
} else {
|
||||
fontName = nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ class InfoViewController: UIViewController, UIWebViewDelegate {
|
|||
}
|
||||
|
||||
private func loadFromServer() {
|
||||
let keyboardInfo = Manager.shared.currentKeyboardInfo
|
||||
let keyboardInfo = Manager.shared.currentKeyboard
|
||||
let currentKeyboardId = keyboardInfo?.id ?? Defaults.keyboard.id
|
||||
let userData = AppDelegate.activeUserDefaults()
|
||||
let keyboards = userData.userKeyboards
|
||||
|
|
|
|||
|
|
@ -273,7 +273,7 @@ class WebBrowserViewController: UIViewController, UIWebViewDelegate, UIAlertView
|
|||
}
|
||||
|
||||
private func keyboardChanged(_ kb: InstallableKeyboard) {
|
||||
if let fontName = Manager.shared.fontNameForKeyboard(withID: kb.id, languageID: kb.languageID) {
|
||||
if let fontName = Manager.shared.fontNameForKeyboard(withFullID: kb.fullID) {
|
||||
newFontFamily = fontName
|
||||
} else {
|
||||
newFontFamily = UIFont.systemFont(ofSize: UIFont.systemFontSize).fontName
|
||||
|
|
|
|||
|
|
@ -470,7 +470,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg
|
|||
didDownload = false
|
||||
}
|
||||
|
||||
checkProfile(forKeyboardID: kb.id, languageID: kb.languageID, doListCheck: listCheck)
|
||||
checkProfile(forFullID: kb.fullID, doListCheck: listCheck)
|
||||
}
|
||||
|
||||
private func keyboardDownloadStarted() {
|
||||
|
|
@ -869,8 +869,8 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg
|
|||
}
|
||||
}
|
||||
|
||||
private func profileName(withKeyboardID kbID: String, languageID langID: String) -> String? {
|
||||
guard let keyboard = AppDelegate.activeUserDefaults().userKeyboard(withID: kbID, languageID: langID),
|
||||
private func profileName(withFullID fullID: FullKeyboardID) -> String? {
|
||||
guard let keyboard = AppDelegate.activeUserDefaults().userKeyboard(withFullID: fullID),
|
||||
let font = keyboard.font else {
|
||||
return nil
|
||||
}
|
||||
|
|
@ -882,15 +882,15 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg
|
|||
return font.source.first { $0.lowercased().hasSuffix(FileExtensions.configurationProfile) }
|
||||
}
|
||||
|
||||
private func checkProfile(forKeyboardID kbID: String, languageID langID: String, doListCheck: Bool) {
|
||||
if kbID == Defaults.keyboard.id && langID == Defaults.keyboard.languageID {
|
||||
private func checkProfile(forFullID fullID: FullKeyboardID, doListCheck: Bool) {
|
||||
if fullID == Defaults.keyboard.fullID {
|
||||
return
|
||||
}
|
||||
if profileName != nil {
|
||||
return // already installing a profile
|
||||
}
|
||||
|
||||
guard let profile = profileName(withKeyboardID: kbID, languageID: langID) else {
|
||||
guard let profile = profileName(withFullID: fullID) else {
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -906,7 +906,7 @@ class MainViewController: UIViewController, TextViewDelegate, UIActionSheetDeleg
|
|||
|
||||
if doInstall {
|
||||
profileName = profile
|
||||
let keyboard = AppDelegate.activeUserDefaults().userKeyboard(withID: kbID, languageID: langID)!
|
||||
let keyboard = AppDelegate.activeUserDefaults().userKeyboard(withFullID: fullID)!
|
||||
let languageName = keyboard.languageName
|
||||
let title = "\(languageName) Font"
|
||||
let msg = "Touch Install to make \(languageName) display correctly in all your apps"
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class SetUpViewController: UIViewController, UIWebViewDelegate {
|
|||
}
|
||||
|
||||
private func loadFromServer() {
|
||||
let keyboardInfo = Manager.shared.currentKeyboardInfo
|
||||
let keyboardInfo = Manager.shared.currentKeyboard
|
||||
let currentKeyboardId = keyboardInfo?.id ?? Defaults.keyboard.id
|
||||
let userData = AppDelegate.activeUserDefaults()
|
||||
let keyboards = userData.userKeyboards
|
||||
|
|
|
|||
|
|
@ -15,17 +15,7 @@ class ViewController: UIViewController, TextViewDelegate {
|
|||
super.viewDidLoad()
|
||||
Manager.shared.openURL = UIApplication.shared.openURL
|
||||
Manager.shared.isKeymanHelpOn = false
|
||||
do {
|
||||
try Manager.shared.preloadKeyboardFile(at: Bundle.main.url(forResource: "tamil99m-1.1", withExtension: "js")!,
|
||||
shouldOverwrite: true)
|
||||
try Manager.shared.preloadFontFile(at: Bundle.main.url(forResource: "aava1", withExtension: "ttf")!,
|
||||
shouldOverwrite: true)
|
||||
} catch {
|
||||
print("Error preloading: \(error)")
|
||||
}
|
||||
FontManager.shared.registerCustomFonts()
|
||||
|
||||
Manager.shared.addKeyboard(Defaults.keyboard)
|
||||
let kb = InstallableKeyboard(id: "tamil99m",
|
||||
name: "Tamil 99M",
|
||||
languageID: "tam",
|
||||
|
|
@ -35,6 +25,18 @@ class ViewController: UIViewController, TextViewDelegate {
|
|||
font: Font(filename: "aava1.ttf"),
|
||||
oskFont: nil,
|
||||
isCustom: true)
|
||||
let urls = [
|
||||
Bundle.main.url(forResource: "tamil99m-1.1", withExtension: "js")!,
|
||||
Bundle.main.url(forResource: "aava1", withExtension: "ttf")!
|
||||
]
|
||||
do {
|
||||
try Manager.shared.preloadFiles(forKeyboardID: kb.id, at: urls, shouldOverwrite: true)
|
||||
} catch {
|
||||
print("Error preloading: \(error)")
|
||||
}
|
||||
FontManager.shared.registerCustomFonts()
|
||||
|
||||
Manager.shared.addKeyboard(Defaults.keyboard)
|
||||
Manager.shared.addKeyboard(kb)
|
||||
|
||||
textView.setKeymanDelegate(self)
|
||||
|
|
|
|||
|
|
@ -16,19 +16,8 @@ class ViewController: UIViewController, TextViewDelegate {
|
|||
super.viewDidLoad()
|
||||
|
||||
Manager.shared.openURL = UIApplication.shared.openURL
|
||||
|
||||
Manager.shared.isKeymanHelpOn = false
|
||||
do {
|
||||
try Manager.shared.preloadKeyboardFile(at: Bundle.main.url(forResource: "tamil99m-1.1", withExtension: "js")!,
|
||||
shouldOverwrite: true)
|
||||
try Manager.shared.preloadFontFile(at: Bundle.main.url(forResource: "aava1", withExtension: "ttf")!,
|
||||
shouldOverwrite: true)
|
||||
} catch {
|
||||
print("Error preloading: \(error)")
|
||||
}
|
||||
FontManager.shared.registerCustomFonts()
|
||||
|
||||
Manager.shared.addKeyboard(Defaults.keyboard)
|
||||
let kb = InstallableKeyboard(id: "tamil99m",
|
||||
name: "Tamil 99M",
|
||||
languageID: "tam",
|
||||
|
|
@ -38,6 +27,18 @@ class ViewController: UIViewController, TextViewDelegate {
|
|||
font: Font(filename: "aava1.ttf"),
|
||||
oskFont: nil,
|
||||
isCustom: true)
|
||||
let urls = [
|
||||
Bundle.main.url(forResource: "tamil99m-1.1", withExtension: "js")!,
|
||||
Bundle.main.url(forResource: "aava1", withExtension: "ttf")!
|
||||
]
|
||||
do {
|
||||
try Manager.shared.preloadFiles(forKeyboardID: kb.id, at: urls, shouldOverwrite: true)
|
||||
} catch {
|
||||
print("Error preloading: \(error)")
|
||||
}
|
||||
FontManager.shared.registerCustomFonts()
|
||||
|
||||
Manager.shared.addKeyboard(Defaults.keyboard)
|
||||
Manager.shared.addKeyboard(kb)
|
||||
|
||||
textView.setKeymanDelegate(self)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue