Skip to content

Commit

Permalink
android: V12 Update
Browse files Browse the repository at this point in the history
  • Loading branch information
Macdu committed Jun 6, 2024
1 parent fab31c8 commit a62e232
Show file tree
Hide file tree
Showing 18 changed files with 479 additions and 387 deletions.
466 changes: 233 additions & 233 deletions .github/workflows/c-cpp.yml

Large diffs are not rendered by default.

8 changes: 5 additions & 3 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ android {
namespace "org.vita3k.emulator"
compileSdk 34
ndkVersion "26.3.11579264"
buildToolsVersion "34.0.0"
buildFeatures {
buildConfig true
}

defaultConfig {
applicationId "org.vita3k.emulator"
minSdk 24
targetSdk 34
versionCode 11
versionName "0.2.0-11"
versionCode 12
versionName "0.2.0-12"

externalNativeBuild {
cmake {
Expand Down
19 changes: 16 additions & 3 deletions android/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,16 @@

<!-- Allow downloading to the external storage on Android 5.1 and older -->
<!-- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="22" /> -->
<!-- For android API <= 29 (Up to Android 10), use Legacy storage, otherwise use the MANAGE_EXTERNAL_STORAGE permission -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
android:maxSdkVersion="29" />
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission
android:name="android.permission.MANAGE_EXTERNAL_STORAGE"
android:minSdkVersion="30" />

<!-- Allow access to Bluetooth devices -->
<!-- Currently this is just for Steam Controller support and requires setting SDL_HINT_JOYSTICK_HIDAPI_STEAM -->
Expand All @@ -70,6 +77,8 @@
then replace "SDLActivity" with the name of your class (e.g. "MyGame")
in the XML below.
An example Java class can be found in README-android.md
The requestLegacyExternalStorage parameter only has an effect when running on Android <= 10
-->
<application android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
Expand All @@ -78,7 +87,9 @@
android:hardwareAccelerated="true"
android:appCategory="game"
android:isGame="true"
android:hasFragileUserData="true" tools:targetApi="q">
android:hasFragileUserData="true"
android:requestLegacyExternalStorage="true"
tools:targetApi="q">

<!-- Example of setting SDL hints from AndroidManifest.xml:
<meta-data android:name="SDL_ENV.SDL_ACCELEROMETER_AS_JOYSTICK" android:value="0"/>
Expand All @@ -89,8 +100,10 @@
android:launchMode="singleInstance"
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
android:preferMinimalPostProcessing="true"
android:theme="@style/Theme.Design.NoActionBar"
android:exported="true"
>
tools:targetApi="r">

<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
Expand Down
20 changes: 20 additions & 0 deletions android/src/main/java/org/vita3k/emulator/EmuSurface.java
Original file line number Diff line number Diff line change
@@ -1,14 +1,24 @@
package org.vita3k.emulator;

import android.content.Context;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.View;

import org.libsdl.app.SDLSurface;
import org.vita3k.emulator.overlay.InputOverlay;

public class EmuSurface extends SDLSurface {

private InputOverlay mOverlay;

public InputOverlay getmOverlay() {
return mOverlay;
}

public EmuSurface(Context context){
super(context);
mOverlay = new InputOverlay(context);
}

@Override
Expand All @@ -23,6 +33,16 @@ public void surfaceDestroyed(SurfaceHolder holder) {
super.surfaceDestroyed(holder);
}

@Override
public boolean onTouch(View v, MotionEvent event) {
if(mOverlay.onTouch(v, event)){
// priority is given to the overlay
return true;
}

return super.onTouch(v, event);
}

public native void setSurfaceStatus(boolean surface_present);

}
152 changes: 96 additions & 56 deletions android/src/main/java/org/vita3k/emulator/Emulator.java
Original file line number Diff line number Diff line change
@@ -1,28 +1,33 @@
package org.vita3k.emulator;


import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.system.ErrnoException;
import android.system.Os;
import android.view.Surface;
import android.view.ViewGroup;

import androidx.annotation.Keep;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.documentfile.provider.DocumentFile;

import com.jakewharton.processphoenix.ProcessPhoenix;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;

Expand All @@ -32,11 +37,11 @@

public class Emulator extends SDLActivity
{
private InputOverlay mOverlay;
private String currentGameId = "";
private EmuSurface mSurface;

public InputOverlay getInputOverlay(){
return mOverlay;
public InputOverlay getmOverlay() {
return mSurface.getmOverlay();
}

@Keep
Expand Down Expand Up @@ -69,17 +74,17 @@ protected String[] getLibraries() {
@Override
protected SDLSurface createSDLSurface(Context context) {
// Create the input overlay in the same time
mOverlay = new InputOverlay(this);
return new EmuSurface(context);
mSurface = new EmuSurface(context);
return mSurface;
}

@Override
protected void setupLayout(ViewGroup layout){
super.setupLayout(layout);
layout.addView(mOverlay);
layout.addView(getmOverlay());
}

static private String APP_RESTART_PARAMETERS = "AppStartParameters";
static private final String APP_RESTART_PARAMETERS = "AppStartParameters";

@Override
protected String[] getArguments() {
Expand Down Expand Up @@ -107,7 +112,7 @@ protected void onNewIntent(Intent intent){

@Keep
public void restartApp(String app_path, String exec_path, String exec_args){
ArrayList<String> args = new ArrayList<String>();
ArrayList<String> args = new ArrayList<>();

// first build the args given to Vita3K when it restarts
// this is similar to run_execv in main.cpp
Expand All @@ -134,17 +139,43 @@ public void restartApp(String app_path, String exec_path, String exec_args){
}

static final int FILE_DIALOG_CODE = 545;
static final int FOLDER_DIALOG_CODE = 546;
static final int STORAGE_MANAGER_DIALOG_CODE = 547;

@Keep
public void showFileDialog(){
public void showFileDialog() {
Intent intent = new Intent()
.setType("*/*")
.setAction(Intent.ACTION_GET_CONTENT);
.setAction(Intent.ACTION_GET_CONTENT)
.putExtra(Intent.EXTRA_LOCAL_ONLY, true);

intent = Intent.createChooser(intent, "Choose a file");
startActivityForResult(intent, FILE_DIALOG_CODE);
}

private boolean isStorageManagerEnabled(){
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) && Environment.isExternalStorageManager();
}

@Keep
public void showFolderDialog() {
// If running Android 10-, SDL should have already asked for read and write permissions
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || isStorageManagerEnabled()) {
Intent intent = new Intent()
.setAction(Intent.ACTION_OPEN_DOCUMENT_TREE)
.putExtra(Intent.EXTRA_LOCAL_ONLY, true);

intent = Intent.createChooser(intent, "Choose a folder");
startActivityForResult(intent, FOLDER_DIALOG_CODE);
} else {
Intent intent = new Intent()
.setAction(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION)
.setData(Uri.parse("package:" + BuildConfig.APPLICATION_ID));

startActivityForResult(intent, STORAGE_MANAGER_DIALOG_CODE);
}
}

private File getFileFromUri(Uri uri){
try {
InputStream inputStream = getContentResolver().openInputStream(uri);
Expand All @@ -166,75 +197,76 @@ private File getFileFromUri(Uri uri){
}
}

// from https://stackoverflow.com/questions/5568874/how-to-extract-the-file-name-from-uri-returned-from-intent-action-get-content
private String getFileName(Uri uri){
String result = null;
if(uri.getScheme().equals(ContentResolver.SCHEME_CONTENT)){
Cursor cursor = getContentResolver().query(uri, null, null, null, null);
try {
if(cursor != null && cursor.moveToFirst()){
int name_index = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
if(name_index >= 0)
result = cursor.getString(name_index);
}
} finally {
cursor.close();
}
}

if(result == null){
result = uri.getLastPathSegment();
}

return result;
}

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);

if(requestCode == FILE_DIALOG_CODE){
String result_path = "";
int result_fd = -1;
if(resultCode == RESULT_OK){
Uri result_uri = data.getData();
String filename = getFileName(result_uri);
String result_uri_string = result_uri.toString();
int result_fd = -1;
try {
AssetFileDescriptor asset_fd = getContentResolver().openAssetFileDescriptor(result_uri, "r");
// if the file is less than 64 KB, make a temporary copy
if(asset_fd.getLength() >= 64*1024) {
ParcelFileDescriptor file_descr = getContentResolver().openFileDescriptor(result_uri, "r");
result_fd = file_descr.detachFd();
try (AssetFileDescriptor asset_fd = getContentResolver().openAssetFileDescriptor(result_uri, "r")){
// if the file is less than 4 KB, make a temporary copy
if(asset_fd.getLength() >= 4*1024) {
try (ParcelFileDescriptor file_descr = getContentResolver().openFileDescriptor(result_uri, "r")) {
result_fd = file_descr.detachFd();
// in case the last call returns a ErrnoException
result_path = result_uri.toString();
result_path = Os.readlink("/proc/self/fd/" + result_fd);
}
} else {
File f = getFileFromUri(result_uri);
result_uri_string = f.getAbsolutePath();
result_path = f.getAbsolutePath();
}
} catch (ErrnoException | IOException e) {
}
}
filedialogReturn(result_path, result_fd);
} else if(requestCode == FOLDER_DIALOG_CODE){
String result_path = "";
if(resultCode == RESULT_OK){
Uri result_uri = data.getData();
DocumentFile tree = DocumentFile.fromTreeUri(getApplicationContext(), result_uri);
try(ParcelFileDescriptor file_descr = getContentResolver().openFileDescriptor(tree.getUri(), "r")) {
int result_fd = file_descr.getFd();

result_path = Os.readlink("/proc/self/fd/" + result_fd);
// replace /mnt/user/{id} with /storage
if(result_path.startsWith("/mnt/user/")){
result_path = result_path.substring("/mnt/user/".length());
result_path = "/storage" + result_path.substring(result_path.indexOf('/'));
}
} catch (FileNotFoundException e) {
} catch (ErrnoException | IOException e) {
}
filedialogReturn(result_uri_string, result_fd, filename);
} else if(resultCode == RESULT_CANCELED){
filedialogReturn("", -1, "");
}
filedialogReturn(result_path, 0);
} else if (requestCode == STORAGE_MANAGER_DIALOG_CODE) {
if (isStorageManagerEnabled()) {
showFolderDialog();
} else {
filedialogReturn("", -1);
}
}
}

@Keep
public void setControllerOverlayState(int overlay_mask, boolean edit, boolean reset){
mOverlay.setState(overlay_mask);
mOverlay.setIsInEditMode(edit);
getmOverlay().setState(overlay_mask);
getmOverlay().setIsInEditMode(edit);

if(reset)
mOverlay.resetButtonPlacement();
getmOverlay().resetButtonPlacement();
}

@Keep
public void setControllerOverlayScale(float scale){
mOverlay.setScale(scale);
getmOverlay().setScale(scale);
}

@Keep
public void setControllerOverlayOpacity(int opacity){
mOverlay.setOpacity(opacity);
getmOverlay().setOpacity(opacity);
}

@Keep
Expand Down Expand Up @@ -270,5 +302,13 @@ public boolean createShortcut(String game_id, String game_name){
return true;
}

public native void filedialogReturn(String result_uri, int result_fd, String filename);
@Keep
public boolean isDefaultOrientationLandscape() {
// we know the current device orientation is landscape
// so the default one is also landscape if and only if the rotation is 0 or 180
int rotation = getWindowManager().getDefaultDisplay().getRotation();
return rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180;
}

public native void filedialogReturn(String result_path, int result_fd);
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ public InputOverlay(Context context/*, AttributeSet attrs*/)
defaultOverlay();

// Set the on touch listener.
setOnTouchListener(this);
// Do not register the overlay as a touch listener
// Instead let EmuSurface forward touch events
// setOnTouchListener(this);

// Force draw
setWillNotDraw(false);
Expand All @@ -126,7 +128,7 @@ public InputOverlay(Context context/*, AttributeSet attrs*/)
@Override
public void run() {
Emulator emu = (Emulator) SDL.getContext();
emu.getInputOverlay().tick();
emu.getmOverlay().tick();
}
}, 1000, 1000);

Expand Down
Loading

0 comments on commit a62e232

Please # to comment.