From 2b19588c3c40390c362144ab365eaadfc81e4a65 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Tue, 3 Dec 2019 16:01:40 +0700 Subject: [PATCH 1/4] fix(android): Add a preference for ignoring update notifications This is done individually per keyboard or lexical model ID --- .../kmea/logic/ResourcesUpdateTool.java | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java index 8ac3d66b7a..54548a1764 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java @@ -63,6 +63,11 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl */ public static final String PREF_KEY_LAST_UPDATE_CHECK = "lastUpdateCheck"; + /** + * Months to ignore update notification + */ + public static final int MONTHS_TO_IGNORE_NOTIFICATION = 3; + private static final class OngoingUpdate { Integer notificationid; @@ -269,6 +274,31 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl addOpenUpdate(createKeyboardId(langid, kbid), null, theResourceBundle); } } + + /** + * Check shared preference to see if an update notification should be ignored. + * The window is MONTHS_TO_IGNORE_NOTIFICATION from the last time the notification was ignored. + * @param id keyboard or lexical model ID + * @return true if the notification should be ignored + */ + private boolean checkIfNotificationShouldBeIgnored(String id) { + // Check preference if notification is to be ignored + SharedPreferences prefs = currentContext.getSharedPreferences(currentContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + Long lastIgnoredTime = prefs.getLong(id, 0); + if (lastIgnoredTime > 0) { + Calendar now = Calendar.getInstance(); + Calendar ignoreUntilTime = Calendar.getInstance(); + ignoreUntilTime.setTime(new Date(lastIgnoredTime)); + ignoreUntilTime.add(Calendar.MONTH, MONTHS_TO_IGNORE_NOTIFICATION); + if (now.compareTo(ignoreUntilTime) > 0) { + return true; + } + } + + return false; + } + /** * send update notification. * @param theResourceBundle the bundle @@ -290,13 +320,23 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl String modelid = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_MODEL_ID); String modelName = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_MODEL_NAME); message = currentContext.getString(R.string.dictionary_update_message, langName, modelName); - addOpenUpdate(createLexicalModelId(langid,modelid),notification_id, theResourceBundle); + if (!checkIfNotificationShouldBeIgnored(modelid)) { + addOpenUpdate(createLexicalModelId(langid, modelid), notification_id, theResourceBundle); + } else { + // Update notification should be ignored + return; + } } else { String kbid = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_KB_ID); String kbName = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_KB_NAME); message = currentContext.getString(R.string.keyboard_update_message, langName, kbName); - addOpenUpdate(createKeyboardId(langid,kbid),notification_id, theResourceBundle); + if (!checkIfNotificationShouldBeIgnored(kbid)) { + addOpenUpdate(createKeyboardId(langid, kbid), notification_id, theResourceBundle); + } else { + // Update notification should be ignored + return; + } } From 9bf644ea5e4967793bddf0ddce92ce715d71fba4 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 4 Dec 2019 11:51:57 +0700 Subject: [PATCH 2/4] fix(android): Set preference when update is cancelled --- .../kmea/logic/ResourcesUpdateTool.java | 94 ++++++++++++++++--- 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java index 54548a1764..f6cb67a158 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java @@ -1,6 +1,5 @@ package com.tavultesoft.kmea.logic; - import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; @@ -13,6 +12,7 @@ import android.content.SharedPreferences; import android.os.Build; import android.os.Bundle; import android.os.Handler; +import android.util.Log; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; @@ -21,7 +21,6 @@ import androidx.core.app.NotificationCompat; import androidx.core.app.NotificationCompat.Builder; import androidx.core.app.NotificationManagerCompat; - import com.tavultesoft.kmea.KMKeyboardDownloaderActivity; import com.tavultesoft.kmea.KeyboardPickerActivity; import com.tavultesoft.kmea.KMManager; @@ -39,8 +38,12 @@ import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; +import org.json.JSONException; +import org.json.JSONObject; + public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownloadEventListener, CloudRepository.UpdateHandler{ + private static final String TAG = "ResourceUpdateTool"; /** * Force resource update. @@ -63,6 +66,11 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl */ public static final String PREF_KEY_LAST_UPDATE_CHECK = "lastUpdateCheck"; + /** + * Preference key for ignored notifications + */ + public static final String PREF_KEY_IGNORE_NOTIFICATIONS = "ignoredNotifications"; + /** * Months to ignore update notification */ @@ -281,24 +289,77 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl * @param id keyboard or lexical model ID * @return true if the notification should be ignored */ - private boolean checkIfNotificationShouldBeIgnored(String id) { - // Check preference if notification is to be ignored + private boolean shouldIgnoreNotification(String id) { SharedPreferences prefs = currentContext.getSharedPreferences(currentContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); - Long lastIgnoredTime = prefs.getLong(id, 0); - if (lastIgnoredTime > 0) { - Calendar now = Calendar.getInstance(); - Calendar ignoreUntilTime = Calendar.getInstance(); - ignoreUntilTime.setTime(new Date(lastIgnoredTime)); - ignoreUntilTime.add(Calendar.MONTH, MONTHS_TO_IGNORE_NOTIFICATION); - if (now.compareTo(ignoreUntilTime) > 0) { - return true; + String ignoredNotificationsStr = prefs.getString(PREF_KEY_IGNORE_NOTIFICATIONS, null); + + /* + * Preference is a JSON Object (as a string) + * { PREF_KEY_IGNORE_NOTIFICATIONS : + * { id1 : time1 ignored, + * id2 : time2 ignored + * } + * } + */ + JSONObject ignoredNotificationsObj; + if (ignoredNotificationsStr != null) { + try { + ignoredNotificationsObj = new JSONObject(ignoredNotificationsStr); + + Long lastIgnoredTime = ignoredNotificationsObj.optLong(id, 0); + if (lastIgnoredTime > 0) { + Calendar now = Calendar.getInstance(); + Calendar ignoreUntilTime = Calendar.getInstance(); + ignoreUntilTime.setTime(new Date(lastIgnoredTime)); + ignoreUntilTime.add(Calendar.MONTH, MONTHS_TO_IGNORE_NOTIFICATION); + Log.d(TAG,"now: " + now.getTime() + ", ignore til: " + ignoreUntilTime.getTime()); + if (now.compareTo(ignoreUntilTime) < 0) { + return true; + } + } + } catch (JSONException e) { + Log.e(TAG, "JSON Exception parsing ignoreNotifications preference"); } } return false; } + /** + * Update preference to ignore notifications for keyboard / lexical model ID + * @param id : keyboard or lexical model ID to ignore for MONTHS_TO_IGNORE_NOTIFICATION months + */ + private void setPrefKeyIgnoreNotifications(String id) { + SharedPreferences prefs = currentContext.getSharedPreferences(currentContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); + SharedPreferences.Editor editor = prefs.edit(); + String ignoredNotificationsStr = prefs.getString(PREF_KEY_IGNORE_NOTIFICATIONS, null); + + /* + * Preference is a JSON Object (stored as a string) + * { PREF_KEY_IGNORE_NOTIFICATIONS : + * { id1 : time1 ignored, + * id2 : time2 ignored + * } + * } + */ + JSONObject ignoredNotificationsObj; + try { + if (ignoredNotificationsStr == null) { + ignoredNotificationsObj = new JSONObject(); + } else { + ignoredNotificationsObj = new JSONObject(ignoredNotificationsStr); + } + + Calendar now = Calendar.getInstance(); + ignoredNotificationsObj.put(id, now.getTime().getTime()); + editor.putString(PREF_KEY_IGNORE_NOTIFICATIONS, ignoredNotificationsObj.toString()); + editor.commit(); + } catch (JSONException e) { + Log.e(TAG, "JSON Exception updating ignoreNotifications preference"); + } + } + /** * send update notification. * @param theResourceBundle the bundle @@ -320,10 +381,11 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl String modelid = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_MODEL_ID); String modelName = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_MODEL_NAME); message = currentContext.getString(R.string.dictionary_update_message, langName, modelName); - if (!checkIfNotificationShouldBeIgnored(modelid)) { + if (!shouldIgnoreNotification(modelid)) { addOpenUpdate(createLexicalModelId(langid, modelid), notification_id, theResourceBundle); } else { // Update notification should be ignored + notificationManager.cancel(notification_id); return; } } @@ -331,10 +393,11 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl String kbid = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_KB_ID); String kbName = theResourceBundle.getString(KMKeyboardDownloaderActivity.ARG_KB_NAME); message = currentContext.getString(R.string.keyboard_update_message, langName, kbName); - if (!checkIfNotificationShouldBeIgnored(kbid)) { + if (!shouldIgnoreNotification(kbid)) { addOpenUpdate(createKeyboardId(langid, kbid), notification_id, theResourceBundle); } else { // Update notification should be ignored + notificationManager.cancel(notification_id); return; } @@ -505,6 +568,7 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl public void cancelKeyboardUpdate(String aLangId, String aKbId) { + setPrefKeyIgnoreNotifications(aKbId); removeOpenUpdate(createKeyboardId(aLangId,aKbId)); if(openUpdates.isEmpty()) checkingUpdates = false; @@ -512,6 +576,8 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl public void cancelLexicalModelUpdate(String aLangId, String aModelId) { + NotificationManagerCompat notificationManager = NotificationManagerCompat.from(currentContext); + setPrefKeyIgnoreNotifications(aModelId); removeOpenUpdate(createLexicalModelId(aLangId,aModelId)); if(openUpdates.isEmpty()) checkingUpdates = false; From 4b894a02df47061414ff7c4a90567c2bae02eaf5 Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 4 Dec 2019 14:31:18 +0700 Subject: [PATCH 3/4] chore(android): remove unnecessary code --- .../java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java index f6cb67a158..503e102deb 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java @@ -313,7 +313,6 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl Calendar ignoreUntilTime = Calendar.getInstance(); ignoreUntilTime.setTime(new Date(lastIgnoredTime)); ignoreUntilTime.add(Calendar.MONTH, MONTHS_TO_IGNORE_NOTIFICATION); - Log.d(TAG,"now: " + now.getTime() + ", ignore til: " + ignoreUntilTime.getTime()); if (now.compareTo(ignoreUntilTime) < 0) { return true; } @@ -576,7 +575,6 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl public void cancelLexicalModelUpdate(String aLangId, String aModelId) { - NotificationManagerCompat notificationManager = NotificationManagerCompat.from(currentContext); setPrefKeyIgnoreNotifications(aModelId); removeOpenUpdate(createLexicalModelId(aLangId,aModelId)); if(openUpdates.isEmpty()) From 397f4f7d3a549b8d6f13928e31ec325497e1ce8a Mon Sep 17 00:00:00 2001 From: Darcy Wong Date: Wed, 4 Dec 2019 20:14:32 +0700 Subject: [PATCH 4/4] chore(android): add linewrap and update history.md --- .../java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java | 3 ++- android/history.md | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java index 503e102deb..5de4b018e5 100644 --- a/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java +++ b/android/KMEA/app/src/main/java/com/tavultesoft/kmea/logic/ResourcesUpdateTool.java @@ -330,7 +330,8 @@ public class ResourcesUpdateTool implements KeyboardEventHandler.OnKeyboardDownl * @param id : keyboard or lexical model ID to ignore for MONTHS_TO_IGNORE_NOTIFICATION months */ private void setPrefKeyIgnoreNotifications(String id) { - SharedPreferences prefs = currentContext.getSharedPreferences(currentContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); + SharedPreferences prefs = currentContext.getSharedPreferences( + currentContext.getString(R.string.kma_prefs_name), Context.MODE_PRIVATE); SharedPreferences.Editor editor = prefs.edit(); String ignoredNotificationsStr = prefs.getString(PREF_KEY_IGNORE_NOTIFICATIONS, null); diff --git a/android/history.md b/android/history.md index 8df1a65d2f..b220a2e4c9 100644 --- a/android/history.md +++ b/android/history.md @@ -9,10 +9,12 @@ * Check for keyboard updates during keyman startup (#2335) * Show available keyboard updates as android system notifications (#2335) * Add update indicator icon to inform user about updates and install updates in keyman app (#2335) + * Add preference so update notifications can be ignored 3 months (#2412) * Changes: * Update target Android SDK version to 29 (#2279) * Add simple UI tests for keyboard picker and keyboard info screens (#2326) * Add example dictionary to KMSample1 project (#2369) + * Prevent lower-cased API returns from causing mismatches (#2404) * Bug fix: * Sanitize the app version to `#.#.#` for the API cloud query (#2319) * Add linting to Debug builds and resolve lint errors (#2305)