mirror of
				https://github.com/godotengine/godot.git
				synced 2025-10-31 05:31:01 +00:00 
			
		
		
		
	Merge pull request #94799 from m4gr3d/memory_allocation_cleanup_and_optimizations
Android memory cleanup and optimizations
This commit is contained in:
		
						commit
						82adfebcf8
					
				
					 14 changed files with 626 additions and 188 deletions
				
			
		|  | @ -39,8 +39,6 @@ import android.content.res.Configuration | |||
| import android.content.res.Resources | ||||
| import android.graphics.Color | ||||
| import android.hardware.Sensor | ||||
| import android.hardware.SensorEvent | ||||
| import android.hardware.SensorEventListener | ||||
| import android.hardware.SensorManager | ||||
| import android.os.* | ||||
| import android.util.Log | ||||
|  | @ -53,6 +51,7 @@ import androidx.core.view.WindowInsetsAnimationCompat | |||
| import androidx.core.view.WindowInsetsCompat | ||||
| import com.google.android.vending.expansion.downloader.* | ||||
| import org.godotengine.godot.input.GodotEditText | ||||
| import org.godotengine.godot.input.GodotInputHandler | ||||
| import org.godotengine.godot.io.directory.DirectoryAccessHandler | ||||
| import org.godotengine.godot.io.file.FileAccessHandler | ||||
| import org.godotengine.godot.plugin.GodotPluginRegistry | ||||
|  | @ -73,6 +72,7 @@ import java.io.InputStream | |||
| import java.lang.Exception | ||||
| import java.security.MessageDigest | ||||
| import java.util.* | ||||
| import java.util.concurrent.atomic.AtomicBoolean | ||||
| import java.util.concurrent.atomic.AtomicReference | ||||
| 
 | ||||
| /** | ||||
|  | @ -81,7 +81,7 @@ import java.util.concurrent.atomic.AtomicReference | |||
|  * Can be hosted by [Activity], [Fragment] or [Service] android components, so long as its | ||||
|  * lifecycle methods are properly invoked. | ||||
|  */ | ||||
| class Godot(private val context: Context) : SensorEventListener { | ||||
| class Godot(private val context: Context) { | ||||
| 
 | ||||
| 	private companion object { | ||||
| 		private val TAG = Godot::class.java.simpleName | ||||
|  | @ -99,15 +99,23 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 	private val pluginRegistry: GodotPluginRegistry by lazy { | ||||
| 		GodotPluginRegistry.getPluginRegistry() | ||||
| 	} | ||||
| 
 | ||||
| 	private val accelerometer_enabled = AtomicBoolean(false) | ||||
| 	private val mAccelerometer: Sensor? by lazy { | ||||
| 		mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) | ||||
| 	} | ||||
| 
 | ||||
| 	private val gravity_enabled = AtomicBoolean(false) | ||||
| 	private val mGravity: Sensor? by lazy { | ||||
| 		mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) | ||||
| 	} | ||||
| 
 | ||||
| 	private val magnetometer_enabled = AtomicBoolean(false) | ||||
| 	private val mMagnetometer: Sensor? by lazy { | ||||
| 		mSensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD) | ||||
| 	} | ||||
| 
 | ||||
| 	private val gyroscope_enabled = AtomicBoolean(false) | ||||
| 	private val mGyroscope: Sensor? by lazy { | ||||
| 		mSensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE) | ||||
| 	} | ||||
|  | @ -127,6 +135,7 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 	val fileAccessHandler = FileAccessHandler(context) | ||||
| 	val netUtils = GodotNetUtils(context) | ||||
| 	private val commandLineFileParser = CommandLineFileParser() | ||||
| 	private val godotInputHandler = GodotInputHandler(context, this) | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Task to run when the engine terminates. | ||||
|  | @ -154,6 +163,17 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 	private var renderViewInitialized = false | ||||
| 	private var primaryHost: GodotHost? = null | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Tracks whether we're in the RESUMED lifecycle state. | ||||
| 	 * See [onResume] and [onPause] | ||||
| 	 */ | ||||
| 	private var resumed = false | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Tracks whether [onGodotSetupCompleted] fired. | ||||
| 	 */ | ||||
| 	private val godotMainLoopStarted = AtomicBoolean(false) | ||||
| 
 | ||||
| 	var io: GodotIO? = null | ||||
| 
 | ||||
| 	private var commandLine : MutableList<String> = ArrayList<String>() | ||||
|  | @ -416,10 +436,10 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 				if (!meetsVulkanRequirements(activity.packageManager)) { | ||||
| 					throw IllegalStateException(activity.getString(R.string.error_missing_vulkan_requirements_message)) | ||||
| 				} | ||||
| 				GodotVulkanRenderView(host, this) | ||||
| 				GodotVulkanRenderView(host, this, godotInputHandler) | ||||
| 			} else { | ||||
| 				// Fallback to openGl | ||||
| 				GodotGLRenderView(host, this, xrMode, useDebugOpengl) | ||||
| 				GodotGLRenderView(host, this, godotInputHandler, xrMode, useDebugOpengl) | ||||
| 			} | ||||
| 
 | ||||
| 			if (host == primaryHost) { | ||||
|  | @ -520,23 +540,13 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 
 | ||||
| 	fun onResume(host: GodotHost) { | ||||
| 		Log.v(TAG, "OnResume: $host") | ||||
| 		resumed = true | ||||
| 		if (host != primaryHost) { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		renderView?.onActivityResumed() | ||||
| 		if (mAccelerometer != null) { | ||||
| 			mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		if (mGravity != null) { | ||||
| 			mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		if (mMagnetometer != null) { | ||||
| 			mSensorManager.registerListener(this, mMagnetometer, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		if (mGyroscope != null) { | ||||
| 			mSensorManager.registerListener(this, mGyroscope, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		registerSensorsIfNeeded() | ||||
| 		if (useImmersive) { | ||||
| 			val window = requireActivity().window | ||||
| 			window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or | ||||
|  | @ -551,14 +561,34 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private fun registerSensorsIfNeeded() { | ||||
| 		if (!resumed || !godotMainLoopStarted.get()) { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		if (accelerometer_enabled.get() && mAccelerometer != null) { | ||||
| 			mSensorManager.registerListener(godotInputHandler, mAccelerometer, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		if (gravity_enabled.get() && mGravity != null) { | ||||
| 			mSensorManager.registerListener(godotInputHandler, mGravity, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		if (magnetometer_enabled.get() && mMagnetometer != null) { | ||||
| 			mSensorManager.registerListener(godotInputHandler, mMagnetometer, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 		if (gyroscope_enabled.get() && mGyroscope != null) { | ||||
| 			mSensorManager.registerListener(godotInputHandler, mGyroscope, SensorManager.SENSOR_DELAY_GAME) | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fun onPause(host: GodotHost) { | ||||
| 		Log.v(TAG, "OnPause: $host") | ||||
| 		resumed = false | ||||
| 		if (host != primaryHost) { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		renderView?.onActivityPaused() | ||||
| 		mSensorManager.unregisterListener(this) | ||||
| 		mSensorManager.unregisterListener(godotInputHandler) | ||||
| 		for (plugin in pluginRegistry.allPlugins) { | ||||
| 			plugin.onMainPause() | ||||
| 		} | ||||
|  | @ -659,6 +689,16 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 	 */ | ||||
| 	private fun onGodotMainLoopStarted() { | ||||
| 		Log.v(TAG, "OnGodotMainLoopStarted") | ||||
| 		godotMainLoopStarted.set(true) | ||||
| 
 | ||||
| 		accelerometer_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_accelerometer"))) | ||||
| 		gravity_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_gravity"))) | ||||
| 		gyroscope_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_gyroscope"))) | ||||
| 		magnetometer_enabled.set(java.lang.Boolean.parseBoolean(GodotLib.getGlobal("input_devices/sensors/enable_magnetometer"))) | ||||
| 
 | ||||
| 		runOnUiThread { | ||||
| 			registerSensorsIfNeeded() | ||||
| 		} | ||||
| 
 | ||||
| 		for (plugin in pluginRegistry.allPlugins) { | ||||
| 			plugin.onGodotMainLoopStarted() | ||||
|  | @ -858,77 +898,6 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	private fun getRotatedValues(values: FloatArray?): FloatArray? { | ||||
| 		if (values == null || values.size != 3) { | ||||
| 			return null | ||||
| 		} | ||||
| 		val rotatedValues = FloatArray(3) | ||||
| 		when (windowManager.defaultDisplay.rotation) { | ||||
| 			Surface.ROTATION_0 -> { | ||||
| 				rotatedValues[0] = values[0] | ||||
| 				rotatedValues[1] = values[1] | ||||
| 				rotatedValues[2] = values[2] | ||||
| 			} | ||||
| 			Surface.ROTATION_90 -> { | ||||
| 				rotatedValues[0] = -values[1] | ||||
| 				rotatedValues[1] = values[0] | ||||
| 				rotatedValues[2] = values[2] | ||||
| 			} | ||||
| 			Surface.ROTATION_180 -> { | ||||
| 				rotatedValues[0] = -values[0] | ||||
| 				rotatedValues[1] = -values[1] | ||||
| 				rotatedValues[2] = values[2] | ||||
| 			} | ||||
| 			Surface.ROTATION_270 -> { | ||||
| 				rotatedValues[0] = values[1] | ||||
| 				rotatedValues[1] = -values[0] | ||||
| 				rotatedValues[2] = values[2] | ||||
| 			} | ||||
| 		} | ||||
| 		return rotatedValues | ||||
| 	} | ||||
| 
 | ||||
| 	override fun onSensorChanged(event: SensorEvent) { | ||||
| 		if (renderView == null) { | ||||
| 			return | ||||
| 		} | ||||
| 
 | ||||
| 		val rotatedValues = getRotatedValues(event.values) | ||||
| 
 | ||||
| 		when (event.sensor.type) { | ||||
| 			Sensor.TYPE_ACCELEROMETER -> { | ||||
| 				rotatedValues?.let { | ||||
| 					renderView?.queueOnRenderThread { | ||||
| 						GodotLib.accelerometer(-it[0], -it[1], -it[2]) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			Sensor.TYPE_GRAVITY -> { | ||||
| 				rotatedValues?.let { | ||||
| 					renderView?.queueOnRenderThread { | ||||
| 						GodotLib.gravity(-it[0], -it[1], -it[2]) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			Sensor.TYPE_MAGNETIC_FIELD -> { | ||||
| 				rotatedValues?.let { | ||||
| 					renderView?.queueOnRenderThread { | ||||
| 						GodotLib.magnetometer(-it[0], -it[1], -it[2]) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			Sensor.TYPE_GYROSCOPE -> { | ||||
| 				rotatedValues?.let { | ||||
| 					renderView?.queueOnRenderThread { | ||||
| 						GodotLib.gyroscope(it[0], it[1], it[2]) | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Used by the native code (java_godot_wrapper.h) to vibrate the device. | ||||
| 	 * @param durationMs | ||||
|  | @ -1063,7 +1032,7 @@ class Godot(private val context: Context) : SensorEventListener { | |||
| 
 | ||||
| 	@Keep | ||||
| 	private fun initInputDevices() { | ||||
| 		renderView?.initInputDevices() | ||||
| 		godotInputHandler.initInputDevices() | ||||
| 	} | ||||
| 
 | ||||
| 	@Keep | ||||
|  |  | |||
|  | @ -83,12 +83,12 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView { | |||
| 	private final GodotRenderer godotRenderer; | ||||
| 	private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>(); | ||||
| 
 | ||||
| 	public GodotGLRenderView(GodotHost host, Godot godot, XRMode xrMode, boolean useDebugOpengl) { | ||||
| 	public GodotGLRenderView(GodotHost host, Godot godot, GodotInputHandler inputHandler, XRMode xrMode, boolean useDebugOpengl) { | ||||
| 		super(host.getActivity()); | ||||
| 
 | ||||
| 		this.host = host; | ||||
| 		this.godot = godot; | ||||
| 		this.inputHandler = new GodotInputHandler(this); | ||||
| 		this.inputHandler = inputHandler; | ||||
| 		this.godotRenderer = new GodotRenderer(); | ||||
| 		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||||
| 			setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT)); | ||||
|  | @ -101,11 +101,6 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView { | |||
| 		return this; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void initInputDevices() { | ||||
| 		this.inputHandler.initInputDevices(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void queueOnRenderThread(Runnable event) { | ||||
| 		queueEvent(event); | ||||
|  | @ -144,11 +139,6 @@ class GodotGLRenderView extends GLSurfaceView implements GodotRenderView { | |||
| 		requestRenderThreadExitAndWait(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onBackPressed() { | ||||
| 		godot.onBackPressed(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public GodotInputHandler getInputHandler() { | ||||
| 		return inputHandler; | ||||
|  |  | |||
|  | @ -37,8 +37,6 @@ import android.view.SurfaceView; | |||
| public interface GodotRenderView { | ||||
| 	SurfaceView getView(); | ||||
| 
 | ||||
| 	void initInputDevices(); | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Starts the thread that will drive Godot's rendering. | ||||
| 	 */ | ||||
|  | @ -59,8 +57,6 @@ public interface GodotRenderView { | |||
| 
 | ||||
| 	void onActivityDestroyed(); | ||||
| 
 | ||||
| 	void onBackPressed(); | ||||
| 
 | ||||
| 	GodotInputHandler getInputHandler(); | ||||
| 
 | ||||
| 	void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY); | ||||
|  |  | |||
|  | @ -57,12 +57,12 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { | |||
| 	private final VkRenderer mRenderer; | ||||
| 	private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>(); | ||||
| 
 | ||||
| 	public GodotVulkanRenderView(GodotHost host, Godot godot) { | ||||
| 	public GodotVulkanRenderView(GodotHost host, Godot godot, GodotInputHandler inputHandler) { | ||||
| 		super(host.getActivity()); | ||||
| 
 | ||||
| 		this.host = host; | ||||
| 		this.godot = godot; | ||||
| 		mInputHandler = new GodotInputHandler(this); | ||||
| 		mInputHandler = inputHandler; | ||||
| 		mRenderer = new VkRenderer(); | ||||
| 		if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { | ||||
| 			setPointerIcon(PointerIcon.getSystemIcon(getContext(), PointerIcon.TYPE_DEFAULT)); | ||||
|  | @ -80,11 +80,6 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { | |||
| 		return this; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void initInputDevices() { | ||||
| 		mInputHandler.initInputDevices(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void queueOnRenderThread(Runnable event) { | ||||
| 		queueOnVkThread(event); | ||||
|  | @ -123,11 +118,6 @@ class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { | |||
| 		requestRenderThreadExitAndWait(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onBackPressed() { | ||||
| 		godot.onBackPressed(); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public GodotInputHandler getInputHandler() { | ||||
| 		return mInputHandler; | ||||
|  |  | |||
|  | @ -32,10 +32,14 @@ package org.godotengine.godot.input; | |||
| 
 | ||||
| import static org.godotengine.godot.utils.GLUtils.DEBUG; | ||||
| 
 | ||||
| import org.godotengine.godot.Godot; | ||||
| import org.godotengine.godot.GodotLib; | ||||
| import org.godotengine.godot.GodotRenderView; | ||||
| 
 | ||||
| import android.content.Context; | ||||
| import android.hardware.Sensor; | ||||
| import android.hardware.SensorEvent; | ||||
| import android.hardware.SensorEventListener; | ||||
| import android.hardware.input.InputManager; | ||||
| import android.os.Build; | ||||
| import android.util.Log; | ||||
|  | @ -46,6 +50,10 @@ import android.view.InputDevice; | |||
| import android.view.KeyEvent; | ||||
| import android.view.MotionEvent; | ||||
| import android.view.ScaleGestureDetector; | ||||
| import android.view.Surface; | ||||
| import android.view.WindowManager; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| 
 | ||||
| import java.util.Collections; | ||||
| import java.util.HashSet; | ||||
|  | @ -54,7 +62,7 @@ import java.util.Set; | |||
| /** | ||||
|  * Handles input related events for the {@link GodotRenderView} view. | ||||
|  */ | ||||
| public class GodotInputHandler implements InputManager.InputDeviceListener { | ||||
| public class GodotInputHandler implements InputManager.InputDeviceListener, SensorEventListener { | ||||
| 	private static final String TAG = GodotInputHandler.class.getSimpleName(); | ||||
| 
 | ||||
| 	private static final int ROTARY_INPUT_VERTICAL_AXIS = 1; | ||||
|  | @ -64,8 +72,9 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 	private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4); | ||||
| 	private final HashSet<Integer> mHardwareKeyboardIds = new HashSet<>(); | ||||
| 
 | ||||
| 	private final GodotRenderView mRenderView; | ||||
| 	private final Godot godot; | ||||
| 	private final InputManager mInputManager; | ||||
| 	private final WindowManager windowManager; | ||||
| 	private final GestureDetector gestureDetector; | ||||
| 	private final ScaleGestureDetector scaleGestureDetector; | ||||
| 	private final GodotGestureHandler godotGestureHandler; | ||||
|  | @ -77,12 +86,13 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 
 | ||||
| 	private int rotaryInputAxis = ROTARY_INPUT_VERTICAL_AXIS; | ||||
| 
 | ||||
| 	public GodotInputHandler(GodotRenderView godotView) { | ||||
| 		final Context context = godotView.getView().getContext(); | ||||
| 		mRenderView = godotView; | ||||
| 	public GodotInputHandler(Context context, Godot godot) { | ||||
| 		this.godot = godot; | ||||
| 		mInputManager = (InputManager)context.getSystemService(Context.INPUT_SERVICE); | ||||
| 		mInputManager.registerInputDeviceListener(this, null); | ||||
| 
 | ||||
| 		windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE); | ||||
| 
 | ||||
| 		this.godotGestureHandler = new GodotGestureHandler(this); | ||||
| 		this.gestureDetector = new GestureDetector(context, godotGestureHandler); | ||||
| 		this.gestureDetector.setIsLongpressEnabled(false); | ||||
|  | @ -174,7 +184,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 
 | ||||
| 	public boolean onKeyDown(final int keyCode, KeyEvent event) { | ||||
| 		if (keyCode == KeyEvent.KEYCODE_BACK) { | ||||
| 			mRenderView.onBackPressed(); | ||||
| 			godot.onBackPressed(); | ||||
| 			// press 'back' button should not terminate program | ||||
| 			//normal handle 'back' event in game logic | ||||
| 			return true; | ||||
|  | @ -507,7 +517,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 		return handleTouchEvent(event, eventActionOverride, doubleTap); | ||||
| 	} | ||||
| 
 | ||||
| 	private static float getEventTiltX(MotionEvent event) { | ||||
| 	static float getEventTiltX(MotionEvent event) { | ||||
| 		// Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise. | ||||
| 		final float orientation = event.getOrientation(); | ||||
| 
 | ||||
|  | @ -520,7 +530,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 		return (float)-Math.sin(orientation) * tiltMult; | ||||
| 	} | ||||
| 
 | ||||
| 	private static float getEventTiltY(MotionEvent event) { | ||||
| 	static float getEventTiltY(MotionEvent event) { | ||||
| 		// Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise. | ||||
| 		final float orientation = event.getOrientation(); | ||||
| 
 | ||||
|  | @ -579,6 +589,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 	} | ||||
| 
 | ||||
| 	boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) { | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return false; | ||||
| 		} | ||||
| 
 | ||||
| 		// Fix the buttonsMask | ||||
| 		switch (eventAction) { | ||||
| 			case MotionEvent.ACTION_CANCEL: | ||||
|  | @ -594,7 +609,6 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		final int updatedButtonsMask = buttonsMask; | ||||
| 		// We don't handle ACTION_BUTTON_PRESS and ACTION_BUTTON_RELEASE events as they typically | ||||
| 		// follow ACTION_DOWN and ACTION_UP events. As such, handling them would result in duplicate | ||||
| 		// stream of events to the engine. | ||||
|  | @ -607,11 +621,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 			case MotionEvent.ACTION_HOVER_MOVE: | ||||
| 			case MotionEvent.ACTION_MOVE: | ||||
| 			case MotionEvent.ACTION_SCROLL: { | ||||
| 				if (shouldDispatchInputToRenderThread()) { | ||||
| 					mRenderView.queueOnRenderThread(() -> GodotLib.dispatchMouseEvent(eventAction, updatedButtonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY)); | ||||
| 				} else { | ||||
| 					GodotLib.dispatchMouseEvent(eventAction, updatedButtonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY); | ||||
| 				} | ||||
| 				runnable.setMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY); | ||||
| 				dispatchInputEventRunnable(runnable); | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
|  | @ -627,22 +638,14 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 	} | ||||
| 
 | ||||
| 	boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) { | ||||
| 		final int pointerCount = event.getPointerCount(); | ||||
| 		if (pointerCount == 0) { | ||||
| 		if (event.getPointerCount() == 0) { | ||||
| 			return true; | ||||
| 		} | ||||
| 
 | ||||
| 		final float[] positions = new float[pointerCount * 6]; // pointerId1, x1, y1, pressure1, tiltX1, tiltY1, pointerId2, etc... | ||||
| 
 | ||||
| 		for (int i = 0; i < pointerCount; i++) { | ||||
| 			positions[i * 6 + 0] = event.getPointerId(i); | ||||
| 			positions[i * 6 + 1] = event.getX(i); | ||||
| 			positions[i * 6 + 2] = event.getY(i); | ||||
| 			positions[i * 6 + 3] = event.getPressure(i); | ||||
| 			positions[i * 6 + 4] = getEventTiltX(event); | ||||
| 			positions[i * 6 + 5] = getEventTiltY(event); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return false; | ||||
| 		} | ||||
| 		final int actionPointerId = event.getPointerId(event.getActionIndex()); | ||||
| 
 | ||||
| 		switch (eventActionOverride) { | ||||
| 			case MotionEvent.ACTION_DOWN: | ||||
|  | @ -651,11 +654,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 			case MotionEvent.ACTION_MOVE: | ||||
| 			case MotionEvent.ACTION_POINTER_UP: | ||||
| 			case MotionEvent.ACTION_POINTER_DOWN: { | ||||
| 				if (shouldDispatchInputToRenderThread()) { | ||||
| 					mRenderView.queueOnRenderThread(() -> GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap)); | ||||
| 				} else { | ||||
| 					GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap); | ||||
| 				} | ||||
| 				runnable.setTouchEvent(event, eventActionOverride, doubleTap); | ||||
| 				dispatchInputEventRunnable(runnable); | ||||
| 				return true; | ||||
| 			} | ||||
| 		} | ||||
|  | @ -663,58 +663,128 @@ public class GodotInputHandler implements InputManager.InputDeviceListener { | |||
| 	} | ||||
| 
 | ||||
| 	void handleMagnifyEvent(float x, float y, float factor) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.magnify(x, y, factor)); | ||||
| 		} else { | ||||
| 			GodotLib.magnify(x, y, factor); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setMagnifyEvent(x, y, factor); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	void handlePanEvent(float x, float y, float deltaX, float deltaY) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.pan(x, y, deltaX, deltaY)); | ||||
| 		} else { | ||||
| 			GodotLib.pan(x, y, deltaX, deltaY); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setPanEvent(x, y, deltaX, deltaY); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	private void handleJoystickButtonEvent(int device, int button, boolean pressed) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.joybutton(device, button, pressed)); | ||||
| 		} else { | ||||
| 			GodotLib.joybutton(device, button, pressed); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setJoystickButtonEvent(device, button, pressed); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	private void handleJoystickAxisEvent(int device, int axis, float value) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.joyaxis(device, axis, value)); | ||||
| 		} else { | ||||
| 			GodotLib.joyaxis(device, axis, value); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setJoystickAxisEvent(device, axis, value); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	private void handleJoystickHatEvent(int device, int hatX, int hatY) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.joyhat(device, hatX, hatY)); | ||||
| 		} else { | ||||
| 			GodotLib.joyhat(device, hatX, hatY); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setJoystickHatEvent(device, hatX, hatY); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	private void handleJoystickConnectionChangedEvent(int device, boolean connected, String name) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.joyconnectionchanged(device, connected, name)); | ||||
| 		} else { | ||||
| 			GodotLib.joyconnectionchanged(device, connected, name); | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setJoystickConnectionChangedEvent(device, connected, name); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	void handleKeyEvent(int physicalKeycode, int unicode, int keyLabel, boolean pressed, boolean echo) { | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setKeyEvent(physicalKeycode, unicode, keyLabel, pressed, echo); | ||||
| 		dispatchInputEventRunnable(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	private void dispatchInputEventRunnable(@NonNull InputEventRunnable runnable) { | ||||
| 		if (shouldDispatchInputToRenderThread()) { | ||||
| 			mRenderView.queueOnRenderThread(() -> GodotLib.key(physicalKeycode, unicode, keyLabel, pressed, echo)); | ||||
| 			godot.runOnRenderThread(runnable); | ||||
| 		} else { | ||||
| 			GodotLib.key(physicalKeycode, unicode, keyLabel, pressed, echo); | ||||
| 			runnable.run(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onSensorChanged(SensorEvent event) { | ||||
| 		final float[] values = event.values; | ||||
| 		if (values == null || values.length != 3) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		InputEventRunnable runnable = InputEventRunnable.obtain(); | ||||
| 		if (runnable == null) { | ||||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		float rotatedValue0 = 0f; | ||||
| 		float rotatedValue1 = 0f; | ||||
| 		float rotatedValue2 = 0f; | ||||
| 		switch (windowManager.getDefaultDisplay().getRotation()) { | ||||
| 			case Surface.ROTATION_0: | ||||
| 				rotatedValue0 = values[0]; | ||||
| 				rotatedValue1 = values[1]; | ||||
| 				rotatedValue2 = values[2]; | ||||
| 				break; | ||||
| 
 | ||||
| 			case Surface.ROTATION_90: | ||||
| 				rotatedValue0 = -values[1]; | ||||
| 				rotatedValue1 = values[0]; | ||||
| 				rotatedValue2 = values[2]; | ||||
| 				break; | ||||
| 
 | ||||
| 			case Surface.ROTATION_180: | ||||
| 				rotatedValue0 = -values[0]; | ||||
| 				rotatedValue1 = -values[1]; | ||||
| 				rotatedValue2 = values[2]; | ||||
| 				break; | ||||
| 
 | ||||
| 			case Surface.ROTATION_270: | ||||
| 				rotatedValue0 = values[1]; | ||||
| 				rotatedValue1 = -values[0]; | ||||
| 				rotatedValue2 = values[2]; | ||||
| 				break; | ||||
| 		} | ||||
| 
 | ||||
| 		runnable.setSensorEvent(event.sensor.getType(), rotatedValue0, rotatedValue1, rotatedValue2); | ||||
| 		godot.runOnRenderThread(runnable); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void onAccuracyChanged(Sensor sensor, int accuracy) {} | ||||
| } | ||||
|  |  | |||
|  | @ -0,0 +1,353 @@ | |||
| /**************************************************************************/ | ||||
| /*  InputEventRunnable.java                                               */ | ||||
| /**************************************************************************/ | ||||
| /*                         This file is part of:                          */ | ||||
| /*                             GODOT ENGINE                               */ | ||||
| /*                        https://godotengine.org                         */ | ||||
| /**************************************************************************/ | ||||
| /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ | ||||
| /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.                  */ | ||||
| /*                                                                        */ | ||||
| /* Permission is hereby granted, free of charge, to any person obtaining  */ | ||||
| /* a copy of this software and associated documentation files (the        */ | ||||
| /* "Software"), to deal in the Software without restriction, including    */ | ||||
| /* without limitation the rights to use, copy, modify, merge, publish,    */ | ||||
| /* distribute, sublicense, and/or sell copies of the Software, and to     */ | ||||
| /* permit persons to whom the Software is furnished to do so, subject to  */ | ||||
| /* the following conditions:                                              */ | ||||
| /*                                                                        */ | ||||
| /* The above copyright notice and this permission notice shall be         */ | ||||
| /* included in all copies or substantial portions of the Software.        */ | ||||
| /*                                                                        */ | ||||
| /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,        */ | ||||
| /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF     */ | ||||
| /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ | ||||
| /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY   */ | ||||
| /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,   */ | ||||
| /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE      */ | ||||
| /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                 */ | ||||
| /**************************************************************************/ | ||||
| 
 | ||||
| package org.godotengine.godot.input; | ||||
| 
 | ||||
| import org.godotengine.godot.GodotLib; | ||||
| 
 | ||||
| import android.hardware.Sensor; | ||||
| import android.util.Log; | ||||
| import android.view.MotionEvent; | ||||
| 
 | ||||
| import androidx.annotation.NonNull; | ||||
| import androidx.annotation.Nullable; | ||||
| import androidx.core.util.Pools; | ||||
| 
 | ||||
| import java.util.concurrent.ArrayBlockingQueue; | ||||
| import java.util.concurrent.atomic.AtomicInteger; | ||||
| 
 | ||||
| /** | ||||
|  * Used to dispatch input events. | ||||
|  * | ||||
|  * This is a specialized version of @{@link Runnable} which allows to allocate a finite pool of | ||||
|  * objects for input events dispatching, thus avoid the creation (and garbage collection) of | ||||
|  * spurious @{@link Runnable} objects. | ||||
|  */ | ||||
| final class InputEventRunnable implements Runnable { | ||||
| 	private static final String TAG = InputEventRunnable.class.getSimpleName(); | ||||
| 
 | ||||
| 	private static final int MAX_TOUCH_POINTER_COUNT = 10; // assuming 10 fingers as max supported concurrent touch pointers | ||||
| 
 | ||||
| 	private static final Pools.Pool<InputEventRunnable> POOL = new Pools.Pool<>() { | ||||
| 		private static final int MAX_POOL_SIZE = 120 * 10; // up to 120Hz input events rate for up to 5 secs (ANR limit) * 2 | ||||
| 
 | ||||
| 		private final ArrayBlockingQueue<InputEventRunnable> queue = new ArrayBlockingQueue<>(MAX_POOL_SIZE); | ||||
| 		private final AtomicInteger createdCount = new AtomicInteger(); | ||||
| 
 | ||||
| 		@Nullable | ||||
| 		@Override | ||||
| 		public InputEventRunnable acquire() { | ||||
| 			InputEventRunnable instance = queue.poll(); | ||||
| 			if (instance == null) { | ||||
| 				int creationCount = createdCount.incrementAndGet(); | ||||
| 				if (creationCount <= MAX_POOL_SIZE) { | ||||
| 					instance = new InputEventRunnable(creationCount - 1); | ||||
| 				} | ||||
| 			} | ||||
| 
 | ||||
| 			return instance; | ||||
| 		} | ||||
| 
 | ||||
| 		@Override | ||||
| 		public boolean release(@NonNull InputEventRunnable instance) { | ||||
| 			return queue.offer(instance); | ||||
| 		} | ||||
| 	}; | ||||
| 
 | ||||
| 	@Nullable | ||||
| 	static InputEventRunnable obtain() { | ||||
| 		InputEventRunnable runnable = POOL.acquire(); | ||||
| 		if (runnable == null) { | ||||
| 			Log.w(TAG, "Input event pool is at capacity"); | ||||
| 		} | ||||
| 		return runnable; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Used to track when this instance was created and added to the pool. Primarily used for | ||||
| 	 * debug purposes. | ||||
| 	 */ | ||||
| 	private final int creationRank; | ||||
| 
 | ||||
| 	private InputEventRunnable(int creationRank) { | ||||
| 		this.creationRank = creationRank; | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Set of supported input events. | ||||
| 	 */ | ||||
| 	private enum EventType { | ||||
| 		MOUSE, | ||||
| 		TOUCH, | ||||
| 		MAGNIFY, | ||||
| 		PAN, | ||||
| 		JOYSTICK_BUTTON, | ||||
| 		JOYSTICK_AXIS, | ||||
| 		JOYSTICK_HAT, | ||||
| 		JOYSTICK_CONNECTION_CHANGED, | ||||
| 		KEY, | ||||
| 		SENSOR | ||||
| 	} | ||||
| 
 | ||||
| 	private EventType currentEventType = null; | ||||
| 
 | ||||
| 	// common event fields | ||||
| 	private float eventX; | ||||
| 	private float eventY; | ||||
| 	private float eventDeltaX; | ||||
| 	private float eventDeltaY; | ||||
| 	private boolean eventPressed; | ||||
| 
 | ||||
| 	// common touch / mouse fields | ||||
| 	private int eventAction; | ||||
| 	private boolean doubleTap; | ||||
| 
 | ||||
| 	// Mouse event fields and setter | ||||
| 	private int buttonsMask; | ||||
| 	private boolean sourceMouseRelative; | ||||
| 	private float pressure; | ||||
| 	private float tiltX; | ||||
| 	private float tiltY; | ||||
| 	void setMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) { | ||||
| 		this.currentEventType = EventType.MOUSE; | ||||
| 		this.eventAction = eventAction; | ||||
| 		this.buttonsMask = buttonsMask; | ||||
| 		this.eventX = x; | ||||
| 		this.eventY = y; | ||||
| 		this.eventDeltaX = deltaX; | ||||
| 		this.eventDeltaY = deltaY; | ||||
| 		this.doubleTap = doubleClick; | ||||
| 		this.sourceMouseRelative = sourceMouseRelative; | ||||
| 		this.pressure = pressure; | ||||
| 		this.tiltX = tiltX; | ||||
| 		this.tiltY = tiltY; | ||||
| 	} | ||||
| 
 | ||||
| 	// Touch event fields and setter | ||||
| 	private int actionPointerId; | ||||
| 	private int pointerCount; | ||||
| 	private final float[] positions = new float[MAX_TOUCH_POINTER_COUNT * 6]; // pointerId1, x1, y1, pressure1, tiltX1, tiltY1, pointerId2, etc... | ||||
| 	void setTouchEvent(MotionEvent event, int eventAction, boolean doubleTap) { | ||||
| 		this.currentEventType = EventType.TOUCH; | ||||
| 		this.eventAction = eventAction; | ||||
| 		this.doubleTap = doubleTap; | ||||
| 		this.actionPointerId = event.getPointerId(event.getActionIndex()); | ||||
| 		this.pointerCount = Math.min(event.getPointerCount(), MAX_TOUCH_POINTER_COUNT); | ||||
| 		for (int i = 0; i < pointerCount; i++) { | ||||
| 			positions[i * 6 + 0] = event.getPointerId(i); | ||||
| 			positions[i * 6 + 1] = event.getX(i); | ||||
| 			positions[i * 6 + 2] = event.getY(i); | ||||
| 			positions[i * 6 + 3] = event.getPressure(i); | ||||
| 			positions[i * 6 + 4] = GodotInputHandler.getEventTiltX(event); | ||||
| 			positions[i * 6 + 5] = GodotInputHandler.getEventTiltY(event); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// Magnify event fields and setter | ||||
| 	private float magnifyFactor; | ||||
| 	void setMagnifyEvent(float x, float y, float factor) { | ||||
| 		this.currentEventType = EventType.MAGNIFY; | ||||
| 		this.eventX = x; | ||||
| 		this.eventY = y; | ||||
| 		this.magnifyFactor = factor; | ||||
| 	} | ||||
| 
 | ||||
| 	// Pan event setter | ||||
| 	void setPanEvent(float x, float y, float deltaX, float deltaY) { | ||||
| 		this.currentEventType = EventType.PAN; | ||||
| 		this.eventX = x; | ||||
| 		this.eventY = y; | ||||
| 		this.eventDeltaX = deltaX; | ||||
| 		this.eventDeltaY = deltaY; | ||||
| 	} | ||||
| 
 | ||||
| 	// common joystick field | ||||
| 	private int joystickDevice; | ||||
| 
 | ||||
| 	// Joystick button event fields and setter | ||||
| 	private int button; | ||||
| 	void setJoystickButtonEvent(int device, int button, boolean pressed) { | ||||
| 		this.currentEventType = EventType.JOYSTICK_BUTTON; | ||||
| 		this.joystickDevice = device; | ||||
| 		this.button = button; | ||||
| 		this.eventPressed = pressed; | ||||
| 	} | ||||
| 
 | ||||
| 	// Joystick axis event fields and setter | ||||
| 	private int axis; | ||||
| 	private float value; | ||||
| 	void setJoystickAxisEvent(int device, int axis, float value) { | ||||
| 		this.currentEventType = EventType.JOYSTICK_AXIS; | ||||
| 		this.joystickDevice = device; | ||||
| 		this.axis = axis; | ||||
| 		this.value = value; | ||||
| 	} | ||||
| 
 | ||||
| 	// Joystick hat event fields and setter | ||||
| 	private int hatX; | ||||
| 	private int hatY; | ||||
| 	void setJoystickHatEvent(int device, int hatX, int hatY) { | ||||
| 		this.currentEventType = EventType.JOYSTICK_HAT; | ||||
| 		this.joystickDevice = device; | ||||
| 		this.hatX = hatX; | ||||
| 		this.hatY = hatY; | ||||
| 	} | ||||
| 
 | ||||
| 	// Joystick connection changed event fields and setter | ||||
| 	private boolean connected; | ||||
| 	private String joystickName; | ||||
| 	void setJoystickConnectionChangedEvent(int device, boolean connected, String name) { | ||||
| 		this.currentEventType = EventType.JOYSTICK_CONNECTION_CHANGED; | ||||
| 		this.joystickDevice = device; | ||||
| 		this.connected = connected; | ||||
| 		this.joystickName = name; | ||||
| 	} | ||||
| 
 | ||||
| 	// Key event fields and setter | ||||
| 	private int physicalKeycode; | ||||
| 	private int unicode; | ||||
| 	private int keyLabel; | ||||
| 	private boolean echo; | ||||
| 	void setKeyEvent(int physicalKeycode, int unicode, int keyLabel, boolean pressed, boolean echo) { | ||||
| 		this.currentEventType = EventType.KEY; | ||||
| 		this.physicalKeycode = physicalKeycode; | ||||
| 		this.unicode = unicode; | ||||
| 		this.keyLabel = keyLabel; | ||||
| 		this.eventPressed = pressed; | ||||
| 		this.echo = echo; | ||||
| 	} | ||||
| 
 | ||||
| 	// Sensor event fields and setter | ||||
| 	private int sensorType; | ||||
| 	private float rotatedValue0; | ||||
| 	private float rotatedValue1; | ||||
| 	private float rotatedValue2; | ||||
| 	void setSensorEvent(int sensorType, float rotatedValue0, float rotatedValue1, float rotatedValue2) { | ||||
| 		this.currentEventType = EventType.SENSOR; | ||||
| 		this.sensorType = sensorType; | ||||
| 		this.rotatedValue0 = rotatedValue0; | ||||
| 		this.rotatedValue1 = rotatedValue1; | ||||
| 		this.rotatedValue2 = rotatedValue2; | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
| 	public void run() { | ||||
| 		try { | ||||
| 			if (currentEventType == null) { | ||||
| 				Log.w(TAG, "Invalid event type"); | ||||
| 				return; | ||||
| 			} | ||||
| 
 | ||||
| 			switch (currentEventType) { | ||||
| 				case MOUSE: | ||||
| 					GodotLib.dispatchMouseEvent( | ||||
| 							eventAction, | ||||
| 							buttonsMask, | ||||
| 							eventX, | ||||
| 							eventY, | ||||
| 							eventDeltaX, | ||||
| 							eventDeltaY, | ||||
| 							doubleTap, | ||||
| 							sourceMouseRelative, | ||||
| 							pressure, | ||||
| 							tiltX, | ||||
| 							tiltY); | ||||
| 					break; | ||||
| 
 | ||||
| 				case TOUCH: | ||||
| 					GodotLib.dispatchTouchEvent( | ||||
| 							eventAction, | ||||
| 							actionPointerId, | ||||
| 							pointerCount, | ||||
| 							positions, | ||||
| 							doubleTap); | ||||
| 					break; | ||||
| 
 | ||||
| 				case MAGNIFY: | ||||
| 					GodotLib.magnify(eventX, eventY, magnifyFactor); | ||||
| 					break; | ||||
| 
 | ||||
| 				case PAN: | ||||
| 					GodotLib.pan(eventX, eventY, eventDeltaX, eventDeltaY); | ||||
| 					break; | ||||
| 
 | ||||
| 				case JOYSTICK_BUTTON: | ||||
| 					GodotLib.joybutton(joystickDevice, button, eventPressed); | ||||
| 					break; | ||||
| 
 | ||||
| 				case JOYSTICK_AXIS: | ||||
| 					GodotLib.joyaxis(joystickDevice, axis, value); | ||||
| 					break; | ||||
| 
 | ||||
| 				case JOYSTICK_HAT: | ||||
| 					GodotLib.joyhat(joystickDevice, hatX, hatY); | ||||
| 					break; | ||||
| 
 | ||||
| 				case JOYSTICK_CONNECTION_CHANGED: | ||||
| 					GodotLib.joyconnectionchanged(joystickDevice, connected, joystickName); | ||||
| 					break; | ||||
| 
 | ||||
| 				case KEY: | ||||
| 					GodotLib.key(physicalKeycode, unicode, keyLabel, eventPressed, echo); | ||||
| 					break; | ||||
| 
 | ||||
| 				case SENSOR: | ||||
| 					switch (sensorType) { | ||||
| 						case Sensor.TYPE_ACCELEROMETER: | ||||
| 							GodotLib.accelerometer(-rotatedValue0, -rotatedValue1, -rotatedValue2); | ||||
| 							break; | ||||
| 
 | ||||
| 						case Sensor.TYPE_GRAVITY: | ||||
| 							GodotLib.gravity(-rotatedValue0, -rotatedValue1, -rotatedValue2); | ||||
| 							break; | ||||
| 
 | ||||
| 						case Sensor.TYPE_MAGNETIC_FIELD: | ||||
| 							GodotLib.magnetometer(-rotatedValue0, -rotatedValue1, -rotatedValue2); | ||||
| 							break; | ||||
| 
 | ||||
| 						case Sensor.TYPE_GYROSCOPE: | ||||
| 							GodotLib.gyroscope(rotatedValue0, rotatedValue1, rotatedValue2); | ||||
| 							break; | ||||
| 					} | ||||
| 					break; | ||||
| 			} | ||||
| 		} finally { | ||||
| 			recycle(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	/** | ||||
| 	 * Release the current instance back to the pool | ||||
| 	 */ | ||||
| 	private void recycle() { | ||||
| 		currentEventType = null; | ||||
| 		POOL.release(this); | ||||
| 	} | ||||
| } | ||||
|  | @ -43,6 +43,7 @@ import androidx.annotation.Nullable; | |||
| 
 | ||||
| import java.lang.reflect.Constructor; | ||||
| import java.util.Collection; | ||||
| import java.util.Collections; | ||||
| import java.util.Set; | ||||
| import java.util.concurrent.ConcurrentHashMap; | ||||
| 
 | ||||
|  | @ -82,6 +83,9 @@ public final class GodotPluginRegistry { | |||
| 	 * Retrieve the full set of loaded plugins. | ||||
| 	 */ | ||||
| 	public Collection<GodotPlugin> getAllPlugins() { | ||||
| 		if (registry.isEmpty()) { | ||||
| 			return Collections.emptyList(); | ||||
| 		} | ||||
| 		return registry.values(); | ||||
| 	} | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Rémi Verschelde
						Rémi Verschelde