Android: Rework UI insets handling (#21007)

* During game load, place the loading screen where the game will appear

* Android: Merge NativeActivity into PpssppActivity

* Rework window insets handling on Android

* Main screen: Display the path on its own line in portrait mode

* Make the "Fullscreen" setting on Android separate between portrait and landscape
This commit is contained in:
Henrik Rydgård
2025-11-16 10:43:58 +01:00
committed by GitHub
parent de3365e647
commit defd21cc90
16 changed files with 1776 additions and 1845 deletions
+1 -1
View File
@@ -900,7 +900,7 @@ public:
virtual bool Toggled() const;
// we don't allow these for checkboxes.
virtual void SetAutoResult(DialogResult result) {}
void SetAutoResult(DialogResult result) override {}
protected:
void ClickInternal() override;
+2 -1
View File
@@ -645,6 +645,7 @@ bool DisplayLayoutConfig::ResetToDefault(std::string_view blockName) {
// TODO: On mobile, where the aspect is fixed, we should use the screen size to compute this properly,
// so the screen almost touches the top edge.
fDisplayOffsetY = 0.25f;
bImmersiveMode = false;
}
return true;
}
@@ -666,6 +667,7 @@ static const ConfigSetting displayLayoutSettings[] = {
ConfigSetting("CardboardScreenSize", SETTING(g_Config.displayLayoutLandscape, iCardboardScreenSize), CfgFlag::PER_GAME),
ConfigSetting("CardboardXShift", SETTING(g_Config.displayLayoutLandscape, iCardboardXShift), CfgFlag::PER_GAME),
ConfigSetting("CardboardYShift", SETTING(g_Config.displayLayoutLandscape, iCardboardYShift), CfgFlag::PER_GAME),
ConfigSetting("ImmersiveMode", SETTING(g_Config.displayLayoutLandscape, bImmersiveMode), CfgFlag::PER_GAME),
};
static const ConfigSetting graphicsSettings[] = {
@@ -725,7 +727,6 @@ static const ConfigSetting graphicsSettings[] = {
ConfigSetting("DisplayCropTo16x9", SETTING(g_Config, bDisplayCropTo16x9), true, CfgFlag::PER_GAME),
ConfigSetting("ImmersiveMode", SETTING(g_Config, bImmersiveMode), true, CfgFlag::PER_GAME),
ConfigSetting("SustainedPerformanceMode", SETTING(g_Config, bSustainedPerformanceMode), false, CfgFlag::PER_GAME),
ConfigSetting("ReplaceTextures", SETTING(g_Config, bReplaceTextures), true, CfgFlag::PER_GAME | CfgFlag::REPORT),
+1 -1
View File
@@ -88,6 +88,7 @@ struct DisplayLayoutConfig : public ConfigBlock {
int iCardboardScreenSize = 50; // Screen Size (in %)
int iCardboardXShift = 0; // X-Shift of Screen (in %)
int iCardboardYShift = 0; // Y-Shift of Screen (in %)
bool bImmersiveMode = true; // Mode on Android Kitkat 4.4 and later that hides the back button etc.
bool InternalRotationIsPortrait() const;
bool CanResetToDefault() const override { return true; }
@@ -271,7 +272,6 @@ public:
bool bDisplayCropTo16x9; // Crops to 16:9 if the resolution is very close.
bool bImmersiveMode; // Mode on Android Kitkat 4.4 and later that hides the back button etc.
bool bSustainedPerformanceMode; // Android: Slows clocks down to avoid overheating/speed fluctuations.
bool bShowImDebugger;
-1
View File
@@ -684,7 +684,6 @@ void TouchTestScreen::CreateViews() {
#if PPSSPP_PLATFORM(ANDROID)
root_->Add(new Choice(gr->T("Recreate Activity")))->OnClick.Handle(this, &TouchTestScreen::OnRecreateActivity);
#endif
root_->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &TouchTestScreen::OnImmersiveModeChange);
root_->Add(new Button(di->T("Back"), new LinearLayoutParams(FILL_PARENT, 64, Margins(10, 0))))->OnClick.Handle<UIScreen>(this, &UIScreen::OnBack);
}
+9 -1
View File
@@ -1199,11 +1199,19 @@ public:
if (ginfo->Ready(GameInfoFlags::PIC1) && ginfo->pic1.texture) {
Draw::Texture *texture = ginfo->pic1.texture;
if (texture) {
const DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation());
// Similar to presentation, we want to put the game PIC1 in the same region of the screen.
FRect frame = GetScreenFrame(config.bIgnoreScreenInsets, g_display.pixel_xres, g_display.pixel_yres);
FRect rc;
CalculateDisplayOutputRect(config, &rc, texture->Width(), texture->Height(), frame, config.iInternalScreenRotation);
Bounds bounds(rc.x, rc.y, rc.w, rc.h);
dc.GetDrawContext()->BindTexture(0, texture);
double loadTime = ginfo->pic1.timeLoaded;
uint32_t color = alphaMul(color_, ease((time_now_d() - loadTime) * 3));
dc.Draw()->DrawTexRect(dc.GetBounds(), 0, 0, 1, 1, color);
dc.Draw()->DrawTexRect(bounds, 0, 0, 1, 1, color);
dc.Flush();
dc.RebindTexture();
}
+3 -2
View File
@@ -374,6 +374,8 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
}
#endif
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
graphicsSettings->Add(new CheckBox(&g_Config.bReplaceTextures, dev->T("Replace textures")));
graphicsSettings->Add(new ItemHeader(gr->T("Display")));
@@ -394,7 +396,7 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
// Hide Immersive Mode on pre-kitkat Android
if (System_GetPropertyInt(SYSPROP_SYSTEMVERSION) >= 19) {
// Let's reuse the Fullscreen translation string from desktop.
graphicsSettings->Add(new CheckBox(&g_Config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange);
graphicsSettings->Add(new CheckBox(&config.bImmersiveMode, gr->T("FullScreen", "Full Screen")))->OnClick.Handle(this, &GameSettingsScreen::OnImmersiveModeChange);
}
#endif
// Display Layout Editor: To avoid overlapping touch controls on large tablets, meet geeky demands for integer zoom/unstretched image etc.
@@ -591,7 +593,6 @@ void GameSettingsScreen::CreateGraphicsSettings(UI::ViewGroup *graphicsSettings)
CheckBox *smartFiltering = graphicsSettings->Add(new CheckBox(&g_Config.bSmart2DTexFiltering, gr->T("Smart 2D texture filtering")));
smartFiltering->SetDisabledPtr(&g_Config.bSoftwareRendering);
DisplayLayoutConfig &config = g_Config.GetDisplayLayoutConfig(GetDeviceOrientation());
#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(IOS)
bool showCardboardSettings = deviceType != DEVICE_TYPE_VR;
#else
+13 -4
View File
@@ -776,11 +776,21 @@ void GameBrowser::Refresh() {
// No topbar on recent screen
gameList_ = nullptr;
if (DisplayTopBar()) {
LinearLayout *topBar = new LinearLayout(ORIENT_HORIZONTAL, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(8, 0, 8, 0)));
Add(topBar);
const bool pathOnSeparateLine = g_display.dp_xres < 1050 || portrait_;
if (pathOnSeparateLine) {
Add(new TextView(path_.GetFriendlyPath(), ALIGN_VCENTER | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(8, 0, 8, 0))));
}
if (browseFlags_ & BrowseFlags::NAVIGATE) {
topBar->Add(new Spacer(2.0f));
topBar->Add(new TextView(path_.GetFriendlyPath(), ALIGN_VCENTER | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, 64.0f, 1.0f)));
if (!pathOnSeparateLine) {
topBar->Add(new Spacer(2.0f));
topBar->Add(new TextView(path_.GetFriendlyPath(), ALIGN_VCENTER | FLAG_WRAP_TEXT, true, new LinearLayoutParams(FILL_PARENT, 64.0f, 1.0f)));
}
topBar->Add(new Choice(ImageID("I_HOME"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::OnHomeClick);
if (System_GetPropertyBool(SYSPROP_HAS_ADDITIONAL_STORAGE)) {
topBar->Add(new Choice(ImageID("I_SDCARD"), new LayoutParams(WRAP_CONTENT, 64.0f)))->OnClick.Handle(this, &GameBrowser::StorageClick);
@@ -808,7 +818,7 @@ void GameBrowser::Refresh() {
});
}
#endif
} else {
} else if (!pathOnSeparateLine) {
topBar->Add(new Spacer(new LinearLayoutParams(FILL_PARENT, 64.0f, 1.0f)));
}
@@ -832,7 +842,6 @@ void GameBrowser::Refresh() {
Refresh();
});
topBar->Add(new Choice(ImageID("I_GEAR"), new LayoutParams(64.0f, 64.0f)))->OnClick.Handle(this, &GameBrowser::GridSettingsClick);
Add(topBar);
if (*gridStyle_) {
gameList_ = new UI::GridLayoutList(UI::GridLayoutSettings(150*g_Config.fGameGridScale, 85*g_Config.fGameGridScale), new LinearLayoutParams(FILL_PARENT, WRAP_CONTENT, Margins(10, 0, 0, 0)));
+2 -3
View File
@@ -51,8 +51,8 @@ TopBar::TopBar(const UIContext &ctx, TopBarFlags flags, std::string_view title,
}
auto dlg = GetI18NCategory(I18NCat::DIALOG);
backButton_ = Add(new Choice(ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams()));
backButton_ ->OnClick.Add([](UI::EventParams &e) {
backButton_ = Add(new Choice(ImageID("I_NAVIGATE_BACK"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)));
backButton_->OnClick.Add([](UI::EventParams &e) {
e.bubbleResult = DR_BACK;
});
@@ -180,7 +180,6 @@ private:
Path gamePath_;
int textureWidth_ = 0;
int textureHeight_ = 0;
bool showGear_ = false;
};
PaneTitleBar::PaneTitleBar(const Path &gamePath, std::string_view title, const std::string_view settingsCategory, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_HORIZONTAL, layoutParams), gamePath_(gamePath) {
-1
View File
@@ -69,6 +69,5 @@ public:
PaneTitleBar(const Path &gamePath, std::string_view title, const std::string_view settingsCategory, UI::LayoutParams *layoutParams = nullptr);
private:
UI::Choice *backButton_ = nullptr;
Path gamePath_;
};
+17 -17
View File
@@ -173,7 +173,7 @@ static float g_safeInsetBottom = 0.0;
static jmethodID postCommand;
static jmethodID getDebugString;
static jobject nativeActivity;
static jobject ppssppActivity;
static std::atomic<bool> exitRenderLoop;
static std::atomic<bool> renderLoopRunning;
@@ -241,7 +241,7 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
gJvm = pjvm; // cache the JavaVM pointer
auto env = getEnv();
//replace with one of your classes in the line below
auto randomClass = env->FindClass("org/ppsspp/ppsspp/NativeActivity");
auto randomClass = env->FindClass("org/ppsspp/ppsspp/PpssppActivity");
jclass classClass = env->GetObjectClass(randomClass);
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
@@ -300,7 +300,7 @@ static void EmuThreadFunc() {
NativeFrame(graphicsContext);
std::lock_guard<std::mutex> guard(frameCommandLock);
if (!nativeActivity) {
if (!ppssppActivity) {
ERROR_LOG(Log::System, "No activity, clearing commands");
while (!frameCommands.empty())
frameCommands.pop();
@@ -519,13 +519,13 @@ bool System_GetPropertyBool(SystemProperty prop) {
}
std::string Android_GetInputDeviceDebugString() {
if (!nativeActivity) {
if (!ppssppActivity) {
return "(N/A)";
}
auto env = getEnv();
jstring jparam = env->NewStringUTF("InputDevice");
jstring jstr = (jstring)env->CallObjectMethod(nativeActivity, getDebugString, jparam);
jstring jstr = (jstring)env->CallObjectMethod(ppssppActivity, getDebugString, jparam);
if (!jstr) {
env->DeleteLocalRef(jparam);
return "(N/A)";
@@ -548,21 +548,21 @@ std::string GetJavaString(JNIEnv *env, jstring jstr) {
return cpp_string;
}
extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_registerCallbacks(JNIEnv *env, jobject obj) {
nativeActivity = env->NewGlobalRef(obj);
extern "C" void Java_org_ppsspp_ppsspp_PpssppActivity_registerCallbacks(JNIEnv *env, jobject obj) {
ppssppActivity = env->NewGlobalRef(obj);
postCommand = env->GetMethodID(env->GetObjectClass(obj), "postCommand", "(Ljava/lang/String;Ljava/lang/String;)V");
getDebugString = env->GetMethodID(env->GetObjectClass(obj), "getDebugString", "(Ljava/lang/String;)Ljava/lang/String;");
_dbg_assert_(postCommand);
_dbg_assert_(getDebugString);
Android_RegisterStorageCallbacks(env, obj);
Android_StorageSetActivity(nativeActivity);
Android_StorageSetActivity(ppssppActivity);
}
extern "C" void Java_org_ppsspp_ppsspp_NativeActivity_unregisterCallbacks(JNIEnv *env, jobject obj) {
extern "C" void Java_org_ppsspp_ppsspp_PpssppActivity_unregisterCallbacks(JNIEnv *env, jobject obj) {
Android_StorageSetActivity(nullptr);
env->DeleteGlobalRef(nativeActivity);
nativeActivity = nullptr;
env->DeleteGlobalRef(ppssppActivity);
ppssppActivity = nullptr;
}
// This is now only used as a trigger for GetAppInfo as a function to all before Init.
@@ -594,7 +594,7 @@ static std::string QueryConfig(std::string_view query) {
snprintf(temp, sizeof(temp), "%d", g_Config.iScreenRotation);
return temp;
} else if (query == "immersiveMode") {
return g_Config.bImmersiveMode ? "1" : "0";
return g_Config.GetDisplayLayoutConfig(g_display.GetDeviceOrientation()).bImmersiveMode ? "1" : "0";
} else if (query == "sustainedPerformanceMode") {
return g_Config.bSustainedPerformanceMode ? "1" : "0";
} else if (query == "androidJavaGL") {
@@ -809,7 +809,7 @@ retry:
if (IsVREnabled()) {
Version gitVer(PPSSPP_GIT_VERSION);
InitVROnAndroid(gJvm, nativeActivity, systemName.c_str(), gitVer.ToInteger(), "PPSSPP");
InitVROnAndroid(gJvm, ppssppActivity, systemName.c_str(), gitVer.ToInteger(), "PPSSPP");
SetVRCallbacks(NativeAxis, NativeKey, NativeTouch);
}
}
@@ -1577,7 +1577,7 @@ static void ProcessFrameCommands(JNIEnv *env) {
jstring cmd = env->NewStringUTF(frameCmd.command.c_str());
jstring param = env->NewStringUTF(frameCmd.params.c_str());
env->CallVoidMethod(nativeActivity, postCommand, cmd, param);
env->CallVoidMethod(ppssppActivity, postCommand, cmd, param);
env->DeleteLocalRef(cmd);
env->DeleteLocalRef(param);
}
@@ -1589,7 +1589,7 @@ static void VulkanEmuThread(ANativeWindow *wnd);
// This runs in Vulkan mode only.
// This handles the entire lifecycle of the Vulkan context, init and exit.
extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runVulkanRenderLoop(JNIEnv * env, jobject obj, jobject _surf) {
extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_PpssppActivity_runVulkanRenderLoop(JNIEnv * env, jobject obj, jobject _surf) {
_assert_(!useCPUThread);
if (!graphicsContext) {
@@ -1615,7 +1615,7 @@ extern "C" jboolean JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runVulkanRende
return true;
}
extern "C" void JNICALL Java_org_ppsspp_ppsspp_NativeActivity_requestExitVulkanRenderLoop(JNIEnv * env, jobject obj) {
extern "C" void JNICALL Java_org_ppsspp_ppsspp_PpssppActivity_requestExitVulkanRenderLoop(JNIEnv * env, jobject obj) {
if (!renderLoopRunning) {
ERROR_LOG(Log::System, "Render loop already exited");
return;
@@ -1708,7 +1708,7 @@ Java_org_ppsspp_ppsspp_ShortcutActivity_queryGameInfo(JNIEnv * env, jclass, jobj
jobject activityRef = nullptr;
bool teardownThreadManager = false;
// Maybe we should just check nativeActivity instead.
// Maybe we should just check ppssppActivity instead.
if (!g_threadManager.IsInitialized()) {
teardownThreadManager = true;
g_threadManager.Init(1, 1);
-66
View File
@@ -23,39 +23,6 @@
column="36"/>
</issue>
<issue
id="GestureBackNavigation"
message="If intercepting back events, this should be handled through the registration of callbacks; see https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture"
errorLine1=" case KeyEvent.KEYCODE_BACK:"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/ppsspp/ppsspp/NativeActivity.java"
line="1021"
column="8"/>
</issue>
<issue
id="GestureBackNavigation"
message="If intercepting back events, this should be handled through the registration of callbacks; see https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture"
errorLine1=" case KeyEvent.KEYCODE_BACK:"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/ppsspp/ppsspp/NativeActivity.java"
line="1135"
column="8"/>
</issue>
<issue
id="GestureBackNavigation"
message="If intercepting back events, this should be handled through the registration of callbacks; see https://developer.android.com/guide/navigation/custom-back/predictive-back-gesture"
errorLine1=" case KeyEvent.KEYCODE_BACK:"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/ppsspp/ppsspp/NativeActivity.java"
line="1169"
column="8"/>
</issue>
<issue
id="UnusedAttribute"
message="Attribute `appCategory` is only used in API level 26 and higher (current min is 21)"
@@ -89,37 +56,4 @@
column="22"/>
</issue>
<issue
id="QueryPermissionsNeeded"
message="Consider adding a `&lt;queries>` declaration to your manifest when calling this method; see https://g.co/dev/packagevisibility for details"
errorLine1=" if (intent.resolveActivityInfo(getPackageManager(), 0) != null) {"
errorLine2=" ~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/ppsspp/ppsspp/NativeActivity.java"
line="1669"
column="16"/>
</issue>
<issue
id="SourceLockedOrientationActivity"
message="You should not lock orientation of your activities, so that you can support a good user experience for any device or orientation"
errorLine1=" setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/ppsspp/ppsspp/NativeActivity.java"
line="538"
column="4"/>
</issue>
<issue
id="SourceLockedOrientationActivity"
message="You should not lock orientation of your activities, so that you can support a good user experience for any device or orientation"
errorLine1=" setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="src/org/ppsspp/ppsspp/NativeActivity.java"
line="544"
column="4"/>
</issue>
</issues>
@@ -161,7 +161,7 @@ class CameraHelper {
static ArrayList<String> getDeviceList() {
ArrayList<String> deviceList = new ArrayList<>();
if (NativeActivity.isVRDevice()) {
if (PpssppActivity.isVRDevice()) {
return deviceList;
}
int nrCam = Camera.getNumberOfCameras();
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -114,7 +114,7 @@ public class NativeApp {
Log.i(TAG, "motion mouse event");
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN: {
if (NativeActivity.useModernMouseEvents) {
if (PpssppActivity.useModernMouseEvents) {
return;
}
//Log.i(TAG, "Surface Action down. button state: " + ev.getButtonState());
@@ -122,7 +122,7 @@ public class NativeApp {
break;
}
case MotionEvent.ACTION_UP: {
if (NativeActivity.useModernMouseEvents) {
if (PpssppActivity.useModernMouseEvents) {
return;
}
//Log.i(TAG, "Surface Action up. button state: " + ev.getButtonState());
File diff suppressed because it is too large Load Diff
+6 -45
View File
@@ -1,33 +1,27 @@
package org.ppsspp.ppsspp;
import android.annotation.TargetApi;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Build;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowInsets;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresApi;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
public class SizeManager implements SurfaceHolder.Callback {
private static final String TAG = "PPSSPPSizeManager";
final NativeActivity activity;
final PpssppActivity activity;
SurfaceView surfaceView = null;
private int safeInsetLeft = 0;
private int safeInsetRight = 0;
private int safeInsetTop = 0;
private int safeInsetBottom = 0;
private float densityDpi;
private float refreshRate;
@@ -42,7 +36,7 @@ public class SizeManager implements SurfaceHolder.Callback {
private boolean paused = false;
public SizeManager(final NativeActivity a) {
public SizeManager(final PpssppActivity a) {
activity = a;
}
@@ -67,17 +61,6 @@ public class SizeManager implements SurfaceHolder.Callback {
return;
surfaceView.getHolder().addCallback(this);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
surfaceView.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
@NonNull
@Override
public WindowInsets onApplyWindowInsets(@NonNull View view, @NonNull WindowInsets windowInsets) {
updateInsets(windowInsets);
return windowInsets;
}
});
}
}
@Override
@@ -212,26 +195,4 @@ public class SizeManager implements SurfaceHolder.Callback {
sz.x = NativeApp.getDesiredBackbufferWidth();
sz.y = NativeApp.getDesiredBackbufferHeight();
}
@RequiresApi(Build.VERSION_CODES.P)
private void updateInsets(WindowInsets insets) {
if (insets == null) {
return;
}
DisplayCutout cutout = insets.getDisplayCutout();
if (cutout != null) {
safeInsetLeft = cutout.getSafeInsetLeft();
safeInsetRight = cutout.getSafeInsetRight();
safeInsetTop = cutout.getSafeInsetTop();
safeInsetBottom = cutout.getSafeInsetBottom();
// Log.i(TAG, "Safe insets: left: " + safeInsetLeft + " right: " + safeInsetRight + " top: " + safeInsetTop + " bottom: " + safeInsetBottom);
} else {
// Log.i(TAG, "Safe insets: Cutout was null");
safeInsetLeft = 0;
safeInsetRight = 0;
safeInsetTop = 0;
safeInsetBottom = 0;
}
NativeApp.sendMessageFromJava("safe_insets", safeInsetLeft + ":" + safeInsetRight + ":" + safeInsetTop + ":" + safeInsetBottom);
}
}