diff --git a/meson.build b/meson.build index 3638cf94..2eb76df8 100644 --- a/meson.build +++ b/meson.build @@ -82,11 +82,12 @@ libtranslationlayer_so = shared_library('translation_layer_main', [ 'src/api-impl-jni/android_graphics_Bitmap.c', 'src/api-impl-jni/android_app_NativeActivity.c', 'src/api-impl-jni/android_opengl_GLES20.c', + 'src/api-impl-jni/location/android_location_LocationManager.c', ] + marshal_files, install: true, install_dir : get_option('libdir') / 'java/dex/android_translation_layer/natives', dependencies: [ - dependency('gtk4'), dependency('gl'), dependency('egl'), dependency('wayland-client'), dependency('jni') + dependency('gtk4'), dependency('gl'), dependency('egl'), dependency('wayland-client'), dependency('jni'), dependency('libportal') ], link_with: [ libandroid_so ], link_args: [ diff --git a/src/api-impl-jni/generated_headers/android_location_LocationManager.h b/src/api-impl-jni/generated_headers/android_location_LocationManager.h new file mode 100644 index 00000000..6dea43c1 --- /dev/null +++ b/src/api-impl-jni/generated_headers/android_location_LocationManager.h @@ -0,0 +1,21 @@ +/* DO NOT EDIT THIS FILE - it is machine generated */ +#include +/* Header for class android_location_LocationManager */ + +#ifndef _Included_android_location_LocationManager +#define _Included_android_location_LocationManager +#ifdef __cplusplus +extern "C" { +#endif +/* + * Class: android_location_LocationManager + * Method: nativeGetLocation + * Signature: ()V + */ +JNIEXPORT void JNICALL Java_android_location_LocationManager_nativeGetLocation + (JNIEnv *, jobject); + +#ifdef __cplusplus +} +#endif +#endif diff --git a/src/api-impl-jni/location/android_location_LocationManager.c b/src/api-impl-jni/location/android_location_LocationManager.c new file mode 100644 index 00000000..175847cd --- /dev/null +++ b/src/api-impl-jni/location/android_location_LocationManager.c @@ -0,0 +1,35 @@ +#include + +#include "../defines.h" +#include "../generated_headers/android_location_LocationManager.h" + +static void location_updated ( + XdpPortal* self, + gdouble latitude, + gdouble longitude, + gdouble altitude, + gdouble accuracy, + gdouble speed, + gdouble heading, + gchar* description, + gint64 timestamp_s, + gint64 timestamp_ms, + JavaVM *jvm +) { + JNIEnv *env; + (*jvm)->GetEnv(jvm, (void**)&env, JNI_VERSION_1_6); + jclass class = (*env)->FindClass(env, "android/location/LocationManager"); + (*env)->CallStaticVoidMethod(env, class, _STATIC_METHOD(class, "locationUpdated", "(DDD)V"), latitude, longitude, heading); +} + +static XdpPortal *portal = NULL; + +JNIEXPORT void JNICALL Java_android_location_LocationManager_nativeGetLocation(JNIEnv *env, jobject) { + if (!portal) { + portal = xdp_portal_new(); + JavaVM *jvm; + (*env)->GetJavaVM(env, &jvm); + g_signal_connect(portal, "location-updated", G_CALLBACK(location_updated), jvm); + } + xdp_portal_location_monitor_start (portal, NULL, 0, 0, XDP_LOCATION_ACCURACY_EXACT, XDP_LOCATION_MONITOR_FLAG_NONE, NULL, NULL, NULL); +} diff --git a/src/api-impl/android/content/Context.java b/src/api-impl/android/content/Context.java index d5b690d4..167d78c7 100644 --- a/src/api-impl/android/content/Context.java +++ b/src/api-impl/android/content/Context.java @@ -20,6 +20,7 @@ import android.hardware.input.InputManager; import android.hardware.SensorManager; import android.hardware.display.DisplayManager; import android.hardware.usb.UsbManager; +import android.location.LocationManager; import android.media.AudioManager; import android.media.MediaRouter; import android.net.ConnectivityManager; @@ -131,6 +132,8 @@ public class Context extends Object { return new AlarmManager(); case "input": return new InputManager(); + case "location": + return new LocationManager(); default: System.out.println("!!!!!!! getSystemService: case >" + name + "< is not implemented yet"); return null; diff --git a/src/api-impl/android/hardware/Sensor.java b/src/api-impl/android/hardware/Sensor.java index ca95a9c5..b18330ef 100644 --- a/src/api-impl/android/hardware/Sensor.java +++ b/src/api-impl/android/hardware/Sensor.java @@ -327,7 +327,8 @@ public final class Sensor { private int mFifoReservedEventCount; private int mFifoMaxEventCount; - Sensor() { + Sensor(int type) { + mType = type; } /** diff --git a/src/api-impl/android/hardware/SensorEvent.java b/src/api-impl/android/hardware/SensorEvent.java new file mode 100644 index 00000000..a3950a20 --- /dev/null +++ b/src/api-impl/android/hardware/SensorEvent.java @@ -0,0 +1,11 @@ +package android.hardware; + +public class SensorEvent { + + public final float[] values; + + public SensorEvent(float[] values) { + this.values = values; + } + +} diff --git a/src/api-impl/android/hardware/SensorEventListener.java b/src/api-impl/android/hardware/SensorEventListener.java index 44b11155..579109d1 100644 --- a/src/api-impl/android/hardware/SensorEventListener.java +++ b/src/api-impl/android/hardware/SensorEventListener.java @@ -1,4 +1,6 @@ package android.hardware; public interface SensorEventListener { + + public void onSensorChanged(SensorEvent event); } diff --git a/src/api-impl/android/hardware/SensorManager.java b/src/api-impl/android/hardware/SensorManager.java index 3189da1a..1a33193d 100644 --- a/src/api-impl/android/hardware/SensorManager.java +++ b/src/api-impl/android/hardware/SensorManager.java @@ -1,13 +1,31 @@ package android.hardware; +import android.location.Location; +import android.location.LocationListener; +import android.location.LocationManager; import android.os.Handler; public class SensorManager { public Sensor getDefaultSensor(int type) { - return null; + return new Sensor(type); } 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 } + + public boolean registerListener(final SensorEventListener listener, Sensor sensor, int samplingPeriodUs) { + switch(sensor.getType()) { + case Sensor.TYPE_ORIENTATION: + new LocationManager().requestLocationUpdates(null, 0, 0, new LocationListener() { + @Override + public void onLocationChanged(Location location) { + listener.onSensorChanged(new SensorEvent(new float[]{(float)location.getBearing()})); + } + }); + return true; + default: + return false; + } + } } diff --git a/src/api-impl/android/location/Criteria.java b/src/api-impl/android/location/Criteria.java index 27c2c968..7c1fb388 100644 --- a/src/api-impl/android/location/Criteria.java +++ b/src/api-impl/android/location/Criteria.java @@ -12,4 +12,12 @@ public class Criteria { public static final int ACCURACY_HIGH = 3; public void setAccuracy(int accuracy) {} + + public void setAltitudeRequired(boolean required) {} + + public void setBearingRequired(boolean required) {} + + public void setCostAllowed(boolean allowed) {} + + public void setPowerRequirement(int powerRequirement) {} } diff --git a/src/api-impl/android/location/Location.java b/src/api-impl/android/location/Location.java new file mode 100644 index 00000000..7a9f95fb --- /dev/null +++ b/src/api-impl/android/location/Location.java @@ -0,0 +1,27 @@ +package android.location; + +public class Location { + + private double latitude; + private double longitude; + private double bearing; + + public Location (double latitude, double longitude, double bearing) { + this.latitude = latitude; + this.longitude = longitude; + this.bearing = bearing; + } + + public double getLatitude() { + return latitude; + } + + public double getLongitude() { + return longitude; + } + + public double getBearing() { + return bearing; + } + +} diff --git a/src/api-impl/android/location/LocationListener.java b/src/api-impl/android/location/LocationListener.java index 021547ef..f014e95f 100644 --- a/src/api-impl/android/location/LocationListener.java +++ b/src/api-impl/android/location/LocationListener.java @@ -1,4 +1,7 @@ package android.location; public interface LocationListener { + + public void onLocationChanged(Location location); + } diff --git a/src/api-impl/android/location/LocationManager.java b/src/api-impl/android/location/LocationManager.java new file mode 100644 index 00000000..c5b1c915 --- /dev/null +++ b/src/api-impl/android/location/LocationManager.java @@ -0,0 +1,31 @@ +package android.location; + +import java.util.HashSet; +import java.util.Set; + +public class LocationManager { + + static Set listeners = new HashSet<>(); + + public String getBestProvider(Criteria criteria, boolean enabledOnly) { + return "xdgportal"; + } + + public Location getLastKnownLocation(String provider) { + return null; + } + + public void requestLocationUpdates (String provider, long minTimeMs, float minDistanceM, LocationListener listener) { + listeners.add(listener); + nativeGetLocation(); + } + + private native void nativeGetLocation(); + + private static void locationUpdated(double latitude, double longitude, double heading) { + for (LocationListener locationListener : listeners) { + locationListener.onLocationChanged(new Location(latitude, longitude, heading)); + } + } + +} diff --git a/src/api-impl/meson.build b/src/api-impl/meson.build index a1d6c3e4..c3134342 100644 --- a/src/api-impl/meson.build +++ b/src/api-impl/meson.build @@ -98,12 +98,15 @@ hax_jar = jar('hax', [ 'android/graphics/drawable/Drawable.java', 'android/hardware/display/DisplayManager.java', 'android/hardware/input/InputManager.java', + 'android/hardware/SensorEvent.java', 'android/hardware/SensorEventListener.java', 'android/hardware/Sensor.java', 'android/hardware/SensorManager.java', 'android/hardware/usb/UsbManager.java', 'android/location/Criteria.java', + 'android/location/Location.java', 'android/location/LocationListener.java', + 'android/location/LocationManager.java', 'android/Manifest.java', 'android/media/AudioManager.java', 'android/media/AudioTrack.java',