are created. Instead, the system may choose to terminate windows that
are not on screen in order to save memory, with the assumption that
the program will save its contents to disk and restore them later,
-when the user asks to open it again. As this is obvious not possible
-with Emacs, Emacs separates a frame from a system window.
+when the user asks to open it again. As this is obviously not
+possible with Emacs, Emacs separates a frame from a system window.
Each system window created (including the initial window created
during Emacs startup) is appended to a list of windows that do not
@item
The @code{alpha}, @code{alpha-background}, @code{z-group},
-@code{override-redirect}, @code{mouse-color}, @code{cursor-color},
-@code{cursor-type}, @code{title}, @code{wait-for-wm}, @code{sticky},
-@code{undecorated} and @code{tool-bar-position} frame parameters
-(@pxref{Frame Parameters,,, elisp, the Emacs Lisp Reference Manual})
-are unsupported.
+@code{override-redirect}, @code{mouse-color}, @code{title},
+@code{wait-for-wm}, @code{sticky}, @code{undecorated} and
+@code{tool-bar-position} frame parameters (@pxref{Frame Parameters,,,
+elisp, the Emacs Lisp Reference Manual}) are unsupported.
@item
-The @code{fullscreen} frame parameter is always @code{maximized} for
-top-level frames.
+On Android 4.0 and earlier, the @code{fullscreen} frame parameter is
+always @code{maximized} for top-level frames; on later versions of
+Android, it can also be @code{fullscreen}.
@end itemize
@cindex selections, android
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
-import android.os.Bundle;
import android.os.Build;
+import android.os.Bundle;
import android.util.Log;
-import android.widget.FrameLayout;
-import android.widget.FrameLayout.LayoutParams;
import android.view.Menu;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowInsets;
+import android.view.WindowInsetsController;
+import android.widget.FrameLayout.LayoutParams;
+import android.widget.FrameLayout;
public class EmacsActivity extends Activity
implements EmacsWindowAttachmentManager.WindowConsumer
/* Whether or not this activity is paused. */
private boolean isPaused;
+ /* Whether or not this activity is fullscreen. */
+ private boolean isFullscreen;
+
static
{
focusedActivities = new ArrayList<EmacsActivity> ();
public void
detachWindow ()
{
+ syncFullscreenWith (null);
+
if (window == null)
Log.w (TAG, "detachWindow called, but there is no window");
else
throw new IllegalStateException ("trying to attach window when one"
+ " already exists");
+ syncFullscreenWith (child);
+
/* Record and attach the view. */
window = child;
public void
onWindowFocusChanged (boolean isFocused)
{
+ Log.d (TAG, ("onWindowFocusChanged: "
+ + (isFocused ? "YES" : "NO")));
+
if (isFocused && !focusedActivities.contains (this))
{
focusedActivities.add (this);
{
isPaused = false;
+ /* Update the window insets. */
+ syncFullscreenWith (window);
+
EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this);
super.onResume ();
}
super.onContextMenuClosed (menu);
}
+
+ @SuppressWarnings ("deprecation")
+ public void
+ syncFullscreenWith (EmacsWindow emacsWindow)
+ {
+ WindowInsetsController controller;
+ Window window;
+ int behavior, flags;
+ View view;
+
+ if (emacsWindow != null)
+ isFullscreen = emacsWindow.fullscreen;
+ else
+ isFullscreen = false;
+
+ /* On Android 11 or later, use the window insets controller to
+ control whether or not the view is fullscreen. */
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
+ {
+ window = getWindow ();
+
+ /* If there is no attached window, return immediately. */
+ if (window == null)
+ return;
+
+ behavior = WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+ controller = window.getInsetsController ();
+ controller.setSystemBarsBehavior (behavior);
+
+ if (isFullscreen)
+ controller.hide (WindowInsets.Type.statusBars ()
+ | WindowInsets.Type.navigationBars ());
+ else
+ controller.show (WindowInsets.Type.statusBars ()
+ | WindowInsets.Type.navigationBars ());
+
+ return;
+ }
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
+ {
+ /* On Android 4.1 or later, use `setSystemUiVisibility'. */
+
+ window = getWindow ();
+
+ if (window == null)
+ return;
+
+ view = window.getDecorView ();
+
+ if (isFullscreen)
+ {
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT)
+ /* This flag means that Emacs will be full screen, but
+ the system will cancel the full screen state upon
+ switching to another program. */
+ view.setSystemUiVisibility (View.SYSTEM_UI_FLAG_FULLSCREEN);
+ else
+ {
+ /* These flags means that Emacs will be full screen as
+ long as the state flag is set. */
+ flags = 0;
+ flags |= View.SYSTEM_UI_FLAG_FULLSCREEN;
+ flags |= View.SYSTEM_UI_FLAG_HIDE_NAVIGATION;
+ flags |= View.SYSTEM_UI_FLAG_IMMERSIVE;
+ flags |= View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
+ view.setSystemUiVisibility (flags);
+ }
+ }
+ else
+ view.setSystemUiVisibility (View.SYSTEM_UI_FLAG_VISIBLE);
+ }
+ }
+
+ @Override
+ public void
+ onAttachedToWindow ()
+ {
+ super.onAttachedToWindow ();
+
+ /* Update the window insets. */
+ syncFullscreenWith (window);
+ }
};
events. */
public LinkedHashMap<Integer, String> eventStrings;
+ /* Whether or not this window is fullscreen. */
+ public boolean fullscreen;
+
public
EmacsWindow (short handle, final EmacsWindow parent, int x, int y,
int width, int height, boolean overrideRedirect)
return any;
}
+
+ public void
+ setFullscreen (final boolean isFullscreen)
+ {
+ EmacsService.SERVICE.runOnUiThread (new Runnable () {
+ @Override
+ public void
+ run ()
+ {
+ EmacsActivity activity;
+ Object tem;
+
+ fullscreen = isFullscreen;
+ tem = getAttachedConsumer ();
+
+ if (tem != null)
+ {
+ activity = (EmacsActivity) getAttachedConsumer ();
+ activity.syncFullscreenWith (EmacsWindow.this);
+ }
+ }
+ });
+ }
};
jmethodID swap_buffers;
jmethodID toggle_on_screen_keyboard;
jmethodID lookup_string;
+ jmethodID set_fullscreen;
};
/* The API level of the current device. */
FIND_METHOD (toggle_on_screen_keyboard,
"toggleOnScreenKeyboard", "(Z)V");
FIND_METHOD (lookup_string, "lookupString", "(I)Ljava/lang/String;");
+ FIND_METHOD (set_fullscreen, "setFullscreen", "(Z)V");
#undef FIND_METHOD
}
\f
+/* Window decoration management functions. */
+
+/* Make the specified WINDOW fullscreen, i.e. obscure all of the
+ system navigation and status bars. If not FULLSCREEN, make it
+ maximized instead.
+
+ Value is 1 if the system does not support this, else 0. */
+
+int
+android_set_fullscreen (android_window window, bool fullscreen)
+{
+ jobject object;
+
+ /* Android 4.0 and earlier don't support fullscreen windows. */
+
+ if (android_api_level < 16)
+ return 1;
+
+ object = android_resolve_handle (window, ANDROID_HANDLE_WINDOW);
+
+ (*android_java_env)->CallVoidMethod (android_java_env,
+ object,
+ window_class.set_fullscreen,
+ (jboolean) fullscreen);
+ android_exception_check ();
+ return 0;
+}
+
+\f
+
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */
extern void android_update_ic (android_window, ptrdiff_t, ptrdiff_t,
ptrdiff_t, ptrdiff_t);
extern void android_reset_ic (android_window, enum android_ic_mode);
+extern int android_set_fullscreen (android_window, bool);
#endif
static void
android_fullscreen_hook (struct frame *f)
{
- /* Explicitly setting fullscreen is not supported on Android. */
+ Lisp_Object wanted;
if (!FRAME_PARENT_FRAME (f))
- store_frame_param (f, Qfullscreen, Qmaximized);
+ {
+ /* Explicitly setting fullscreen is not supported on older
+ Android versions. */
+
+ wanted = (f->want_fullscreen == FULLSCREEN_BOTH
+ ? Qfullscreen : Qmaximized);
+
+ if (android_set_fullscreen (FRAME_ANDROID_WINDOW (f),
+ EQ (wanted, Qfullscreen)))
+ store_frame_param (f, Qfullscreen, Qmaximized);
+ else
+ store_frame_param (f, Qfullscreen, wanted);
+ }
else
- store_frame_param (f, Qfullscreen, Qnil);
+ {
+ store_frame_param (f, Qfullscreen, Qnil);
+
+ /* If this is a child frame, don't keep it fullscreen
+ anymore. */
+ android_set_fullscreen (FRAME_ANDROID_WINDOW (f), false);
+ }
}
void