1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

Android: Improve screen safe-area reporting

The goal of this change is to ensure that the safeAreaInsets and
keyboardInsets members of Display correctly take the current system UI
and screen cutouts into account.

This change also enables rendering behind the status bar and navigation
bar for JUCE applications. This is in line with the new defaults in
Android 15, where building against the Android SDK 35 will automatically
enable "edge-to-edge" drawing. Enabling this behaviour on older
platforms too provides a more consistent experience.
This commit is contained in:
reuk 2025-05-22 16:30:39 +01:00
parent cfc006aaf9
commit f904fd356a
No known key found for this signature in database
5 changed files with 1359 additions and 1181 deletions

View file

@ -230,7 +230,7 @@ static jobject makeAndroidRect (Rectangle<int> r)
r.getBottom());
}
static jobject makeAndroidPoint (Point<int> p)
static inline jobject makeAndroidPoint (Point<int> p)
{
return getEnv()->NewObject (AndroidPoint,
AndroidPoint.create,

View file

@ -34,6 +34,10 @@
package com.rmsl.juce;
import static android.view.WindowInsetsController.BEHAVIOR_DEFAULT;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_BARS_BY_SWIPE;
import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
@ -44,31 +48,33 @@ import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Build;
import android.text.Selection;
import android.text.SpanWatcher;
import android.text.Spannable;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.Pair;
import android.os.Bundle;
import android.text.Editable;
import android.text.InputType;
import android.text.Selection;
import android.text.SpanWatcher;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.Spanned;
import android.text.TextWatcher;
import android.util.Pair;
import android.view.Choreographer;
import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeProvider;
import android.view.inputmethod.BaseInputConnection;
import android.view.inputmethod.EditorInfo;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
@ -80,7 +86,7 @@ public final class ComponentPeerView extends ViewGroup
{
super (context);
if (Application.class.isInstance (context))
if (context instanceof Application)
{
((Application) context).registerActivityLifecycleCallbacks (this);
}
@ -796,35 +802,53 @@ public final class ComponentPeerView extends ViewGroup
{
}
public void setSystemUiVisibilityCompat (int visibility)
public void setSystemUiVisibilityCompat (Window window, boolean visible)
{
Method systemUIVisibilityMethod = null;
try
if (30 <= Build.VERSION.SDK_INT)
{
systemUIVisibilityMethod = this.getClass().getMethod ("setSystemUiVisibility", int.class);
}
catch (SecurityException e)
{
return;
}
catch (NoSuchMethodException e)
{
return;
}
if (systemUIVisibilityMethod == null) return;
WindowInsetsController controller = getWindowInsetsController();
try
{
systemUIVisibilityMethod.invoke (this, visibility);
if (controller != null)
{
if (visible)
{
controller.show (WindowInsets.Type.systemBars());
controller.setSystemBarsBehavior (31 <= Build.VERSION.SDK_INT ? BEHAVIOR_DEFAULT
: BEHAVIOR_SHOW_BARS_BY_SWIPE);
}
else
{
controller.hide (WindowInsets.Type.systemBars());
controller.setSystemBarsBehavior (BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
}
return;
}
}
catch (java.lang.IllegalArgumentException e)
{
}
catch (java.lang.IllegalAccessException e)
{
}
catch (java.lang.reflect.InvocationTargetException e)
if (window == null)
return;
// Displays::findDisplays queries the DecorView to determine the
// most recently-requested visibility state of the system UI.
// As we're creating new top-level views via WindowManager,
// updating only the DecorView isn't sufficient to hide the global
// system UI; we also need to update the view that was added to
// the WindowManager.
ArrayList<View> views = new ArrayList<>();
views.add (window.getDecorView());
views.add (this);
for (View view : views)
{
final int prevFlags = view.getSystemUiVisibility();
final int fullScreenFlags = SYSTEM_UI_FLAG_HIDE_NAVIGATION
| SYSTEM_UI_FLAG_FULLSCREEN
| SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
final int newFlags = visible ? (prevFlags & ~fullScreenFlags)
: (prevFlags | fullScreenFlags);
view.setSystemUiVisibility (newFlags);
}
}

View file

@ -34,21 +34,54 @@
package com.rmsl.juce;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.content.Intent;
import android.view.View;
//==============================================================================
public class JuceActivity extends Activity
{
//==============================================================================
private native void appNewIntent (Intent intent);
private native void appOnResume();
private void initEdgeToEdge()
{
if (Build.VERSION.SDK_INT < 35)
{
View decorView = getWindow().getDecorView();
final int flags = Build.VERSION.SDK_INT < 30
? ( SYSTEM_UI_FLAG_LAYOUT_STABLE
| SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
| SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN)
: SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility (decorView.getSystemUiVisibility() | flags);
}
if (30 <= Build.VERSION.SDK_INT)
getWindow().setDecorFitsSystemWindows (false);
}
@Override
protected void onCreate (Bundle savedInstanceState)
{
initEdgeToEdge();
super.onCreate (savedInstanceState);
}
@Override
protected void onNewIntent (Intent intent)
{
super.onNewIntent(intent);
setIntent(intent);
super.onNewIntent (intent);
setIntent (intent);
appNewIntent (intent);
}
@ -57,7 +90,6 @@ public class JuceActivity extends Activity
protected void onResume()
{
super.onResume();
appOnResume();
}
}

File diff suppressed because it is too large Load diff