Merge pull request #2020 from keymanapp/android-uninstall

[Android] Fix keyboard and model info pages
This commit is contained in:
Darcy Wong 2019-08-30 02:26:14 -05:00 • committed by GitHub
commit a476a1e2df
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 91 additions and 41 deletions

View file

@ -192,15 +192,6 @@
android:launchMode="singleTask"
android:theme="@style/AppTheme.Base" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.tavultesoft.kmapro.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View file

@ -69,6 +69,16 @@
android:theme="@style/Theme.AppCompat.Light.Dialog" >
</activity>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.tavultesoft.kmea.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
</manifest>

View file

@ -39,6 +39,7 @@ public class KMKeyboardDownloaderActivity extends AppCompatActivity {
public static final String ARG_MODEL_ID = "KMKeyboardActivity.modelID";
public static final String ARG_MODEL_NAME = "KMKeyboardActivity.modelName";
public static final String ARG_MODEL_URL = "KMKeyboardActivity.modelURL";
public static final String ARG_MODEL_CUSTOM_HELP_LINK = "KMKeyboardActivity.customHelpLink";
// custom keyboard
public static final String ARG_KEYBOARD = "KMKeyboardActivity.keyboard";

View file

@ -701,6 +701,7 @@ public final class KMManager {
languageJSONArray.put(languageID);
modelObj.put("languages", languageJSONArray);
modelObj.put("path", path);
modelObj.put("CustomHelpLink", lexicalModelInfo.get(KMKey_CustomHelpLink));
} catch (JSONException e) {
Log.e(TAG, "Invalid lexical model to register");
return false;
@ -770,7 +771,7 @@ public final class KMManager {
* Search the installed lexical models list and see if there's an
* associated model for a given language ID
* @param langId - String of the language ID
* @return HashMap<String, String> Keyboard information if it exists. Otherwise null
* @return HashMap<String, String> Model information if it exists. Otherwise null
*/
public static HashMap<String, String> getAssociatedLexicalModel(String langId) {
ArrayList<HashMap<String, String>> lexicalModelsList = getLexicalModelsList(appContext);

View file

@ -100,7 +100,7 @@ public final class KeyboardInfoActivity extends AppCompatActivity {
// Starting with Android N, you can't pass file:// to intents, so we use FileProvider
try {
Uri contentUri = FileProvider.getUriForFile(
context, getApplication().getPackageName() + ".fileProvider", customHelp);
context, "com.tavultesoft.kmea.fileProvider", customHelp);
i.setDataAndType(contentUri, "text/html");
} catch (Exception e) {
Log.e("KeyboardInfoActivity", "Failed to access " + customHelp.toString());

View file

@ -27,6 +27,7 @@ import android.widget.SimpleAdapter;
import android.widget.TextView;
import com.tavultesoft.kmea.util.FileUtils;
import com.tavultesoft.kmea.util.MapCompat;
import static com.tavultesoft.kmea.ConfirmDialogFragment.DialogType.DIALOG_TYPE_DELETE_KEYBOARD;
@ -41,6 +42,7 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
private final String titleKey = "title";
private final String subtitleKey = "subtitle";
private final String iconKey = "icon";
private final String isEnabledKey = "isEnabled";
@Override
public void onCreate(Bundle savedInstanceState) {
@ -68,9 +70,10 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
if (titleFont != null)
textView.setTypeface(titleFont, Typeface.BOLD);
boolean isCustomKeyboard = getIntent().getBooleanExtra(KMManager.KMKey_CustomKeyboard, false);
final boolean isCustomKeyboard = getIntent().getBooleanExtra(KMManager.KMKey_CustomKeyboard, false);
infoList = new ArrayList<HashMap<String, String>>();
// Display keyboard version title
String icon = "0";
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put(titleKey, getString(R.string.keyboard_version));
@ -78,15 +81,18 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
hashMap.put(iconKey, icon);
infoList.add(hashMap);
// Display keyboard help link
final String customHelpLink = getIntent().getStringExtra(KMManager.KMKey_CustomHelpLink);
if (!isCustomKeyboard || customHelpLink != null) {
if (isCustomKeyboard && customHelpLink == null) {
icon = "0";
} else {
icon = String.valueOf(R.drawable.ic_arrow_forward);
hashMap = new HashMap<String, String>();
hashMap.put(titleKey, getString(R.string.help_link));
hashMap.put(subtitleKey, "");
hashMap.put(iconKey, icon);
infoList.add(hashMap);
}
hashMap = new HashMap<String, String>();
hashMap.put(titleKey, getString(R.string.help_link));
hashMap.put(subtitleKey, "");
hashMap.put(iconKey, icon);
infoList.add(hashMap);
if (!packageID.equalsIgnoreCase(KMManager.KMDefault_UndefinedPackageID) ||
!kbID.equalsIgnoreCase(KMManager.KMDefault_KeyboardID)) {
@ -100,13 +106,34 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
String[] from = new String[]{titleKey, subtitleKey, iconKey};
int[] to = new int[]{R.id.text1, R.id.text2, R.id.image1};
ListAdapter adapter = new SimpleAdapter(context, infoList, R.layout.list_row_layout2, from, to);
ListAdapter adapter = new SimpleAdapter(context, infoList, R.layout.list_row_layout2, from, to) {
@Override
public boolean isEnabled(int position) {
HashMap<String, String> hashMap = (HashMap<String, String>) infoList.get(position);
String itemTitle = MapCompat.getOrDefault(hashMap, titleKey, "");
if (itemTitle.equals(getString(R.string.keyboard_version))) {
// No point in 'clicking' on version info.
return false;
// Visibly disables the help option when help isn't available.
} else if (itemTitle.equals(getString(R.string.help_link)) && isCustomKeyboard && customHelpLink == null) {
return false;
}
return super.isEnabled(position);
}
};
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 1) {
HashMap<String, String> hashMap = (HashMap<String, String>)parent.getItemAtPosition(position);
String itemTitle = MapCompat.getOrDefault(hashMap, titleKey, "");
// "Help" link clicked
if (itemTitle.equals(getString(R.string.help_link))) {
Intent i = new Intent(Intent.ACTION_VIEW);
if (customHelpLink != null) {
@ -116,7 +143,7 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
// Starting with Android N, you can't pass file:// to intents, so we use FileProvider
try {
Uri contentUri = FileProvider.getUriForFile(
context, getApplication().getPackageName() + ".fileProvider", customHelp);
context, "com.tavultesoft.kmea.fileProvider", customHelp);
i.setDataAndType(contentUri, "text/html");
} catch (Exception e) {
Log.e("KeyboardInfoActivity", "Failed to access " + customHelp.toString());
@ -131,7 +158,8 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
i.setData(Uri.parse(helpUrlStr));
startActivity(i);
}
} else if (position == 2) {
// "Uninstall Keyboard" clicked
} else if (itemTitle.equals(getString(R.string.uninstall_keyboard))) {
// Uninstall selected keyboard
String title = String.format("%s: %s", languageName, kbName);
String keyboardKey = String.format("%s_%s", languageID, kbID);
@ -140,11 +168,7 @@ public final class KeyboardSettingsActivity extends AppCompatActivity {
dialog.show(getFragmentManager(), "dialog");
}
}
});
}
@Override

View file

@ -47,6 +47,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
private String associatedLexicalModel = "";
private String lgCode;
private String lgName;
private String customHelpLink;
private SharedPreferences prefs;
private final static String TAG = "LanguageSettingsAct";
@ -119,6 +120,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
lgCode = bundle.getString(KMManager.KMKey_LanguageID);
lgName = bundle.getString(KMManager.KMKey_LanguageName);
customHelpLink = bundle.getString(KMManager.KMKey_CustomHelpLink);
// Necessary to properly insert a language name into the title. (Has a %s slot for it.)
String title = String.format(getString(R.string.title_language_settings), lgName);
@ -168,6 +170,7 @@ public final class LanguageSettingsActivity extends AppCompatActivity {
Bundle bundle = new Bundle();
bundle.putString(KMManager.KMKey_LanguageID, lgCode);
bundle.putString(KMManager.KMKey_LanguageName, lgName);
bundle.putString(KMManager.KMKey_CustomHelpLink, customHelpLink);
Intent i = new Intent(context, ModelPickerActivity.class);
i.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
i.putExtras(bundle);

View file

@ -107,6 +107,7 @@ public final class LanguagesSettingsActivity extends AppCompatActivity
if(associatedLexicalModel != null) {
args.putString(KMManager.KMKey_LexicalModelName, associatedLexicalModel.get(KMManager.KMKey_LexicalModelName));
args.putString(KMManager.KMKey_CustomHelpLink, associatedLexicalModel.get(KMManager.KMKey_CustomHelpLink));
}
Intent intent = new Intent(context, LanguageSettingsActivity.class);

View file

@ -31,6 +31,7 @@ import android.widget.TextView;
import android.widget.Toast;
import com.tavultesoft.kmea.util.FileUtils;
import com.tavultesoft.kmea.util.MapCompat;
import static com.tavultesoft.kmea.ConfirmDialogFragment.DialogType.DIALOG_TYPE_DELETE_MODEL;
@ -72,10 +73,9 @@ public final class ModelInfoActivity extends AppCompatActivity {
textView.setTypeface(titleFont, Typeface.BOLD);
final String modelVersion = getIntent().getStringExtra(KMManager.KMKey_LexicalModelVersion);
final String customModel = getIntent().getStringExtra(KMManager.KMKey_CustomModel);
infoList = new ArrayList<HashMap<String, String>>();
// Display model title
// Display model version title
final String noIcon = "0";
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put(titleKey, getString(R.string.model_version));
@ -85,17 +85,16 @@ public final class ModelInfoActivity extends AppCompatActivity {
// Display model help link
final String customHelpLink = getIntent().getStringExtra(KMManager.KMKey_CustomHelpLink);
String icon = String.valueOf(R.drawable.ic_arrow_forward);
hashMap = new HashMap<String, String>();
hashMap.put(titleKey, getString(R.string.help_link));
hashMap.put(subtitleKey, "");
if(customHelpLink != null) {
// For now, lexical model help only available when installed via custom packages
if(!customHelpLink.equals("")) {
hashMap.put(iconKey, icon);
} else {
hashMap.put(iconKey, noIcon);
}
infoList.add(hashMap);
// Display link to uninstall model
@ -111,11 +110,14 @@ public final class ModelInfoActivity extends AppCompatActivity {
ListAdapter adapter = new SimpleAdapter(context, infoList, R.layout.list_row_layout2, from, to) {
@Override
public boolean isEnabled(int position) {
if(position == 0) {
HashMap<String, String> hashMap = (HashMap<String, String>)infoList.get(position);
String itemTitle = MapCompat.getOrDefault(hashMap, titleKey, "");
if (itemTitle.equals(getString(R.string.model_version))) {
// No point in 'clicking' on version info.
return false;
// Visibly disables the help option when help isn't available.
} else if(position == 1 && customHelpLink == null) {
} else if (itemTitle.equals(getString(R.string.help_link)) && customHelpLink.equals("")) {
return false;
}
@ -127,18 +129,21 @@ public final class ModelInfoActivity extends AppCompatActivity {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position == 1) {
// Help link to model
HashMap<String, String> hashMap = (HashMap<String, String>)parent.getItemAtPosition(position);
String itemTitle = MapCompat.getOrDefault(hashMap, titleKey, "");
// "Help" link clicked
if (itemTitle.equals(getString(R.string.help_link))) {
Intent i = new Intent(Intent.ACTION_VIEW);
if (customHelpLink != null) {
if (!customHelpLink.equals("")) {
if (FileUtils.isWelcomeFile(customHelpLink)) {
File customHelp = new File(new File(customHelpLink).getAbsolutePath());
i.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
// Starting with Android N, you can't pass file:// to intents, so we use FileProvider
try {
Uri contentUri = FileProvider.getUriForFile(
context, getApplication().getPackageName() + ".fileProvider", customHelp);
context, "com.tavultesoft.kmea.fileProvider", customHelp);
i.setDataAndType(contentUri, "text/html");
} catch (Exception e) {
Log.e("ModelInfoActivity", "Failed to access " + customHelp.toString());
@ -151,8 +156,9 @@ public final class ModelInfoActivity extends AppCompatActivity {
} else {
// We should always have a help file packaged with models.
}
} else if (position == 2) {
// Confirmation to delete model
// "Uninstall Model" clicked
} else if (itemTitle.equals(getString(R.string.uninstall_model))) {
// Uninstall selected model
String lexicalModelKey = String.format("%s_%s_%s", packageID, languageID, modelID);
DialogFragment dialog = ConfirmDialogFragment.newInstance(
DIALOG_TYPE_DELETE_MODEL, modelName, getString(R.string.confirm_delete_model), lexicalModelKey);

View file

@ -46,6 +46,7 @@ public final class ModelPickerActivity extends AppCompatActivity {
private final static String TAG = "ModelPickerActivity";
private String languageID = "";
private String customHelpLink = "";
@Override
public void onCreate(Bundle savedInstanceState) {
@ -63,9 +64,11 @@ public final class ModelPickerActivity extends AppCompatActivity {
Bundle bundle = getIntent().getExtras();
String newLanguageID = bundle.getString(KMManager.KMKey_LanguageID);
String newCustomHelpLink = bundle.getString(KMManager.KMKey_CustomHelpLink);
// Sometimes we need to re-initialize the list of models that are displayed in the ListView
languageID = newLanguageID;
customHelpLink = newCustomHelpLink;
final String languageName = bundle.getString(KMManager.KMKey_LanguageName);
textView.setText(String.format(getString(R.string.model_picker_header), languageName));
@ -123,8 +126,7 @@ public final class ModelPickerActivity extends AppCompatActivity {
bundle.putString(KMManager.KMKey_LexicalModelName, modelName);
bundle.putString(KMManager.KMKey_LexicalModelVersion,
modelInfo.get(KMManager.KMKey_LexicalModelVersion));
bundle.putString(KMManager.KMKey_CustomModel,
MapCompat.getOrDefault(new HashMap<>(modelInfo), KMManager.KMKey_CustomModel, "N"));
bundle.putString(KMManager.KMKey_CustomHelpLink, customHelpLink);
Intent i = new Intent(context, ModelInfoActivity.class);
i.putExtras(bundle);
startActivityForResult(i, 1);

View file

@ -64,6 +64,8 @@ public class LexicalModel implements Serializable, LanguageResource {
return null;
}
String customHelpLink = map.get(KMManager.KMKey_CustomHelpLink);
bundle.putString(KMKeyboardDownloaderActivity.ARG_PKG_ID, getPackage());
bundle.putString(KMKeyboardDownloaderActivity.ARG_MODEL_ID, getResourceId());
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANG_ID, getLanguageCode());
@ -71,6 +73,7 @@ public class LexicalModel implements Serializable, LanguageResource {
bundle.putString(KMKeyboardDownloaderActivity.ARG_LANG_NAME, getLanguageName());
bundle.putBoolean(KMKeyboardDownloaderActivity.ARG_IS_CUSTOM, false);
bundle.putString(KMKeyboardDownloaderActivity.ARG_MODEL_URL, modelURL);
bundle.putString(KMKeyboardDownloaderActivity.ARG_MODEL_CUSTOM_HELP_LINK, customHelpLink);
return bundle;
}

View file

@ -80,6 +80,8 @@ public class LexicalModelPackageProcessor extends PackageProcessor {
File welcomeFile = new File(packageDir, "welcome.htm");
// Only storing relative instead of absolute paths as a convenience for unit tests.
models[i].put(KMManager.KMKey_CustomHelpLink, welcomeFile.getPath());
} else {
models[i].put(KMManager.KMKey_CustomHelpLink, "");
}
}
return models;

View file

@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<!-- path is relative to /data/data/com.tavultesoft.kmapro/files/ -->
<files-path name="cloud" path="../app_data/cloud/" />
<files-path name="models" path="../app_data/models/" />
<files-path name="packages" path="../app_data/packages/" />
</paths>

View file

@ -73,6 +73,7 @@ public class LexicalModelPackageProcessorTest {
en_custom.put(KMManager.KMKey_LexicalModelVersion, "1.0.0");
en_custom.put(KMManager.KMKey_LanguageID, "en");
en_custom.put(KMManager.KMKey_LanguageName, "English");
en_custom.put(KMManager.KMKey_CustomHelpLink, "");
Assert.assertEquals(en_custom, models[0]);

View file

@ -7,6 +7,9 @@
* New Feature:
* Allow user to "Add keyboard from local device" from Settings menu (#1992)
* Bug Fix:
* Fix keyboard and dictionary info pages (#2020)
## 2019-08-27 12.0.4080 beta
* Fix menu icon and text alignment (#1999)