floooh / sokol

minimal cross-platform standalone C headers
https://floooh.github.io/sokol-html5
zlib License
6.53k stars 467 forks source link

App Window Size on Android #1069

Open voidware opened 1 week ago

voidware commented 1 week ago

Hi! I'm now on the latest Sokol;

having a go at getting my app working on Android. I have it built and running but I can't figure out how to control the main window size.

It appears that full-screen is automatic on Android, but the window created fills the whole phone area. Now actually, that's what i will eventually want, but also i have to find a way to hide/show the system UI.

But for now, I'd just like it to be the client area size. ie the phone size minus the top system area and the bottom button area. Because clicks don't work on the app in these areas, they seem to go to the system.

Any idea how i might do this? I had a go at messing with things like;

ANativeActivity_setWindowFlags(activity, AWINDOW_FLAG_FORCE_NOT_FULLSCREEN, 0);

This didn't make any difference, but i wonder if I'm calling too late, or something. Or whether ANativeWindow_getWidth(window) does not consider this.

Anyhow. if you know, or have ideas, that could help.

Or i can keep hacking!

Thanks.

floooh commented 1 week ago

No idea tbh (Android is basically a "tier 3 platform" for sokol_app.h, basic support is there, but personally I'm not all that invested in the platform).

In general, sokol_app.h on the mobile platforms and the web doesn't have the concept of windows, and specifically on iOS and Android it assumes that the canvas stretches the entire display.

If it's just the "system chrome" that should be visible I would actually expect that this is a manifest file setting (but not sure).

You could try adding the ANativeActivity_setWindowFlags calls here (but you probably found that place already):

https://github.com/floooh/sokol/blob/b1221d1f2bfc3cbb22f566cfa8f31b4073c287ae/sokol_app.h#L8180

Also, if SDL2 has a solution that doesn't require too many changes, we could probably do something similar in sokol_app.h.

voidware commented 1 week ago

OK. Thanks for your reply.

I think the default Android "full screen" should not overlay the system buttons but otherwise occupy the screen.

I'll see if i can find out how. If i do, I'll let you know in case you want to make that the default.

voidware commented 5 days ago

Hi,

I failed to find out how to size to a client of the screen gadgets. But, more usefully, I now have full screen working properly by hiding the system UI.

Here are my changes in case they are helpful to someone.

in AndroidManifest.xml change acivity android::name to MainActivity;

    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="Whatever"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
        tools:targetApi="31">
        <activity
            android:name=".MainActivity"
            android:launchMode="singleTask"
            ...

Have some Java in MainActivity.java;

package com.voidware.whatever;

import android.app.NativeActivity;
import android.view.View;

public class MainActivity extends NativeActivity {
    static {
        System.loadLibrary("whatever");
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);

        if (hasFocus) {
            hideSystemUi();
        }
    }

    private void hideSystemUi() {
        View decorView = getWindow().getDecorView();
        decorView.setSystemUiVisibility(
                View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
                        | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
                        | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
                        | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                        | View.SYSTEM_UI_FLAG_FULLSCREEN
        );
    }
}

Despite setSystemUiVisibility deprecated, this seems to work fine. At least on 28.

Also, while I'm here. I finally managed to find out the approximate screen DPI. This is needed for sizing fonts, for example. You might want to put something like this into Sokol. This is quite useful.

static inline int android_dpi()
{
    /* return the screen density (DPI).
     * In theory, it should return one from the following table of
     * values, but in practice it seems to return its own number!
     */
    int dpi = 0;

    /*
      ACONFIGURATION_DENSITY_DEFAULT = 0,
      ACONFIGURATION_DENSITY_LOW = 120,
      ACONFIGURATION_DENSITY_MEDIUM = 160,
      ACONFIGURATION_DENSITY_TV = 213,
      ACONFIGURATION_DENSITY_HIGH = 240,
      ACONFIGURATION_DENSITY_XHIGH = 320,
      ACONFIGURATION_DENSITY_XXHIGH = 480,
      ACONFIGURATION_DENSITY_XXXHIGH = 640,
      ACONFIGURATION_DENSITY_ANY = 0xfffe,
      ACONFIGURATION_DENSITY_NONE = 0xffff,
    */

    auto act = (ANativeActivity*)sapp_android_get_native_activity();
    if (act)
    {
        AAssetManager* am = act->assetManager;
        assert(am);

        AConfiguration* ac = AConfiguration_new();
        AConfiguration_fromAssetManager(ac, am);

        // can return values not in above list;
        // eg;
        // 440 = phone
        // 360 = pad
        dpi = AConfiguration_getDensity(ac);

        if (dpi >= ACONFIGURATION_DENSITY_ANY)
        {
            // mark as unknown
            dpi = 0;
        }

        AConfiguration_delete(ac);
    }
    return dpi;
}