diff --git a/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java b/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java index 9fea7a81..47e9be8f 100644 --- a/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java +++ b/app/src/main/java/io/github/sspanak/tt9/ime/TraditionalT9.java @@ -28,6 +28,7 @@ public class TraditionalT9 extends MainViewHandler { @NonNull private final Handler backgroundTasks = new Handler(Looper.getMainLooper()); @NonNull private final Handler zombieDetector = new Handler(Looper.getMainLooper()); + @NonNull private final Handler heartbeatDetector = new Handler(Looper.getMainLooper()); private boolean isDead = false; private int zombieChecks = 0; @@ -131,12 +132,17 @@ public class TraditionalT9 extends MainViewHandler { @Override protected boolean onStart(EditorInfo field) { - AppHacks.onStart(settings, field); - if (zombieChecks == 0 && !SystemSettings.isTT9Selected(this)) { - startZombieCheck(); + if (SystemSettings.isTT9Selected(this)) { + startHeartbeatCheck(); + } else { + if (zombieChecks == 0) { + startZombieCheck(); + } return false; } + AppHacks.onStart(settings, field); + if (isDead || !super.onStart(field)) { setStatusIcon(mInputMode, mLanguage); return false; @@ -188,6 +194,8 @@ public class TraditionalT9 extends MainViewHandler { if (zombieChecks == 0) { startZombieCheck(); } + + stopHeartbeatCheck(); } @@ -207,10 +215,31 @@ public class TraditionalT9 extends MainViewHandler { /** - * On Android 11+ the IME is sometimes not killed when the user switches to a different one. - * Here we attempt to detect if we are disabled, then hide and kill ourselves. + * On Android 11+ onStop() and onDestroy() are sometimes not called when the user switches to a + * different IME. Here we attempt to detect if we are disabled, then hide and kill ourselves. */ - protected void startZombieCheck() { + private void startHeartbeatCheck() { + if (!SystemSettings.isTT9Selected(this)) { + onZombie(); + } else if (!isDead && !InputModeKind.isPassthrough(mInputMode)) { + heartbeatDetector.postDelayed(this::startHeartbeatCheck, SettingsStore.ZOMBIE_HEARTBEAT_INTERVAL); + Logger.v(LOG_TAG, "===> Heart is beating"); + } + } + + + private void stopHeartbeatCheck() { + if (!DeviceInfo.AT_LEAST_ANDROID_10 || heartbeatDetector.hasCallbacks(this::startHeartbeatCheck)) { + heartbeatDetector.removeCallbacksAndMessages(null); + Logger.d(LOG_TAG, "===> Heartbeat check stopped"); + } + } + + + /** + * Similar to the heartbeat check, but detects if we are on when invisible or after re-init. + */ + private void startZombieCheck() { if (zombieChecks > 0 && !SystemSettings.isTT9Selected(this)) { zombieChecks = 0; onZombie(); @@ -226,7 +255,7 @@ public class TraditionalT9 extends MainViewHandler { } - protected void onZombie() { + private void onZombie() { if (isDead) { Logger.w(LOG_TAG, "===> Already dead. Cannot kill self."); return; @@ -241,13 +270,12 @@ public class TraditionalT9 extends MainViewHandler { protected void cleanUp() { + stopHeartbeatCheck(); + zombieDetector.removeCallbacksAndMessages(null); + zombieChecks = SettingsStore.ZOMBIE_CHECK_MAX; + backgroundTasks.removeCallbacksAndMessages(null); super.cleanUp(); setInputField(null); - backgroundTasks.removeCallbacksAndMessages(null); - zombieChecks = SettingsStore.ZOMBIE_CHECK_MAX; - zombieDetector.removeCallbacksAndMessages(null); - LanguageCollection.destroy(); - DataStore.destroy(); Logger.d(LOG_TAG, "===> Final cleanup completed"); } diff --git a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java index bda06235..c6220f80 100644 --- a/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java +++ b/app/src/main/java/io/github/sspanak/tt9/preferences/settings/SettingsStore.java @@ -43,8 +43,9 @@ public class SettingsStore extends SettingsHotkeys { public final static int WORD_FREQUENCY_NORMALIZATION_DIVIDER = 100; // normalized frequency = WORD_FREQUENCY_MAX / WORD_FREQUENCY_NORMALIZATION_DIVIDER public final static int WORD_PAIR_MAX = 1000; public final static int WORD_PAIR_MAX_WORD_LENGTH = 6; - public final static int ZOMBIE_CHECK_INTERVAL = 1500; // ms + public final static int ZOMBIE_CHECK_INTERVAL = 5000; // ms public final static int ZOMBIE_CHECK_MAX = 2; + public final static int ZOMBIE_HEARTBEAT_INTERVAL = 2000; // ms /************* hacks *************/ public final static int PREFERENCES_CLICK_DEBOUNCE_TIME = 250; // ms