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.
This commit is contained in:
parent
4cee95815b
commit
755665d95a
2 changed files with 66 additions and 1 deletions
|
@ -858,6 +858,18 @@ When the user closes the window created during application startup,
|
|||
and the window was not previously closed by the system in order to
|
||||
save resources, Emacs deletes any frame displayed within that window.
|
||||
|
||||
However, on Android 7.0 and later, such frames are not deleted if the
|
||||
window is closed four or more hours after the window moves into the
|
||||
background, as the system automatically removes open windows once a
|
||||
certain period of inactivity elapses when the number of windows retained
|
||||
by the window manager surpasses a specific threshold, and window
|
||||
deletion by this mechanism is indistinguishable from window deletion by
|
||||
the user. Emacs begins to ignore window deletion after two hours less
|
||||
than the default value of this threshold both to err on the side of
|
||||
caution, in case the system's record of inactivity and Emacs's differ,
|
||||
and for the reason that this threshold is open to customization by OS
|
||||
distributors.
|
||||
|
||||
@item
|
||||
When the user or the system closes any window created by Emacs on
|
||||
behalf of a specific frame, Emacs deletes the frame displayed within
|
||||
|
|
|
@ -20,9 +20,12 @@
|
|||
package org.gnu.emacs;
|
||||
|
||||
import java.lang.IllegalStateException;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
|
@ -31,6 +34,7 @@
|
|||
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
|
@ -78,6 +82,9 @@ public class EmacsActivity extends Activity
|
|||
/* The last context menu to be closed. */
|
||||
private static Menu lastClosedMenu;
|
||||
|
||||
/* The time of the most recent call to onStop. */
|
||||
private static long timeOfLastInteraction;
|
||||
|
||||
static
|
||||
{
|
||||
focusedActivities = new ArrayList<EmacsActivity> ();
|
||||
|
@ -271,6 +278,50 @@ children and RESETWHENCHILDLESS is set (implying it is a
|
|||
syncFullscreenWith (window);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onStop ()
|
||||
{
|
||||
timeOfLastInteraction = SystemClock.elapsedRealtime ();
|
||||
|
||||
super.onStop ();
|
||||
}
|
||||
|
||||
/* Return whether the task is being finished in response to explicit
|
||||
user action. That is to say, Activity.isFinished, but as
|
||||
documented. */
|
||||
|
||||
public final boolean
|
||||
isReallyFinishing ()
|
||||
{
|
||||
long atime, dtime;
|
||||
int hours;
|
||||
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.NOUGAT)
|
||||
return isFinishing ();
|
||||
|
||||
/* When the number of tasks retained in the recents list exceeds a
|
||||
threshold, Android 7 and later so destroy activities in trimming
|
||||
them from recents on the expiry of a timeout that isFinishing
|
||||
returns true, in direct contradiction to the documentation. This
|
||||
timeout is generally 6 hours, but admits of customization by
|
||||
individual system distributors, so to err on the side of the
|
||||
caution, the timeout Emacs applies is a more conservative figure
|
||||
of 4 hours. */
|
||||
|
||||
if (timeOfLastInteraction == 0)
|
||||
return isFinishing ();
|
||||
|
||||
atime = timeOfLastInteraction;
|
||||
|
||||
/* Compare atime with the current system time. */
|
||||
dtime = SystemClock.elapsedRealtime () - atime;
|
||||
if (dtime + 1000000 < TimeUnit.HOURS.toMillis (4))
|
||||
return isFinishing ();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void
|
||||
onDestroy ()
|
||||
|
@ -283,7 +334,8 @@ children and RESETWHENCHILDLESS is set (implying it is a
|
|||
/* The activity will die shortly hereafter. If there is a window
|
||||
attached, close it now. */
|
||||
isMultitask = this instanceof EmacsMultitaskActivity;
|
||||
manager.removeWindowConsumer (this, isMultitask || isFinishing ());
|
||||
manager.removeWindowConsumer (this, (isMultitask
|
||||
|| isReallyFinishing ()));
|
||||
focusedActivities.remove (this);
|
||||
invalidateFocus (2);
|
||||
|
||||
|
@ -340,6 +392,7 @@ children and RESETWHENCHILDLESS is set (implying it is a
|
|||
onResume ()
|
||||
{
|
||||
isPaused = false;
|
||||
timeOfLastInteraction = 0;
|
||||
|
||||
EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this);
|
||||
super.onResume ();
|
||||
|
|
Loading…
Add table
Reference in a new issue