implement some stuff to make exaple SDL app run

NOTE: the main addition in this commit is WIP support for apps which
render on an EGL surface obtained using ANativeWindow_fromSurface

currently, this EGL surface is obtained by creating a 700x700 pixel
window with GLFW (the 700x700 size is hardcoded in several places)
and only Wayland is supported

ideally, we'd want to use a wayland subsurface to position the EGL
surface above the Surface widget it's associated with (and do
whatever for X11)
This commit is contained in:
Mis012
2022-10-26 18:39:04 +02:00
parent 3627f35bd5
commit b801f0fb3c
26 changed files with 1552 additions and 161 deletions

View File

@@ -21,6 +21,7 @@ import java.io.StringReader;
public class Activity extends Context {
LayoutInflater layout_inflater;
Window window = new Window();
int requested_orientation = -1 /*ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED*/; // dummy
protected void set_window(long native_window) {
window.native_window = native_window;
@@ -49,6 +50,14 @@ public class Activity extends Context {
// return new Intent();
}
public int getRequestedOrientation() {
return requested_orientation;
}
public void setRequestedOrientation (int orientation) {
requested_orientation = orientation;
}
public boolean isFinishing() {
return false; // FIXME
}

View File

@@ -27,10 +27,12 @@ public class AlertDialog extends Dialog {
}
public AlertDialog.Builder setTitle (CharSequence title) {
System.out.println("AlertDialog.Builder setTitle called with: '"+title+"'");
return this;
}
public AlertDialog.Builder setMessage (CharSequence message) {
System.out.println("AlertDialog.Builder setMessage called with: '"+message+"'");
return this;
}

View File

@@ -3,10 +3,14 @@ package android.content;
import android.util.Log;
import android.content.pm.PackageManager;
import android.content.pm.ApplicationInfo;
import android.content.res.AssetManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.Intent;
import android.content.BroadcastReceiver;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.content.SharedPreferences;
@@ -23,6 +27,8 @@ import android.app.KeyguardManager;
import android.telephony.TelephonyManager;
import android.media.AudioManager;
import android.app.ActivityManager;
import android.hardware.usb.UsbManager;
import android.os.Vibrator;
import java.io.File;
import java.io.FileInputStream;
@@ -55,6 +61,10 @@ public class Context extends Object {
System.out.println("new Context! this one is: " + this);
}
public ApplicationInfo getApplicationInfo () {
return new ApplicationInfo();
}
public Context getApplicationContext() {
return (Context)this_application;
}
@@ -81,12 +91,20 @@ public class Context extends Object {
return new AudioManager();
case "activity":
return new ActivityManager();
case "usb":
return new UsbManager();
case "vibrator":
return new Vibrator();
default:
System.out.println("!!!!!!! getSystemService: case >"+name+"< is not implemented yet");
return null;
}
}
public Intent registerReceiver(BroadcastReceiver receiver, IntentFilter filter) {
return new Intent();
}
public Looper getMainLooper() {
System.out.println("returning the main Looper, most definitely doing just that!");
return new Looper();

View File

@@ -0,0 +1,5 @@
package android.content;
public class IntentFilter {
public void addAction(String action) {}
}

View File

@@ -339,7 +339,8 @@ public final class AssetManager {
}
}
throw new FileNotFoundException("Asset file: " + fileName);*/
return null; // FIXME
throw new IOException("FIXME: 'public final AssetFileDescriptor openFd(String fileName)': throwing an exception, which makes e.g SDL2 fall back to using something that we actually have implemented");
// return null; // FIXME
}
/**

View File

@@ -1,7 +1,13 @@
package android.hardware;
import android.os.Handler;
public class SensorManager {
public Sensor getDefaultSensor(int type) {
return null;
}
public boolean registerListener (SensorEventListener listener, Sensor sensor, int samplingPeriodUs, Handler handler) {
return true; // we could try saying that the sensor doesn't exist and hope the app just doesn't use it then, but as long as we never call the handler the app should leave this alone
}
}

View File

@@ -0,0 +1,9 @@
package android.hardware.usb;
import java.util.HashMap;
public class UsbManager {
public HashMap getDeviceList() {
return new HashMap();
}
}

View File

@@ -0,0 +1,5 @@
package android.os;
public class Vibrator {
}

View File

@@ -17,4 +17,8 @@ public final class Display {
public int getRotation() {
return 0/*ROTATION_0*/;
}
public float getRefreshRate() {
return 60; // FIXME
}
}

View File

@@ -0,0 +1,11 @@
package android.view;
public class InputDevice {
public static int[] getDeviceIds() {
return new int[]{0}; // might work?
}
public static InputDevice getDevice(int id) {
return null;
}
}

View File

@@ -18,8 +18,6 @@ package android.view;
import java.util.concurrent.atomic.AtomicInteger;
class InputDevice {}
/**
* Common base class for input events.
*/

View File

@@ -6,187 +6,191 @@ import android.graphics.Rect;
import android.content.Context;
public class SurfaceView extends View {
public SurfaceView(Context context) {
super(context);
// native_constructor(context);
native_constructor(context);
}
private native void native_constructor(Context context);
public SurfaceHolder getHolder() {
return mSurfaceHolder;
return mSurfaceHolder;
}
void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {}
final Surface mSurface = new Surface();
private final SurfaceHolder mSurfaceHolder = new SurfaceHolder() {
private static final String LOG_TAG = "SurfaceHolder";
private static final String LOG_TAG = "SurfaceHolder";
@Override
public boolean isCreating() {
// return mIsCreating;
@Override
public boolean isCreating() {
// return mIsCreating;
return false;
}
}
@Override
public void addCallback(Callback callback) {
/* synchronized (mCallbacks) {
// This is a linear search, but in practice we'll
// have only a couple callbacks, so it doesn't matter.
if (mCallbacks.contains(callback) == false) {
mCallbacks.add(callback);
}
}*/
}
@Override
public void addCallback(Callback callback) {
/* synchronized (mCallbacks) {
// This is a linear search, but in practice we'll
// have only a couple callbacks, so it doesn't matter.
if (mCallbacks.contains(callback) == false) {
mCallbacks.add(callback);
}
}*/
}
@Override
public void removeCallback(Callback callback) {
/* synchronized (mCallbacks) {
mCallbacks.remove(callback);
}*/
}
@Override
public void removeCallback(Callback callback) {
/* synchronized (mCallbacks) {
mCallbacks.remove(callback);
}*/
}
@Override
public void setFixedSize(int width, int height) {
/* if (mRequestedWidth != width || mRequestedHeight != height) {
mRequestedWidth = width;
mRequestedHeight = height;
requestLayout();
}*/
}
@Override
public void setFixedSize(int width, int height) {
/* if (mRequestedWidth != width || mRequestedHeight != height) {
mRequestedWidth = width;
mRequestedHeight = height;
requestLayout();
}*/
}
@Override
public void setSizeFromLayout() {
/* if (mRequestedWidth != -1 || mRequestedHeight != -1) {
mRequestedWidth = mRequestedHeight = -1;
requestLayout();
}*/
}
@Override
public void setSizeFromLayout() {
/* if (mRequestedWidth != -1 || mRequestedHeight != -1) {
mRequestedWidth = mRequestedHeight = -1;
requestLayout();
}*/
}
@Override
public void setFormat(int format) {
/*
// for backward compatibility reason, OPAQUE always
// means 565 for SurfaceView
if (format == PixelFormat.OPAQUE)
format = PixelFormat.RGB_565;
@Override
public void setFormat(int format) {
/*
// for backward compatibility reason, OPAQUE always
// means 565 for SurfaceView
if (format == PixelFormat.OPAQUE)
format = PixelFormat.RGB_565;
mRequestedFormat = format;
if (mWindow != null) {
updateWindow(false, false);
}*/
}
mRequestedFormat = format;
if (mWindow != null) {
updateWindow(false, false);
}*/
}
/**
* @deprecated setType is now ignored.
*/
@Override
@Deprecated
public void setType(int type) { }
/**
* @deprecated setType is now ignored.
*/
@Override
@Deprecated
public void setType(int type) { }
@Override
public void setKeepScreenOn(boolean screenOn) {
// Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
// msg.arg1 = screenOn ? 1 : 0;
// mHandler.sendMessage(msg);
}
@Override
public void setKeepScreenOn(boolean screenOn) {
// Message msg = mHandler.obtainMessage(KEEP_SCREEN_ON_MSG);
// msg.arg1 = screenOn ? 1 : 0;
// mHandler.sendMessage(msg);
}
/**
* Gets a {@link Canvas} for drawing into the SurfaceView's Surface
*
* After drawing into the provided {@link Canvas}, the caller must
* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
*
* The caller must redraw the entire surface.
* @return A canvas for drawing into the surface.
*/
@Override
public Canvas lockCanvas() {
// return internalLockCanvas(null);
/**
* Gets a {@link Canvas} for drawing into the SurfaceView's Surface
*
* After drawing into the provided {@link Canvas}, the caller must
* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
*
* The caller must redraw the entire surface.
* @return A canvas for drawing into the surface.
*/
@Override
public Canvas lockCanvas() {
// return internalLockCanvas(null);
return null;
}
}
/**
* Gets a {@link Canvas} for drawing into the SurfaceView's Surface
*
* After drawing into the provided {@link Canvas}, the caller must
* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
*
* @param inOutDirty A rectangle that represents the dirty region that the caller wants
* to redraw. This function may choose to expand the dirty rectangle if for example
* the surface has been resized or if the previous contents of the surface were
* not available. The caller must redraw the entire dirty region as represented
* by the contents of the inOutDirty rectangle upon return from this function.
* The caller may also pass <code>null</code> instead, in the case where the
* entire surface should be redrawn.
* @return A canvas for drawing into the surface.
*/
@Override
public Canvas lockCanvas(Rect inOutDirty) {
// return internalLockCanvas(inOutDirty);
/**
* Gets a {@link Canvas} for drawing into the SurfaceView's Surface
*
* After drawing into the provided {@link Canvas}, the caller must
* invoke {@link #unlockCanvasAndPost} to post the new contents to the surface.
*
* @param inOutDirty A rectangle that represents the dirty region that the caller wants
* to redraw. This function may choose to expand the dirty rectangle if for example
* the surface has been resized or if the previous contents of the surface were
* not available. The caller must redraw the entire dirty region as represented
* by the contents of the inOutDirty rectangle upon return from this function.
* The caller may also pass <code>null</code> instead, in the case where the
* entire surface should be redrawn.
* @return A canvas for drawing into the surface.
*/
@Override
public Canvas lockCanvas(Rect inOutDirty) {
// return internalLockCanvas(inOutDirty);
return null;
}
}
private final Canvas internalLockCanvas(Rect dirty) {
/* mSurfaceLock.lock();
private final Canvas internalLockCanvas(Rect dirty) {
/* mSurfaceLock.lock();
if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
+ mDrawingStopped + ", win=" + mWindow);
if (DEBUG) Log.i(TAG, "Locking canvas... stopped="
+ mDrawingStopped + ", win=" + mWindow);
Canvas c = null;
if (!mDrawingStopped && mWindow != null) {
try {
c = mSurface.lockCanvas(dirty);
} catch (Exception e) {
Log.e(LOG_TAG, "Exception locking surface", e);
}
}
Canvas c = null;
if (!mDrawingStopped && mWindow != null) {
try {
c = mSurface.lockCanvas(dirty);
} catch (Exception e) {
Log.e(LOG_TAG, "Exception locking surface", e);
}
}
if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
if (c != null) {
mLastLockTime = SystemClock.uptimeMillis();
return c;
}
if (DEBUG) Log.i(TAG, "Returned canvas: " + c);
if (c != null) {
mLastLockTime = SystemClock.uptimeMillis();
return c;
}
// If the Surface is not ready to be drawn, then return null,
// but throttle calls to this function so it isn't called more
// than every 100ms.
long now = SystemClock.uptimeMillis();
long nextTime = mLastLockTime + 100;
if (nextTime > now) {
try {
Thread.sleep(nextTime-now);
} catch (InterruptedException e) {
}
now = SystemClock.uptimeMillis();
}
mLastLockTime = now;
mSurfaceLock.unlock();
*/
return null;
}
/**
* Posts the new contents of the {@link Canvas} to the surface and
* releases the {@link Canvas}.
*
* @param canvas The canvas previously obtained from {@link #lockCanvas}.
*/
@Override
public void unlockCanvasAndPost(Canvas canvas) {
// mSurface.unlockCanvasAndPost(canvas);
// mSurfaceLock.unlock();
}
@Override
public Surface getSurface() {
return mSurface;
}
@Override
public Rect getSurfaceFrame() {
// return mSurfaceFrame;
// If the Surface is not ready to be drawn, then return null,
// but throttle calls to this function so it isn't called more
// than every 100ms.
long now = SystemClock.uptimeMillis();
long nextTime = mLastLockTime + 100;
if (nextTime > now) {
try {
Thread.sleep(nextTime-now);
} catch (InterruptedException e) {
}
now = SystemClock.uptimeMillis();
}
mLastLockTime = now;
mSurfaceLock.unlock();
*/
return null;
}
};
}
/**
* Posts the new contents of the {@link Canvas} to the surface and
* releases the {@link Canvas}.
*
* @param canvas The canvas previously obtained from {@link #lockCanvas}.
*/
@Override
public void unlockCanvasAndPost(Canvas canvas) {
// mSurface.unlockCanvasAndPost(canvas);
// mSurfaceLock.unlock();
}
@Override
public Surface getSurface() {
return mSurface;
}
@Override
public Rect getSurfaceFrame() {
// return mSurfaceFrame;
return null;
}
};
}

View File

@@ -525,6 +525,14 @@ public class View extends Object {
// TODO
}
public interface OnGenericMotionListener {
// TODO
}
public interface OnSystemUiVisibilityChangeListener {
// TODO
}
public static interface OnKeyListener {
// TODO
// boolean onKey(View v, int keyCode, KeyEvent event);
@@ -741,6 +749,7 @@ public class View extends Object {
public native void setGravity(int gravity);
public native void setOnTouchListener(OnTouchListener l);
public native void setOnClickListener(OnClickListener l);
public /*native*/ void setOnSystemUiVisibilityChangeListener(OnSystemUiVisibilityChangeListener l) {}
public native final int getWidth();
public native final int getHeight();

View File

@@ -28,5 +28,9 @@ public class Window {
set_widget_as_root(native_window, view.widget);
}
public View getDecorView() {
return new View(); // FIXME: this can probably backfire
}
private native void set_widget_as_root(long native_window, long widget);
}

View File

@@ -142,6 +142,7 @@ hax_jar = jar('hax', [
'android/view/WindowManager.java',
'android/view/ViewGroup.java',
'android/view/SurfaceHolder.java',
'android/view/InputDevice.java',
'android/view/InputEvent.java',
'android/view/View.java',
'android/view/LayoutInflater.java',
@@ -154,6 +155,7 @@ hax_jar = jar('hax', [
'android/hardware/SensorEventListener.java',
'android/hardware/Sensor.java',
'android/hardware/SensorManager.java',
'android/hardware/usb/UsbManager.java',
'android/text/TextUtils.java',
'android/text/Spannable.java',
'android/text/ClipboardManager.java',
@@ -173,6 +175,7 @@ hax_jar = jar('hax', [
'android/content/Context.java',
'android/content/ActivityNotFoundException.java',
'android/content/DialogInterface.java',
'android/content/IntentFilter.java',
'android/content/OperationApplicationException.java',
'android/content/res/ColorStateList.java',
'android/content/res/XmlResourceParser.java',