diff options
| author | Po Lu | 2024-03-28 19:56:31 +0800 |
|---|---|---|
| committer | Po Lu | 2024-03-29 08:26:48 +0800 |
| commit | 755665d95adbba07335f400f1090e53b66c41ff5 (patch) | |
| tree | 03dbc80da010992a04e52f7119338e28ba9bed36 /java | |
| parent | 4cee95815b9d7d56f6f77abb1cc17e346c038685 (diff) | |
| download | emacs-755665d95adbba07335f400f1090e53b66c41ff5.tar.gz emacs-755665d95adbba07335f400f1090e53b66c41ff5.zip | |
Prevent Android OS task trimming from deleting Emacs frames
* doc/emacs/android.texi (Android Windowing): Document proviso
on Android 7.0 and later.
* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity)
<timeOfLastInteraction>: New field.
(onStop, onResume): Set and clear timeOfLastInteraction.
(isReallyFinishing): New function.
(onDestroy): Don't delete frame even in the event isFinishing
returns true if more than 4 hours have elapsed since the
activity last moved into the background.
Diffstat (limited to 'java')
| -rw-r--r-- | java/org/gnu/emacs/EmacsActivity.java | 55 |
1 files changed, 54 insertions, 1 deletions
diff --git a/java/org/gnu/emacs/EmacsActivity.java b/java/org/gnu/emacs/EmacsActivity.java index 6ab6a709bef..f5b05a9c184 100644 --- a/java/org/gnu/emacs/EmacsActivity.java +++ b/java/org/gnu/emacs/EmacsActivity.java | |||
| @@ -20,9 +20,12 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */ | |||
| 20 | package org.gnu.emacs; | 20 | package org.gnu.emacs; |
| 21 | 21 | ||
| 22 | import java.lang.IllegalStateException; | 22 | import java.lang.IllegalStateException; |
| 23 | |||
| 23 | import java.util.List; | 24 | import java.util.List; |
| 24 | import java.util.ArrayList; | 25 | import java.util.ArrayList; |
| 25 | 26 | ||
| 27 | import java.util.concurrent.TimeUnit; | ||
| 28 | |||
| 26 | import android.app.Activity; | 29 | import android.app.Activity; |
| 27 | 30 | ||
| 28 | import android.content.ContentResolver; | 31 | import android.content.ContentResolver; |
| @@ -31,6 +34,7 @@ import android.content.Intent; | |||
| 31 | 34 | ||
| 32 | import android.os.Build; | 35 | import android.os.Build; |
| 33 | import android.os.Bundle; | 36 | import android.os.Bundle; |
| 37 | import android.os.SystemClock; | ||
| 34 | 38 | ||
| 35 | import android.util.Log; | 39 | import android.util.Log; |
| 36 | 40 | ||
| @@ -78,6 +82,9 @@ public class EmacsActivity extends Activity | |||
| 78 | /* The last context menu to be closed. */ | 82 | /* The last context menu to be closed. */ |
| 79 | private static Menu lastClosedMenu; | 83 | private static Menu lastClosedMenu; |
| 80 | 84 | ||
| 85 | /* The time of the most recent call to onStop. */ | ||
| 86 | private static long timeOfLastInteraction; | ||
| 87 | |||
| 81 | static | 88 | static |
| 82 | { | 89 | { |
| 83 | focusedActivities = new ArrayList<EmacsActivity> (); | 90 | focusedActivities = new ArrayList<EmacsActivity> (); |
| @@ -273,6 +280,50 @@ public class EmacsActivity extends Activity | |||
| 273 | 280 | ||
| 274 | @Override | 281 | @Override |
| 275 | public final void | 282 | public final void |
| 283 | onStop () | ||
| 284 | { | ||
| 285 | timeOfLastInteraction = SystemClock.elapsedRealtime (); | ||
| 286 | |||
| 287 | super.onStop (); | ||
| 288 | } | ||
| 289 | |||
| 290 | /* Return whether the task is being finished in response to explicit | ||
| 291 | user action. That is to say, Activity.isFinished, but as | ||
| 292 | documented. */ | ||
| 293 | |||
| 294 | public final boolean | ||
| 295 | isReallyFinishing () | ||
| 296 | { | ||
| 297 | long atime, dtime; | ||
| 298 | int hours; | ||
| 299 | |||
| 300 | if (Build.VERSION.SDK_INT < Build.VERSION_CODES.NOUGAT) | ||
| 301 | return isFinishing (); | ||
| 302 | |||
| 303 | /* When the number of tasks retained in the recents list exceeds a | ||
| 304 | threshold, Android 7 and later so destroy activities in trimming | ||
| 305 | them from recents on the expiry of a timeout that isFinishing | ||
| 306 | returns true, in direct contradiction to the documentation. This | ||
| 307 | timeout is generally 6 hours, but admits of customization by | ||
| 308 | individual system distributors, so to err on the side of the | ||
| 309 | caution, the timeout Emacs applies is a more conservative figure | ||
| 310 | of 4 hours. */ | ||
| 311 | |||
| 312 | if (timeOfLastInteraction == 0) | ||
| 313 | return isFinishing (); | ||
| 314 | |||
| 315 | atime = timeOfLastInteraction; | ||
| 316 | |||
| 317 | /* Compare atime with the current system time. */ | ||
| 318 | dtime = SystemClock.elapsedRealtime () - atime; | ||
| 319 | if (dtime + 1000000 < TimeUnit.HOURS.toMillis (4)) | ||
| 320 | return isFinishing (); | ||
| 321 | |||
| 322 | return false; | ||
| 323 | } | ||
| 324 | |||
| 325 | @Override | ||
| 326 | public final void | ||
| 276 | onDestroy () | 327 | onDestroy () |
| 277 | { | 328 | { |
| 278 | EmacsWindowAttachmentManager manager; | 329 | EmacsWindowAttachmentManager manager; |
| @@ -283,7 +334,8 @@ public class EmacsActivity extends Activity | |||
| 283 | /* The activity will die shortly hereafter. If there is a window | 334 | /* The activity will die shortly hereafter. If there is a window |
| 284 | attached, close it now. */ | 335 | attached, close it now. */ |
| 285 | isMultitask = this instanceof EmacsMultitaskActivity; | 336 | isMultitask = this instanceof EmacsMultitaskActivity; |
| 286 | manager.removeWindowConsumer (this, isMultitask || isFinishing ()); | 337 | manager.removeWindowConsumer (this, (isMultitask |
| 338 | || isReallyFinishing ())); | ||
| 287 | focusedActivities.remove (this); | 339 | focusedActivities.remove (this); |
| 288 | invalidateFocus (2); | 340 | invalidateFocus (2); |
| 289 | 341 | ||
| @@ -340,6 +392,7 @@ public class EmacsActivity extends Activity | |||
| 340 | onResume () | 392 | onResume () |
| 341 | { | 393 | { |
| 342 | isPaused = false; | 394 | isPaused = false; |
| 395 | timeOfLastInteraction = 0; | ||
| 343 | 396 | ||
| 344 | EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this); | 397 | EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this); |
| 345 | super.onResume (); | 398 | super.onResume (); |