Merge pull request #3255 from keymanapp/modify/android/add-language-from-package

feat(android): Implement menu to add language for installed keyboard pkg
This commit is contained in:
Darcy Wong 2020-06-22 06:43:48 +07:00 • committed by GitHub
commit 3a6dcc2ddd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 366 additions and 15 deletions

View file

@ -226,6 +226,18 @@
android:parentActivityName=".KeymanSettingsActivity"
android:launchMode="singleTask"
android:theme="@style/AppTheme.Base" />
<activity
android:name=".SelectPackageActivity"
android:label="@string/app_name"
android:parentActivityName=".KeymanSettingsInstallActivity"
android:launchMode="singleTask"
android:theme="@style/AppTheme.Base" />
<activity
android:name=".SelectLanguageActivity"
android:label="@string/app_name"
android:parentActivityName=".SelectPackageActivity"
android:launchMode="singleTask"
android:theme="@style/AppTheme.Base" />
<provider
android:name="androidx.core.content.FileProvider"

View file

@ -26,6 +26,7 @@ import android.widget.TextView;
import com.tavultesoft.kmea.KMManager;
import com.tavultesoft.kmea.KMPBrowserActivity;
import com.tavultesoft.kmea.data.KeyboardController;
import com.tavultesoft.kmea.util.MapCompat;
public class KeymanSettingsInstallActivity extends AppCompatActivity {
@ -107,6 +108,11 @@ public class KeymanSettingsInstallActivity extends AppCompatActivity {
if (itemTitle.equals(getString(R.string.install_from_other_device))) {
// Scan QR code not implemented yet
return false;
} else if (itemTitle.equals(getString(R.string.add_language_to_installed_keyboard))) {
if (KeyboardController.getInstance().getInstalledPackagesList() == null) {
// Disable if no keyboard packages installed
return false;
}
}
return super.isEnabled(position);
@ -150,7 +156,8 @@ public class KeymanSettingsInstallActivity extends AppCompatActivity {
// Add language from keyboard package already installed
} else if (itemTitle.equals(getString(R.string.add_language_to_installed_keyboard))) {
// TODO
Intent intent = new Intent(context, SelectPackageActivity.class);
context.startActivity(intent);
}
}
});

View file

@ -0,0 +1,126 @@
/**
* Copyright (C) 2020 SIL International. All rights reserved.
*/
package com.tavultesoft.kmapro;
import android.content.Context;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.tavultesoft.kmea.KMManager;
import com.tavultesoft.kmea.data.Keyboard;
import com.tavultesoft.kmea.data.KeyboardController;
import com.tavultesoft.kmea.packages.PackageProcessor;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Keyman Settings --> KeymanInstallActivity --> SelectPackageActivity --> SelectLanguageActivity
* Displays a list of available languages for the user to add for a given installed packageID/keyboardID.
*/
public final class SelectLanguageActivity extends AppCompatActivity {
private static final String TAG = "SelectLanguageActivity";
private static ArrayList<HashMap<String, String>> list = null;
private static KMListAdapter adapter = null;
private static Typeface titleFont = null;
private static final String titleKey = "title";
private static final String subtitleKey = "subtitle";
private static final String iconKey = "icon";
private static final String isEnabledKey = "isEnabled";
private static Context context;
private static final boolean excludeInstalledLanguages = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
context = this;
setContentView(R.layout.activity_list_layout);
final Toolbar toolbar = findViewById(R.id.list_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
final ListView listView = findViewById(R.id.listView);
listView.setFastScrollEnabled(true);
final Keyboard keyboard = (Keyboard)getIntent().getSerializableExtra("keyboard");
final String packageID = keyboard.getPackageID();
final String keyboardID = keyboard.getKeyboardID();
final String keyboardName = keyboard.getKeyboardName();
String title_install = String.format(getString(R.string.title_select_language_for_package), keyboardName);
String title_no_install = getString(R.string.all_languages_installed);
final TextView textView = findViewById(R.id.bar_title);
textView.setText(title_no_install);
if (titleFont != null) {
textView.setTypeface(titleFont, Typeface.BOLD);
}
// Get the list of available Keyboards from kmp.json
File resourceRoot = new File(context.getDir("data", Context.MODE_PRIVATE).toString() + File.separator);
PackageProcessor kmpProcessor = new PackageProcessor(resourceRoot);
List<Keyboard> availableKeyboardsList = kmpProcessor.getKeyboardList(
packageID, keyboardID, excludeInstalledLanguages);
final String noIcon = "0";
list = new ArrayList<HashMap<String, String>>();
for (Keyboard k : availableKeyboardsList) {
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(titleKey, k.getLanguageName());
hashMap.put(subtitleKey, k.getLanguageID());
String enable = "true";
String icon = String.valueOf(R.drawable.ic_arrow_forward);
if (!excludeInstalledLanguages && KeyboardController.getInstance().keyboardExists(
k.getPackageID(), k.getKeyboardID(), k.getLanguageID())) {
icon = String.valueOf(R.drawable.ic_check);
enable = "false";
} else {
// Update title
textView.setText(title_install);
}
hashMap.put(iconKey, icon);
hashMap.put(isEnabledKey, enable);
list.add(hashMap);
}
String[] from = new String[]{titleKey, subtitleKey, iconKey};
int[] to = new int[]{R.id.text1, R.id.text2, com.tavultesoft.kmea.R.id.image1};
adapter = new KMListAdapter(context, list, R.layout.list_row_layout2, from, to);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HashMap<String, String> hashMap = (HashMap<String, String>) parent.getItemAtPosition(position);
Keyboard k = availableKeyboardsList.get(position);
KMManager.addKeyboard(context, k);
String confirmation = String.format(getString(R.string.added_language_to_keyboard),
k.getLanguageName(), k.getKeyboardName());
Toast.makeText(context, confirmation, Toast.LENGTH_LONG).show();
finish();
}
});
}
@Override
public boolean onSupportNavigateUp() {
super.onBackPressed();
return true;
}
}

View file

@ -0,0 +1,112 @@
/**
* Copyright (C) 2020 SIL International. All rights reserved.
*/
package com.tavultesoft.kmapro;
import android.content.Context;
import android.content.Intent;
import android.graphics.Typeface;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import com.tavultesoft.kmea.data.Keyboard;
import com.tavultesoft.kmea.data.KeyboardController;
import com.tavultesoft.kmea.util.KMLog;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Keyman Settings --> KeymanInstallActivity --> SelectPackageActivity
* Displays a list of installed package ID / keyboard IDs so the user can select a language from the kmp.json
*/
public final class SelectPackageActivity extends AppCompatActivity {
private static final String TAG = "SelectPackageActivity";
private static ArrayList<HashMap<String, String>> list = null;
private static Typeface titleFont = null;
private static final String titleKey = "title";
private static final String subtitleKey = "subtitle";
private static final String iconKey = "icon";
private static Context context;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
context = this;
setContentView(R.layout.activity_list_layout);
final Toolbar toolbar = findViewById(R.id.list_toolbar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
getSupportActionBar().setDisplayShowTitleEnabled(false);
final ListView listView = findViewById(R.id.listView);
listView.setFastScrollEnabled(true);
Bundle bundle = getIntent().getExtras();
final TextView textView = findViewById(R.id.bar_title);
textView.setText(getString(R.string.title_select_keyboard_package_list));
if (titleFont != null) {
textView.setTypeface(titleFont, Typeface.BOLD);
}
List<Keyboard> packagesList = KeyboardController.getInstance().getInstalledPackagesList();
if (packagesList == null) {
// Should never actually happen
KMLog.LogError(TAG, "Installed keyboard package list is empty");
finish();
}
list = new ArrayList<HashMap<String, String>>();
for (Keyboard k : packagesList) {
String keyboardName = k.getKeyboardName();
String pkgID = k.getPackageID();
final String noIcon = "0";
HashMap<String, String> hashMap = new HashMap<>();
hashMap.put(titleKey, keyboardName);
hashMap.put(subtitleKey, pkgID);
String icon = String.valueOf(R.drawable.ic_arrow_forward);
hashMap.put(iconKey, icon);
list.add(hashMap);
}
String[] from = new String[]{titleKey, subtitleKey, iconKey};
int[] to = new int[]{com.tavultesoft.kmea.R.id.text1, com.tavultesoft.kmea.R.id.text2, com.tavultesoft.kmea.R.id.image1};
ListAdapter adapter = new SimpleAdapter(context, list, com.tavultesoft.kmea.R.layout.list_row_layout2, from, to) {
};
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
HashMap<String, String> hashMap = (HashMap<String, String>) parent.getItemAtPosition(position);
Bundle bundle = new Bundle();
bundle.putSerializable("keyboard", packagesList.get(position));
Intent intent = new Intent(context, SelectLanguageActivity.class);
intent.putExtras(bundle);
context.startActivity(intent);
}
});
}
@Override
public boolean onSupportNavigateUp() {
super.onBackPressed();
return true;
}
}

View file

@ -58,6 +58,12 @@
<string name="add_language_to_installed_keyboard">Add language to installed keyboard</string>
<string name="add_language_subtext">(from keyboard package)</string>
<!-- Select Package and Select Language menu strings -->
<string name="title_select_keyboard_package_list">Select Keyboard Package</string>
<string name="title_select_language_for_package">Select language for %1$s</string>
<string name="added_language_to_keyboard">Added language %1$s to %2$s</string>
<string name="all_languages_installed">All languages already installed</string>
<!-- Web Browser strings -->
<string name="hint_text">Search or type URL</string>
<string name="title_bookmarks">Bookmarks</string>

View file

@ -122,6 +122,37 @@ public class KeyboardController {
}
}
/**
* Returns the list of installed keyboards with unique packageID/keyboardID
*/
public List<Keyboard> getInstalledPackagesList() {
if (!isInitialized) {
KMLog.LogError(TAG, "getInstalledPackagesList while KeyboardController() not initialized");
return null;
}
synchronized (list) {
List<Keyboard> packagesList = new ArrayList<Keyboard>();
// Iterate through the installed keyboards list to find unique packageID/keyboardID
for (int i=0; i<list.size(); i++) {
Keyboard k = list.get(i);
String pkgID = k.getPackageID();
String keyboardID = k.getKeyboardID();
// Ignore "cloud" keyboards"
if (pkgID.equals(KMManager.KMDefault_UndefinedPackageID)) {
continue;
}
// If we search getKeyboardIndex with blank languageID, it will give us the first
// unique pkgID/keyboardID keyboard in the list
int firstMatchingIndex = getKeyboardIndex(pkgID, keyboardID, "");
if (firstMatchingIndex != KeyboardController.INDEX_NOT_FOUND && (firstMatchingIndex == i)) {
packagesList.add(k);
}
}
return packagesList;
}
}
/**
* Return the keyboard info at index
* @param index - int
@ -176,20 +207,6 @@ public class KeyboardController {
return index;
}
/**
* Given a languageID and keyboardID, return the index of the matching keyboard.
* If no match, returns INDEX_NOT_FOUND
* @param languageID - String of the language ID
* @param keyboardID - String of the keyboard ID
* @return int - Index of the matching keyboard
*/
/*
public int getKeyboardIndex(String languageID, String keyboardID) {
String key = String.format("%s_%s", languageID, keyboardID);
return getKeyboardIndex(key);
}
*/
/**
* Given a packageID, keyboardID, and languageID, return the index of the matching keyboard.
* If language ID not specified, only the package ID and keyboard ID are matched

View file

@ -4,6 +4,8 @@ import androidx.annotation.NonNull;
import com.tavultesoft.kmea.KMManager;
import com.tavultesoft.kmea.JSONParser;
import com.tavultesoft.kmea.data.Keyboard;
import com.tavultesoft.kmea.data.KeyboardController;
import com.tavultesoft.kmea.util.FileUtils;
import com.tavultesoft.kmea.util.KMLog;
import com.tavultesoft.kmea.util.ZipUtils;
@ -408,6 +410,75 @@ public class PackageProcessor {
return false;
}
/**
* Generates a list of Keyboards from the keyboard JSONObject. baseKeyboard contains
* keyboard information that's already installed.
* @param keyboardJSON JSONObject - Keyboard JSONObject from kmp.json (entry for keyboardID)
* @param baseKeyboard Keyboard - information of the keyboard that's already installed
* @param excludeInstalledLanguages - boolean whether to exclude languages that are already installed
* @return List<Keyboard>
*/
private List<Keyboard> getKeyboards(JSONObject keyboardJSON, Keyboard baseKeyboard,
boolean excludeInstalledLanguages ) {
List<Keyboard> list = new ArrayList<Keyboard>();
String packageID = baseKeyboard.getPackageID();
String keyboardID = baseKeyboard.getKeyboardID();
try {
JSONArray languages = keyboardJSON.getJSONArray("languages");
for (int j = 0; j < languages.length(); j++) {
JSONObject language = languages.getJSONObject(j);
String languageID = language.getString("id");
String languageName = language.getString("name");
if (!excludeInstalledLanguages ||
!(KeyboardController.getInstance().keyboardExists(packageID, keyboardID, languageID))) {
// Copy keyboard info and update language
Keyboard newKeyboard = new Keyboard(baseKeyboard);
newKeyboard.setLanguage(languageID, languageName);
list.add(newKeyboard);
}
}
} catch (Exception e) {
KMLog.LogException(TAG, "getKeyboards() ", e);
}
return list;
}
/**
* Get a list of available keyboard and language pairings that are available to add
* (parses the kmp.json for the language list)
* @param packageID - String of the package ID
* @param keyboardID - String of the keyboard ID
* @param excludeInstalledLanguages - Boolean whether to exclude
* installed languages from the returned list.
* @return List of <Keyboard> based on kmp.json. If excludeInstalledLanguages is true, this list
* excludes languages already installed
*/
public List<Keyboard> getKeyboardList(String packageID, String keyboardID, boolean excludeInstalledLanguages) {
File packagePath = new File(resourceRoot, KMManager.KMDefault_AssetPackages + File.separator + packageID);
List<Keyboard> list = new ArrayList<Keyboard>();
JSONObject infoJSON = loadPackageInfo(packagePath);
try {
JSONArray keyboards = infoJSON.getJSONArray("keyboards");
for (int i = 0; i < keyboards.length(); i++) {
JSONObject keyboard = keyboards.getJSONObject(i);
if (keyboardID.equals(keyboard.getString("id"))) {
// Find the keyboard already installed. We'll use it as the base
// for creating new keyboards
int baseKeyboardIndex = KeyboardController.getInstance().getKeyboardIndex(packageID, keyboardID, "");
if (baseKeyboardIndex == KeyboardController.INDEX_NOT_FOUND) {
continue;
}
Keyboard baseKeyboard = KeyboardController.getInstance().getKeyboardInfo(baseKeyboardIndex);
return getKeyboards(keyboard, baseKeyboard, excludeInstalledLanguages);
}
}
} catch (Exception e) {
KMLog.LogException(TAG, "getKeyboardList() ", e);
}
return list;
}
/**
* The master KMP processing method; use after a .kmp download to fully install within the filesystem.
* This will overwrite an existing package.