1
0
mirror of https://git.savannah.gnu.org/git/emacs.git synced 2024-12-02 08:22:22 +00:00

Implement `fullscreen' on Android 4.0 and later

* doc/emacs/android.texi (Android Windowing): Document what new
frame parameters are now supported.
* java/org/gnu/emacs/EmacsActivity.java (EmacsActivity): New
field `isFullscreen'.
(detachWindow, attachWindow): Sync fullscreen state.
(onWindowFocusChanged): Add more logging.
(onResume): Restore previous fullscreen state.
(syncFullscreen): New function.
* java/org/gnu/emacs/EmacsWindow.java (EmacsWindow)
(setFullscreen): New function.
* src/android.c (struct android_emacs_window): Add new method.
(android_init_emacs_window): Look up new method.
(android_set_fullscreen): New function.
* src/androidgui.h:
* src/androidterm.c (android_fullscreen_hook): Implement
accordingly.
This commit is contained in:
Po Lu 2023-02-19 13:17:43 +08:00
parent c6809eb927
commit c8f49c9276
6 changed files with 193 additions and 15 deletions

View File

@ -355,8 +355,8 @@ tiled on the screen at any time.
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
@ -402,15 +402,15 @@ devices.
@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

View File

@ -26,12 +26,16 @@
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
@ -56,6 +60,9 @@ public class EmacsActivity extends Activity
/* 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> ();
@ -104,6 +111,8 @@ public class EmacsActivity extends Activity
public void
detachWindow ()
{
syncFullscreenWith (null);
if (window == null)
Log.w (TAG, "detachWindow called, but there is no window");
else
@ -131,6 +140,8 @@ public class EmacsActivity extends Activity
throw new IllegalStateException ("trying to attach window when one"
+ " already exists");
syncFullscreenWith (child);
/* Record and attach the view. */
window = child;
@ -230,6 +241,9 @@ public class EmacsActivity extends Activity
public void
onWindowFocusChanged (boolean isFocused)
{
Log.d (TAG, ("onWindowFocusChanged: "
+ (isFocused ? "YES" : "NO")));
if (isFocused && !focusedActivities.contains (this))
{
focusedActivities.add (this);
@ -257,6 +271,9 @@ public class EmacsActivity extends Activity
{
isPaused = false;
/* Update the window insets. */
syncFullscreenWith (window);
EmacsWindowAttachmentManager.MANAGER.noticeDeiconified (this);
super.onResume ();
}
@ -279,4 +296,88 @@ public class EmacsActivity extends Activity
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);
}
};

View File

@ -128,6 +128,9 @@ private class Coordinate
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)
@ -1179,4 +1182,27 @@ else if (EmacsWindow.this.isMapped)
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);
}
}
});
}
};

View File

@ -136,6 +136,7 @@ struct android_emacs_window
jmethodID swap_buffers;
jmethodID toggle_on_screen_keyboard;
jmethodID lookup_string;
jmethodID set_fullscreen;
};
/* The API level of the current device. */
@ -1920,6 +1921,7 @@ android_init_emacs_window (void)
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
}
@ -5475,6 +5477,36 @@ android_reset_ic (android_window window, enum android_ic_mode mode)
/* 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;
}
#else /* ANDROID_STUBIFY */
/* X emulation functions for Android. */

View File

@ -614,6 +614,7 @@ extern int android_wc_lookup_string (android_key_pressed_event *,
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

View File

@ -1792,12 +1792,30 @@ android_make_frame_visible_invisible (struct frame *f, bool visible)
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