diff --git a/.drone.star b/.drone.star index 60278044c..194adc533 100644 --- a/.drone.star +++ b/.drone.star @@ -39,37 +39,36 @@ def targets_android(platform): 'mspack', 'snappy', 'xxhash', - 'xenia-core', + 'xenia-app', # 'xenia-app-discord', 'xenia-apu', 'xenia-apu-nop', 'xenia-base', 'xenia-base-tests', + 'xenia-core', 'xenia-cpu', - # 'xenia-cpu-tests', - # 'xenia-cpu-ppc-tests', + 'xenia-cpu-tests', + 'xenia-cpu-ppc-tests', # 'xenia-cpu-backend-x64', # 'xenia-debug-ui', 'xenia-gpu', 'xenia-gpu-shader-compiler', 'xenia-gpu-null', 'xenia-gpu-vulkan', - # 'xenia-gpu-vulkan-trace-viewer', + 'xenia-gpu-vulkan-trace-viewer', 'xenia-gpu-vulkan-trace-dump', 'xenia-hid', - # 'xenia-hid-demo', + 'xenia-hid-demo', 'xenia-hid-nop', 'xenia-kernel', 'xenia-ui', 'xenia-ui-vulkan', - # 'xenia-ui-window-vulkan-demo', + 'xenia-ui-window-vulkan-demo', 'xenia-vfs', 'xenia-vfs-dump', ] if platform == 'Android-x86_64': targets.extend([ - 'xenia-cpu-tests', - 'xenia-cpu-ppc-tests', 'xenia-cpu-backend-x64', 'xenia-debug-ui', ]) diff --git a/android/android_studio_project/app/build.gradle b/android/android_studio_project/app/build.gradle index ae753e1b2..92fc816b2 100644 --- a/android/android_studio_project/app/build.gradle +++ b/android/android_studio_project/app/build.gradle @@ -3,14 +3,14 @@ plugins { } android { - compileSdkVersion 30 - ndkVersion '23.0.7599858' + compileSdkVersion 33 + ndkVersion '25.0.8775105' defaultConfig { applicationId 'jp.xenia.emulator' // 24 (7.0) - Vulkan. minSdkVersion 24 - targetSdkVersion 30 + targetSdkVersion 33 versionCode 1 versionName 'Prototype' externalNativeBuild { @@ -18,13 +18,17 @@ android { arguments 'NDK_APPLICATION_MK:=../../../build/xenia.Application.mk', 'PREMAKE_ANDROIDNDK_PLATFORMS:=Android-ARM64', 'PREMAKE_ANDROIDNDK_PLATFORMS+=Android-x86_64', + // ndk.jobs doesn't work as of Gradle 7.1.0. + "-j${Runtime.runtime.availableProcessors()}", // Work around "Bad file descriptor" on Windows on NDK r22+. '--output-sync=none' + // For the app, don't build the executables designed for running from a terminal. + // To build the executables, run ndk-build manually. + targets 'xenia-app' } } ndk { abiFilters 'arm64-v8a', 'x86_64' - jobs Runtime.runtime.availableProcessors() stl 'c++_static' } } diff --git a/android/android_studio_project/app/src/main/AndroidManifest.xml b/android/android_studio_project/app/src/main/AndroidManifest.xml index 25bf5a95f..184d52ad6 100644 --- a/android/android_studio_project/app/src/main/AndroidManifest.xml +++ b/android/android_studio_project/app/src/main/AndroidManifest.xml @@ -15,12 +15,6 @@ - - - + android:name="jp.xenia.emulator.LauncherActivity" + android:exported="true"> + + + + \ No newline at end of file diff --git a/android/android_studio_project/app/src/main/java/jp/xenia/emulator/GpuTraceViewerActivity.java b/android/android_studio_project/app/src/main/java/jp/xenia/emulator/GpuTraceViewerActivity.java new file mode 100644 index 000000000..f1fe8a306 --- /dev/null +++ b/android/android_studio_project/app/src/main/java/jp/xenia/emulator/GpuTraceViewerActivity.java @@ -0,0 +1,18 @@ +package jp.xenia.emulator; + +import android.os.Bundle; + +public class GpuTraceViewerActivity extends WindowedAppActivity { + @Override + protected String getWindowedAppIdentifier() { + return "xenia_gpu_vulkan_trace_viewer"; + } + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_gpu_trace_viewer); + setWindowSurfaceView(findViewById(R.id.gpu_trace_viewer_surface_view)); + } +} diff --git a/android/android_studio_project/app/src/main/java/jp/xenia/emulator/LauncherActivity.java b/android/android_studio_project/app/src/main/java/jp/xenia/emulator/LauncherActivity.java new file mode 100644 index 000000000..0c977f0e8 --- /dev/null +++ b/android/android_studio_project/app/src/main/java/jp/xenia/emulator/LauncherActivity.java @@ -0,0 +1,45 @@ +package jp.xenia.emulator; + +import android.app.Activity; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +public class LauncherActivity extends Activity { + private static final int REQUEST_OPEN_GPU_TRACE_VIEWER = 0; + + @Override + protected void onCreate(final Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + setContentView(R.layout.activity_launcher); + } + + @Override + protected void onActivityResult( + final int requestCode, final int resultCode, final Intent data) { + if (requestCode == REQUEST_OPEN_GPU_TRACE_VIEWER && resultCode == RESULT_OK) { + final Uri uri = data.getData(); + if (uri != null) { + final Intent gpuTraceViewerIntent = new Intent(this, GpuTraceViewerActivity.class); + final Bundle gpuTraceViewerLaunchArguments = new Bundle(); + gpuTraceViewerLaunchArguments.putString("target_trace_file", uri.toString()); + gpuTraceViewerIntent.putExtra( + WindowedAppActivity.EXTRA_CVARS, gpuTraceViewerLaunchArguments); + startActivity(gpuTraceViewerIntent); + } + } + } + + public void onLaunchGpuTraceViewerClick(final View view) { + final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT); + intent.addCategory(Intent.CATEGORY_OPENABLE); + intent.setType("application/octet-stream"); + startActivityForResult(intent, REQUEST_OPEN_GPU_TRACE_VIEWER); + } + + public void onLaunchWindowDemoClick(final View view) { + startActivity(new Intent(this, WindowDemoActivity.class)); + } +} diff --git a/android/android_studio_project/app/src/main/java/jp/xenia/emulator/WindowedAppActivity.java b/android/android_studio_project/app/src/main/java/jp/xenia/emulator/WindowedAppActivity.java index e93baaf0e..84de4ab13 100644 --- a/android/android_studio_project/app/src/main/java/jp/xenia/emulator/WindowedAppActivity.java +++ b/android/android_studio_project/app/src/main/java/jp/xenia/emulator/WindowedAppActivity.java @@ -1,8 +1,10 @@ package jp.xenia.emulator; +import android.annotation.SuppressLint; import android.app.Activity; import android.content.res.AssetManager; import android.os.Bundle; +import android.view.MotionEvent; import android.view.Surface; import android.view.SurfaceHolder; import android.view.View; @@ -12,15 +14,18 @@ import org.jetbrains.annotations.Nullable; import jp.xenia.XeniaRuntimeException; public abstract class WindowedAppActivity extends Activity { + // The EXTRA_CVARS value literal is also used in the native code. + + /** + * Name of the Bundle intent extra containing Xenia config variable launch arguments. + */ + public static final String EXTRA_CVARS = "jp.xenia.emulator.WindowedAppActivity.EXTRA_CVARS"; + static { - // TODO(Triang3l): Move all demos to libxenia.so. - System.loadLibrary("xenia-ui-window-vulkan-demo"); + System.loadLibrary("xenia-app"); } - private final WindowSurfaceOnLayoutChangeListener mWindowSurfaceOnLayoutChangeListener = - new WindowSurfaceOnLayoutChangeListener(); - private final WindowSurfaceHolderCallback mWindowSurfaceHolderCallback = - new WindowSurfaceHolderCallback(); + private final WindowSurfaceListener mWindowSurfaceListener = new WindowSurfaceListener(); // May be 0 while destroying (mainly while the superclass is). private long mAppContext = 0; @@ -36,6 +41,8 @@ public abstract class WindowedAppActivity extends Activity { private native void onWindowSurfaceLayoutChange( long appContext, int left, int top, int right, int bottom); + private native boolean onWindowSurfaceMotionEvent(long appContext, MotionEvent event); + private native void onWindowSurfaceChanged(long appContext, Surface windowSurface); private native void paintWindow(long appContext, boolean forcePaint); @@ -49,8 +56,10 @@ public abstract class WindowedAppActivity extends Activity { // Detach from the old surface. if (mWindowSurfaceView != null) { - mWindowSurfaceView.getHolder().removeCallback(mWindowSurfaceHolderCallback); - mWindowSurfaceView.removeOnLayoutChangeListener(mWindowSurfaceOnLayoutChangeListener); + mWindowSurfaceView.getHolder().removeCallback(mWindowSurfaceListener); + mWindowSurfaceView.setOnTouchListener(null); + mWindowSurfaceView.setOnGenericMotionListener(null); + mWindowSurfaceView.removeOnLayoutChangeListener(mWindowSurfaceListener); mWindowSurfaceView = null; if (mAppContext != 0) { onWindowSurfaceChanged(mAppContext, null); @@ -62,12 +71,12 @@ public abstract class WindowedAppActivity extends Activity { } mWindowSurfaceView = windowSurfaceView; - // The native window code assumes that, when the surface exists, it covers the entire - // window. // FIXME(Triang3l): This doesn't work if the layout has already been performed. - mWindowSurfaceView.addOnLayoutChangeListener(mWindowSurfaceOnLayoutChangeListener); + mWindowSurfaceView.addOnLayoutChangeListener(mWindowSurfaceListener); + mWindowSurfaceView.setOnGenericMotionListener(mWindowSurfaceListener); + mWindowSurfaceView.setOnTouchListener(mWindowSurfaceListener); final SurfaceHolder windowSurfaceHolder = mWindowSurfaceView.getHolder(); - windowSurfaceHolder.addCallback(mWindowSurfaceHolderCallback); + windowSurfaceHolder.addCallback(mWindowSurfaceListener); // If setting after the creation of the surface. if (mAppContext != 0) { final Surface windowSurface = windowSurfaceHolder.getSurface(); @@ -116,7 +125,11 @@ public abstract class WindowedAppActivity extends Activity { super.onDestroy(); } - private class WindowSurfaceOnLayoutChangeListener implements View.OnLayoutChangeListener { + private class WindowSurfaceListener implements + View.OnGenericMotionListener, + View.OnLayoutChangeListener, + View.OnTouchListener, + SurfaceHolder.Callback2 { @Override public void onLayoutChange( final View v, final int left, final int top, final int right, final int bottom, @@ -125,9 +138,24 @@ public abstract class WindowedAppActivity extends Activity { onWindowSurfaceLayoutChange(mAppContext, left, top, right, bottom); } } - } - private class WindowSurfaceHolderCallback implements SurfaceHolder.Callback2 { + @Override + public boolean onGenericMotion(final View view, final MotionEvent event) { + if (mAppContext == 0) { + return false; + } + return onWindowSurfaceMotionEvent(mAppContext, event); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouch(final View view, final MotionEvent event) { + if (mAppContext == 0) { + return false; + } + return onWindowSurfaceMotionEvent(mAppContext, event); + } + @Override public void surfaceCreated(final SurfaceHolder holder) { if (mAppContext == 0) { diff --git a/android/android_studio_project/app/src/main/res/layout/activity_gpu_trace_viewer.xml b/android/android_studio_project/app/src/main/res/layout/activity_gpu_trace_viewer.xml new file mode 100644 index 000000000..8e407ecdf --- /dev/null +++ b/android/android_studio_project/app/src/main/res/layout/activity_gpu_trace_viewer.xml @@ -0,0 +1,7 @@ + + diff --git a/android/android_studio_project/app/src/main/res/layout/activity_launcher.xml b/android/android_studio_project/app/src/main/res/layout/activity_launcher.xml new file mode 100644 index 000000000..15c5c3cc6 --- /dev/null +++ b/android/android_studio_project/app/src/main/res/layout/activity_launcher.xml @@ -0,0 +1,27 @@ + + + + + +