feat(android/app): Use api for downloading associated dictionary

This commit is contained in:
Darcy Wong 2020-09-22 15:57:59 +07:00
parent ce8c502191
commit 0f17062ad2
4 changed files with 203 additions and 17 deletions

View file

@ -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<CloudApiTypes.CloudApiParam> _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<CloudApiTypes.CloudApiParam> 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]));
}
}
}
}

View file

@ -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<Void,
List<CloudLexicalModelMetaDataDownloadCallback.MetaDataResult>>
{
/**
* the metadata result and all necessary downloads which should be started
*/
static class MetaDataResult
{
CloudApiTypes.CloudApiReturns returnjson;
CloudApiTypes.CloudApiParam params;
//HashMap<String,String> keyboardInfo;
String additionalDownloadid;
List<CloudApiTypes.CloudApiParam> 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<CloudLexicalModelMetaDataDownloadCallback.MetaDataResult> extractCloudResultFromDownloadSet(
CloudApiTypes.CloudDownloadSet<Void, List<CloudLexicalModelMetaDataDownloadCallback.MetaDataResult>> aDownload) {
List<CloudLexicalModelMetaDataDownloadCallback.MetaDataResult> _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<CloudLexicalModelMetaDataDownloadCallback.MetaDataResult> 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<MetaDataResult> 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<MetaDataResult> 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<CloudApiTypes.CloudApiParam> 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<Bundle> 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;
}
}

View file

@ -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)

View file

@ -102,6 +102,8 @@
<string name="keyboard_qr_code" comment="QR Code description">
Scan this code to load this\nkeyboard on another device</string>
<!-- Context: Query for associated dictionary -->
<string name="query_associated_model" comment="Check if there's an available dictionary to download">Checking for associated dictionary to download</string>
<!-- Context: Model Updates -->
<string name="confirm_download_model" comment="Confirmation to download a dictionary update">Would you like to download the latest version of this dictionary?</string>