From 0f17062ad2178d940ef8f0ecbab0bce25ebb335d Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 22 Sep 2020 15:57:59 +0700 Subject: [PATCH] feat(android/app): Use api for downloading associated dictionary --- .../com/tavultesoft/kmapro/MainActivity.java | 34 ++-- ...dLexicalModelMetaDataDownloadCallback.java | 178 ++++++++++++++++++ .../kmea/data/CloudRepository.java | 6 + .../KMEA/app/src/main/res/values/strings.xml | 2 + 4 files changed, 203 insertions(+), 17 deletions(-) create mode 100644 android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudLexicalModelMetaDataDownloadCallback.java diff --git a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java index 2e66d40925..2d70f99cce 100644 --- a/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java +++ b/android/KMAPro/kMAPro/src/main/java/com/tavultesoft/kmapro/MainActivity.java @@ -26,7 +26,7 @@ import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardDownloadEventListener import com.tavultesoft.kmea.KeyboardEventHandler.OnKeyboardEventListener; import com.tavultesoft.kmea.cloud.CloudApiTypes; import com.tavultesoft.kmea.cloud.CloudDownloadMgr; -import com.tavultesoft.kmea.cloud.impl.CloudLexicalPackageDownloadCallback; +import com.tavultesoft.kmea.cloud.impl.CloudLexicalModelMetaDataDownloadCallback; import com.tavultesoft.kmea.data.CloudRepository; import com.tavultesoft.kmea.data.Dataset; import com.tavultesoft.kmea.data.Keyboard; @@ -997,25 +997,25 @@ public class MainActivity extends AppCompatActivity implements OnKeyboardEventLi repo = CloudRepository.shared.fetchDataset(context); } - // Check if associated model is available in the cloud, and that it's not already installed - LexicalModel modelInfo = CloudRepository.shared.getAssociatedLexicalModel(context, languageID); - if ((modelInfo != null) && (KMManager.getAssociatedLexicalModel(languageID) == null)) { - String modelID = modelInfo.getLexicalModelID(); - String url = modelInfo.getUpdateKMP(); - if (url != null) { - ArrayList _params = new ArrayList<>(); - _params.add(new CloudApiTypes.CloudApiParam( - CloudApiTypes.ApiTarget.LexicalModelPackage, url)); + // Check if associated model is not already installed + if (KMManager.getAssociatedLexicalModel(languageID) == null) { + String _downloadid = CloudLexicalModelMetaDataDownloadCallback.createDownloadId(languageID); + CloudLexicalModelMetaDataDownloadCallback _callback = new CloudLexicalModelMetaDataDownloadCallback(); - // Check if model is already queued to download - String _downloadid= CloudLexicalPackageDownloadCallback.createDownloadId(modelID); - if(!CloudDownloadMgr.getInstance().alreadyDownloadingData(_downloadid)) { - KMKeyboardDownloaderActivity.downloadLexicalModel(context, modelID, _params); - } - } + Toast.makeText(context, + context.getString(R.string.query_associated_model), + Toast.LENGTH_SHORT).show(); + + ArrayList aPreparedCloudApiParams = new ArrayList<>(); + String url = CloudRepository.prepareLexicalModelQuery(languageID); + aPreparedCloudApiParams.add(new CloudApiTypes.CloudApiParam( + CloudApiTypes.ApiTarget.KeyboardLexicalModels, url).setType(CloudApiTypes.JSONType.Array)); + + CloudDownloadMgr.getInstance().executeAsDownload( + context, _downloadid, null, _callback, + aPreparedCloudApiParams.toArray(new CloudApiTypes.CloudApiParam[0])); } } - } } diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudLexicalModelMetaDataDownloadCallback.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudLexicalModelMetaDataDownloadCallback.java new file mode 100644 index 0000000000..a3de2dd44a --- /dev/null +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/cloud/impl/CloudLexicalModelMetaDataDownloadCallback.java @@ -0,0 +1,178 @@ +/** + * Copyright (C) 2020 SIL International. All rights reserved. + */ +package com.tavultesoft.kmea.cloud.impl; + +import android.content.Context; +import android.os.Bundle; +import android.widget.Toast; + +import com.tavultesoft.kmea.R; +import com.tavultesoft.kmea.cloud.CloudApiTypes; +import com.tavultesoft.kmea.cloud.CloudDataJsonUtil; +import com.tavultesoft.kmea.cloud.CloudDownloadMgr; +import com.tavultesoft.kmea.cloud.ICloudDownloadCallback; +import com.tavultesoft.kmea.util.KMLog; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.List; + +/** + * Start the lexical model download when lexical model metadata is downloaded. + */ +public class CloudLexicalModelMetaDataDownloadCallback implements ICloudDownloadCallback> +{ + /** + * the metadata result and all necessary downloads which should be started + */ + static class MetaDataResult + { + CloudApiTypes.CloudApiReturns returnjson; + CloudApiTypes.CloudApiParam params; + //HashMap keyboardInfo; + String additionalDownloadid; + List additionalDownloads; + } + + private static final String TAG = "CloudLMMetaDldCb"; + + /** + * Additional Cloud API parameter: language id. + */ + public static final String PARAM_LANG_ID = "lang_id"; + /** + * Additional Cloud API parameter: lexical model id. + */ + public static final String PARAM_LM_ID = "lm_id"; + + @Override + public void initializeContext(Context context) { + + } + + @Override + public List extractCloudResultFromDownloadSet( + CloudApiTypes.CloudDownloadSet> aDownload) { + + List _result = new ArrayList<>(aDownload.getSingleDownloads().size()); + + for (CloudApiTypes.SingleCloudDownload _d : aDownload.getSingleDownloads()) { + + CloudApiTypes.CloudApiReturns _json_result = CloudDataJsonUtil.retrieveJsonFromDownload(_d); + + if (_json_result != null) { + + CloudLexicalModelMetaDataDownloadCallback.MetaDataResult _data = new CloudLexicalModelMetaDataDownloadCallback.MetaDataResult(); + _data.returnjson = _json_result; + _data.params = _d.getCloudParams(); + _result.add(_data); // Null if offline. + } + } + return _result; + } + + @Override + public void applyCloudDownloadToModel(Context aContext, Void aModel, List aCloudResult) { + if (aCloudResult.isEmpty()) { + String msg = aContext.getString(R.string.catalog_unavailable); + Toast.makeText(aContext, msg, Toast.LENGTH_SHORT).show(); + KMLog.LogError(TAG, "Could not reach server"); + return; + } + + processCloudResults(aContext, aCloudResult); + + startDownloads(aContext, aCloudResult); + } + + /** + * Start the keyboard data and lexical model download. + * @param aContext the context + * @param aMetaDataResult the meta data result + */ + private void startDownloads(Context aContext, List aMetaDataResult) { + for(MetaDataResult _r:aMetaDataResult) + { + if(_r.additionalDownloads!=null) + { + if(_r.returnjson.target== CloudApiTypes.ApiTarget.KeyboardLexicalModels) { + if( CloudDownloadMgr.getInstance().alreadyDownloadingData(_r.additionalDownloadid)) + { + Toast.makeText(aContext, + aContext.getString(R.string.dictionary_download_is_running_in_background), + Toast.LENGTH_SHORT).show(); + continue; + } + CloudLexicalPackageDownloadCallback _callback = new CloudLexicalPackageDownloadCallback(); + + Toast.makeText(aContext, + aContext.getString(R.string.dictionary_download_start_in_background), + Toast.LENGTH_SHORT).show(); + + CloudDownloadMgr.getInstance().executeAsDownload(aContext, + _r.additionalDownloadid, null, _callback, + _r.additionalDownloads.toArray(new CloudApiTypes.CloudApiParam[0])); + } + } + } + } + + /** + * process the meta data result and prepare the additional downloads. + * @param aContext the context + * @param aMetaDataResult the meta data results + */ + private void processCloudResults(Context aContext, List aMetaDataResult) { + for(MetaDataResult _r:aMetaDataResult) { + if (_r.returnjson.target== CloudApiTypes.ApiTarget.Keyboard) { + //handleKeyboardMetaData(_r); + } + if(_r.returnjson.target== CloudApiTypes.ApiTarget.KeyboardLexicalModels) { + JSONArray lmData = _r.returnjson.jsonArray; + if (lmData != null && lmData.length() > 0) { + try { + JSONObject modelInfo = lmData.getJSONObject(0); + + if (modelInfo.has("packageFilename") && modelInfo.has("id")) { + String _modelID = modelInfo.getString("id"); + ArrayList urls = new ArrayList<>(); + urls.add(new CloudApiTypes.CloudApiParam( + CloudApiTypes.ApiTarget.LexicalModelPackage, + modelInfo.getString("packageFilename"))); + _r.additionalDownloadid = CloudLexicalPackageDownloadCallback.createDownloadId(_modelID); + _r.additionalDownloads= urls; + } + } catch (JSONException e) { + KMLog.LogException(TAG, "Error parsing lexical model from api.keyman.com. ", e); + } + } + } + + if (_r.returnjson.target == CloudApiTypes.ApiTarget.PackageVersion) { + JSONObject pkgData = _r.returnjson.jsonObject; + + if (pkgData != null) { + List updateBundles = new ArrayList<>(); + CloudDataJsonUtil.processKeyboardPackageUpdateJSON(aContext, pkgData, updateBundles); + CloudDataJsonUtil.processLexicalModelPackageUpdateJSON(aContext, pkgData, updateBundles); + } + } + } + } + + /** + * create a download id for the lexical model metadata. + * @param aLanguageId the language id + * @return the result + */ + public static String createDownloadId(String aLanguageId) + { + return "metadata_" + aLanguageId; + } + +} \ No newline at end of file diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java index 0bed00ec3f..2c32a53fc2 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/data/CloudRepository.java @@ -42,6 +42,7 @@ public class CloudRepository { public static final String API_MODEL_QUERY = "?q"; public static final String API_MODEL_FORMATSTR = "https://%s/model%s"; + public static final String API_MODEL_LANGUAGE_FORMATSTR = "https://%s/model?q=bcp47:%s"; public static final String API_PACKAGE_VERSION_FORMATSTR = "https://%s/package-version?platform=android%s%s"; private Dataset memCachedDataset; @@ -225,6 +226,11 @@ public class CloudRepository { /* do what's possible here, rather than in the Task */ } + public static String prepareLexicalModelQuery(String languageID) { + String lexicalURL = String.format(API_MODEL_LANGUAGE_FORMATSTR, getHost(), languageID); + return lexicalURL; + } + /** * initialize the data set from cache on startup of the application * (not used until keyboard update is implemented) diff --git a/android/KMEA/app/src/main/res/values/strings.xml b/android/KMEA/app/src/main/res/values/strings.xml index fbdd7f601c..5ed9a45453 100644 --- a/android/KMEA/app/src/main/res/values/strings.xml +++ b/android/KMEA/app/src/main/res/values/strings.xml @@ -102,6 +102,8 @@ Scan this code to load this\nkeyboard on another device + + Checking for associated dictionary to download Would you like to download the latest version of this dictionary?