Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/Android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ jobs:
path: |
Builder/Android/app/jni/SDL
Builder/Android/app/src/main/java/org/libsdl
key: ${{ runner.os }}-android-sdl2-${{ hashFiles('Builder/Android/setup_sdl2.sh') }}
key: ${{ runner.os }}-android-sdl2-${{ hashFiles('Builder/Android/setup_sdl2.sh', 'Builder/Android/patches/sdl2-2.32.10-android-compat.patch') }}
restore-keys: |
${{ runner.os }}-android-sdl2-

Expand Down
14 changes: 14 additions & 0 deletions Builder/Android/app/jni/src/saf.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,6 +575,20 @@ static jmethodID JNI_RaMethod(JNIEnv *env, const char *name, const char *signatu
return (*env)->GetMethodID(env, java_class, name, signature);
}

//
// Android_SetRotationMode()
// apply Android Activity rotation mode
//
void Android_SetRotationMode(int mode)
{
JNIEnv *env = JNI_GetEnvironment();
if (env == NULL || java_activity == NULL || java_class == NULL) return;
jmethodID id = JNI_RaMethod(env, "setRotationMode", "(I)V");
if (id == NULL) return;
(*env)->CallVoidMethod(env, java_activity, id, (jint)mode);
JNI_HasException(env);
}

void Android_RaShowLogin(const char *username)
{
JNIEnv *env = JNI_GetEnvironment();
Expand Down
4 changes: 4 additions & 0 deletions Builder/Android/app/jni/src/xm8jni.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ int Android_ChDir(char *dir, const char *name);
//
void Android_PollJoystick(void);

// Android_SetRotationMode()
// apply auto, landscape, or portrait Activity rotation mode
void Android_SetRotationMode(int mode);

// RetroAchievements Android bridge (available only in RA-enabled builds).
int Android_RaHttpSend(unsigned long long request_id, const char *url,
const char *post_data, const char *content_type, int connect_timeout_ms,
Expand Down
3 changes: 2 additions & 1 deletion Builder/Android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
An example Java class can be found in README-android.md
-->
<application
android:appCategory="game"
android:allowBackup="true"
android:fullBackupContent="@xml/backup_rules"
android:dataExtractionRules="@xml/data_extraction_rules"
Expand All @@ -75,7 +76,7 @@
android:launchMode="singleInstance"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:screenOrientation="sensorLandscape"
android:screenOrientation="sensor"
android:exported="true">

<intent-filter>
Expand Down
117 changes: 109 additions & 8 deletions Builder/Android/app/src/main/java/net/retropc/pi/XM8.java
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Intent;
import android.content.Intent;
import android.content.res.Configuration;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
Expand All @@ -51,10 +52,14 @@
import android.view.KeyEvent;
import android.view.WindowManager;
import androidx.core.content.ContextCompat;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ActivityInfo;
import androidx.core.app.ActivityCompat;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.DisplayCutout;
import android.view.RoundedCorner;
import android.graphics.Insets;
import android.widget.Toast;
import android.widget.Button;
import android.widget.EditText;
Expand All @@ -68,8 +73,103 @@
import android.os.ParcelFileDescriptor;

public class XM8 extends SDLActivity {
// log
private static final String LOG_TAG = "XM8";
// log
private static final String LOG_TAG = "XM8";
private static final int ROTATION_AUTO = 0;
private static final int ROTATION_LANDSCAPE = 1;
private static final int ROTATION_PORTRAIT = 2;
private int mRotationMode = ROTATION_AUTO;

private void installSafeAreaInsets() {
if (mLayout == null) return;

mLayout.setOnApplyWindowInsetsListener(new View.OnApplyWindowInsetsListener() {
@Override public WindowInsets onApplyWindowInsets(View view, WindowInsets insets) {
int top;
int bottom;

// The portrait game/control layout needs room above and below
// its full-width panels. Do not inset landscape or the left /
// right edges: those margins are both visually excessive and
// unnecessary for the existing aspect-correct landscape view.
if (getResources().getConfiguration().orientation
!= Configuration.ORIENTATION_PORTRAIT) {
view.setPadding(0, 0, 0, 0);
return insets;
}

if (Build.VERSION.SDK_INT >= 30) {
Insets safe = insets.getInsetsIgnoringVisibility(
WindowInsets.Type.displayCutout());
top = safe.top;
bottom = safe.bottom;
} else {
top = 0;
bottom = 0;
if (Build.VERSION.SDK_INT >= 28) {
DisplayCutout cutout = insets.getDisplayCutout();
if (cutout != null) {
top = Math.max(top, cutout.getSafeInsetTop());
bottom = Math.max(bottom, cutout.getSafeInsetBottom());
}
}
}

if (Build.VERSION.SDK_INT >= 31) {
RoundedCorner topLeft = insets.getRoundedCorner(
RoundedCorner.POSITION_TOP_LEFT);
RoundedCorner topRight = insets.getRoundedCorner(
RoundedCorner.POSITION_TOP_RIGHT);
RoundedCorner bottomLeft = insets.getRoundedCorner(
RoundedCorner.POSITION_BOTTOM_LEFT);
RoundedCorner bottomRight = insets.getRoundedCorner(
RoundedCorner.POSITION_BOTTOM_RIGHT);
top = Math.max(top, Math.max(radiusOf(topLeft), radiusOf(topRight)));
bottom = Math.max(bottom, Math.max(radiusOf(bottomLeft), radiusOf(bottomRight)));
}

view.setPadding(0, top, 0, bottom);
return insets;
}
});
mLayout.requestApplyInsets();
}

private static int radiusOf(RoundedCorner corner) {
return corner == null ? 0 : corner.getRadius();
}

@Override
public void setOrientationBis(int w, int h, boolean resizable, String hint) {
// XM8 supports both the legacy landscape layout and the portrait
// game/control split. SDL's default picks landscape from its initial
// 640x400 window size, so keep the Activity responsive to user rotation.
applyRotationMode();
}

public void setRotationMode(final int mode) {
mRotationMode = (mode == ROTATION_LANDSCAPE || mode == ROTATION_PORTRAIT)
? mode : ROTATION_AUTO;
runOnUiThread(new Runnable() {
@Override public void run() {
if (!isFinishing()) applyRotationMode();
}
});
}

private void applyRotationMode() {
switch (mRotationMode) {
case ROTATION_LANDSCAPE:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
break;
case ROTATION_PORTRAIT:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT);
break;
default:
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_USER);
break;
}
}

// directory and filename
private static final String ROM_DIRECTORY = "/XM8/";
Expand Down Expand Up @@ -171,8 +271,9 @@ protected void onCreate(Bundle savedInstanceState) {
// super class
super.onCreate(savedInstanceState);

// immersive full-screen mode or dim status bar / navigation icon
setupWindow();
// immersive full-screen mode or dim status bar / navigation icon
setupWindow();
installSafeAreaInsets();

// set Build.VERSION.SDK_INT and app files directory
nativeBuildVer(Build.VERSION.SDK_INT);
Expand Down
19 changes: 18 additions & 1 deletion Source/UI/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@
#include "tapemgr.h"
#include "clidisk.h"
#include "m3u.h"
#ifdef __ANDROID__
#include "xm8jni.h"
#endif
#ifdef XM8_ENABLE_RETROACHIEVEMENTS
#include "ra_media_change_policy.h"
#include "ra_build_info.h"
Expand Down Expand Up @@ -616,6 +619,9 @@ bool App::Init(const CliOptions& options)
Deinit();
return false;
}
#ifdef __ANDROID__
ApplyAndroidRotationMode();
#endif
if (ApplyCommandLineSettings(options) == false) {
Deinit();
return false;
Expand Down Expand Up @@ -5875,7 +5881,7 @@ bool App::IsFullSpeed()
// SetWindowWidth()
// set window width
//
void App::SetWindowWidth()
void App::SetWindowWidth()
{
int width;
int height;
Expand Down Expand Up @@ -5979,6 +5985,17 @@ void App::CtrlAudio()
audio->Stop();
}
}

#ifdef __ANDROID__
//
// ApplyAndroidRotationMode()
// apply persisted Android Activity rotation mode
//
void App::ApplyAndroidRotationMode()
{
Android_SetRotationMode(setting->GetRotationMode());
}
#endif

//
// ChangeAudio()
Expand Down
20 changes: 12 additions & 8 deletions Source/UI/app.h
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,12 @@ class App
// normal speed
bool IsFullSpeed();
// get full speed flag
void SetWindowWidth();
// set window width
void SetWindowWidth();
// set window width
#ifdef __ANDROID__
void ApplyAndroidRotationMode();
// apply Android rotation mode
#endif

// action
void OnKeyVM(SDL_Scancode code);
Expand Down Expand Up @@ -230,10 +234,12 @@ class App
// get version
const char* GetAppTitle();
// get application title
void* GetEvMgr();
// get event manager

private:
void* GetEvMgr();
// get event manager
bool IsRaOverlayBlocking() const;
// check blocking RA overlay

private:
// drawing
void Draw();
// rendering
Expand Down Expand Up @@ -408,8 +414,6 @@ class App
// save legacy XM8 state body
void ChangeSystemInternal(bool load, bool preserve_ra_session);
// rebuild VM with explicit RA lifecycle policy
bool IsRaOverlayBlocking() const;
// check blocking RA overlay
bool OpenStartupDisks(const std::vector<DiskSpec>& disks, std::string *error);
// open CLI disks
bool OpenDroppedDisk(const char *path, std::string *error);
Expand Down
42 changes: 22 additions & 20 deletions Source/UI/input.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -907,7 +907,7 @@ void Input::OnMouseMotion(SDL_Event *e)
// convert point
x = e->motion.x;
y = e->motion.y;
if (video->ConvertPoint(&x, &y) == false) {
if (video->ConvertSoftKeyPoint(&x, &y) == false) {
return;
}

Expand Down Expand Up @@ -948,7 +948,7 @@ void Input::OnMouseButtonDown(SDL_Event *e)
// convert point
x = e->button.x;
y = e->button.y;
if (video->ConvertPoint(&x, &y) == false) {
if (video->ConvertSoftKeyPoint(&x, &y) == false) {
return;
}

Expand Down Expand Up @@ -990,7 +990,7 @@ void Input::OnMouseButtonUp(SDL_Event *e)
// convert point
x = e->button.x;
y = e->button.y;
if (video->ConvertPoint(&x, &y) == false) {
if (video->ConvertSoftKeyPoint(&x, &y) == false) {
return;
}

Expand Down Expand Up @@ -1108,11 +1108,11 @@ void Input::OnFingerDown(SDL_Event *e)
SDL_assert(e->tfinger.fingerId >= 0);

// convert finger
x = 0;
y = 0;
if (video->ConvertFinger(e->tfinger.x, e->tfinger.y, &x, &y) == false) {
return;
}
x = 0;
y = 0;
if (video->ConvertSoftKeyFinger(e->tfinger.x, e->tfinger.y, &x, &y) == false) {
return;
}

OnInputCommon(x, y, true, (int)e->tfinger.fingerId);
}
Expand All @@ -1121,19 +1121,20 @@ void Input::OnFingerDown(SDL_Event *e)
// OnFingerUp()
// finger up
//
void Input::OnFingerUp(SDL_Event *e)
void Input::OnFingerUp(SDL_Event *e)
{
int x;
int y;

SDL_assert(e->tfinger.fingerId >= 0);

// convert finger
x = 0;
y = 0;
if (video->ConvertFinger(e->tfinger.x, e->tfinger.y, &x, &y) == false) {
return;
}
x = 0;
y = 0;
if (video->ConvertSoftKeyFinger(e->tfinger.x, e->tfinger.y, &x, &y) == false) {
OnInputMove(NULL, (int)e->tfinger.fingerId);
return;
}

OnInputCommon(x, y, false, (int)e->tfinger.fingerId);
}
Expand All @@ -1142,19 +1143,20 @@ void Input::OnFingerUp(SDL_Event *e)
// OnFingerMotion()
// finger motion
//
void Input::OnFingerMotion(SDL_Event *e)
void Input::OnFingerMotion(SDL_Event *e)
{
int x;
int y;

SDL_assert(e->tfinger.fingerId >= 0);

// convert finger
x = 0;
y = 0;
if (video->ConvertFinger(e->tfinger.x, e->tfinger.y, &x, &y) == false) {
return;
}
x = 0;
y = 0;
if (video->ConvertSoftKeyFinger(e->tfinger.x, e->tfinger.y, &x, &y) == false) {
OnInputMove(NULL, (int)e->tfinger.fingerId);
return;
}

OnInputCommon(x, y, true, (int)e->tfinger.fingerId);
}
Expand Down
3 changes: 2 additions & 1 deletion Source/UI/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,8 @@ int main(int argc, char *argv[])
#if SDL_VERSION_ATLEAST(2, 0, 12)
SDL_SetHint(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, "0");
#endif
SDL_SetHint(SDL_HINT_ORIENTATIONS, "LandscapeLeft LandscapeRight");
SDL_SetHint(SDL_HINT_ORIENTATIONS,
"LandscapeLeft LandscapeRight Portrait PortraitUpsideDown");

// initialize SDL
ret = SDL_Init(
Expand Down
Loading
Loading