emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

feature/android c8f49c9276d: Implement `fullscreen' on Android 4.0 and l


From: Po Lu
Subject: feature/android c8f49c9276d: Implement `fullscreen' on Android 4.0 and later
Date: Sun, 19 Feb 2023 00:35:44 -0500 (EST)

branch: feature/android
commit c8f49c9276d34741bfbe7752dd38391c0b8d782b
Author: Po Lu <luangruo@yahoo.com>
Commit: Po Lu <luangruo@yahoo.com>

    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.
---
 doc/emacs/android.texi                |  18 +++---
 java/org/gnu/emacs/EmacsActivity.java | 107 +++++++++++++++++++++++++++++++++-
 java/org/gnu/emacs/EmacsWindow.java   |  26 +++++++++
 src/android.c                         |  32 ++++++++++
 src/androidgui.h                      |   1 +
 src/androidterm.c                     |  24 +++++++-
 6 files changed, 193 insertions(+), 15 deletions(-)

diff --git a/doc/emacs/android.texi b/doc/emacs/android.texi
index 35f0ba55cf4..4e5402f5f40 100644
--- a/doc/emacs/android.texi
+++ b/doc/emacs/android.texi
@@ -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
diff --git a/java/org/gnu/emacs/EmacsActivity.java 
b/java/org/gnu/emacs/EmacsActivity.java
index 3156a144a0f..7e09e608984 100644
--- a/java/org/gnu/emacs/EmacsActivity.java
+++ b/java/org/gnu/emacs/EmacsActivity.java
@@ -26,12 +26,16 @@ import java.util.ArrayList;
 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);
+  }
 };
diff --git a/java/org/gnu/emacs/EmacsWindow.java 
b/java/org/gnu/emacs/EmacsWindow.java
index 0eca35cec61..90fc4c44198 100644
--- a/java/org/gnu/emacs/EmacsWindow.java
+++ b/java/org/gnu/emacs/EmacsWindow.java
@@ -128,6 +128,9 @@ public class EmacsWindow extends EmacsHandleObject
      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 @@ public class EmacsWindow extends EmacsHandleObject
 
     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);
+           }
+       }
+      });
+  }
 };
diff --git a/src/android.c b/src/android.c
index d21aaabc1ac..fc5e6d278ed 100644
--- a/src/android.c
+++ b/src/android.c
@@ -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.  */
diff --git a/src/androidgui.h b/src/androidgui.h
index 25dc6754fff..84419457a8a 100644
--- a/src/androidgui.h
+++ b/src/androidgui.h
@@ -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
 
diff --git a/src/androidterm.c b/src/androidterm.c
index 0fbee1e9867..62a8d5d12b3 100644
--- a/src/androidterm.c
+++ b/src/androidterm.c
@@ -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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]