summaryrefslogtreecommitdiffstats
path: root/platform/android/java/lib/src
diff options
context:
space:
mode:
Diffstat (limited to 'platform/android/java/lib/src')
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/Godot.kt102
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt6
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java1
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java7
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt92
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java183
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt17
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt11
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/io/file/FileErrors.kt53
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java22
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java10
11 files changed, 298 insertions, 206 deletions
diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
index ce53aeebcb..290be727ab 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.kt
@@ -38,7 +38,6 @@ import android.content.pm.PackageManager
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.Color
-import android.graphics.Rect
import android.hardware.Sensor
import android.hardware.SensorEvent
import android.hardware.SensorEventListener
@@ -46,10 +45,12 @@ import android.hardware.SensorManager
import android.os.*
import android.util.Log
import android.view.*
-import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.widget.FrameLayout
import androidx.annotation.Keep
import androidx.annotation.StringRes
+import androidx.core.view.ViewCompat
+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.io.directory.DirectoryAccessHandler
@@ -418,58 +419,42 @@ class Godot(private val context: Context) : SensorEventListener {
io?.setEdit(editText)
// Listeners for keyboard height.
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
- // Report the height of virtual keyboard as it changes during the animation.
- val decorView = activity.window.decorView
- decorView.setWindowInsetsAnimationCallback(object : WindowInsetsAnimation.Callback(DISPATCH_MODE_STOP) {
- var startBottom = 0
- var endBottom = 0
- override fun onPrepare(animation: WindowInsetsAnimation) {
- startBottom = decorView.rootWindowInsets.getInsets(WindowInsets.Type.ime()).bottom
- }
+ val decorView = activity.window.decorView
+ // Report the height of virtual keyboard as it changes during the animation.
+ ViewCompat.setWindowInsetsAnimationCallback(decorView, object : WindowInsetsAnimationCompat.Callback(DISPATCH_MODE_STOP) {
+ var startBottom = 0
+ var endBottom = 0
+ override fun onPrepare(animation: WindowInsetsAnimationCompat) {
+ startBottom = ViewCompat.getRootWindowInsets(decorView)?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
+ }
- override fun onStart(animation: WindowInsetsAnimation, bounds: WindowInsetsAnimation.Bounds): WindowInsetsAnimation.Bounds {
- endBottom = decorView.rootWindowInsets.getInsets(WindowInsets.Type.ime()).bottom
- return bounds
- }
+ override fun onStart(animation: WindowInsetsAnimationCompat, bounds: WindowInsetsAnimationCompat.BoundsCompat): WindowInsetsAnimationCompat.BoundsCompat {
+ endBottom = ViewCompat.getRootWindowInsets(decorView)?.getInsets(WindowInsetsCompat.Type.ime())?.bottom ?: 0
+ return bounds
+ }
- override fun onProgress(windowInsets: WindowInsets, list: List<WindowInsetsAnimation>): WindowInsets {
- // Find the IME animation.
- var imeAnimation: WindowInsetsAnimation? = null
- for (animation in list) {
- if (animation.typeMask and WindowInsets.Type.ime() != 0) {
- imeAnimation = animation
- break
- }
+ override fun onProgress(windowInsets: WindowInsetsCompat, animationsList: List<WindowInsetsAnimationCompat>): WindowInsetsCompat {
+ // Find the IME animation.
+ var imeAnimation: WindowInsetsAnimationCompat? = null
+ for (animation in animationsList) {
+ if (animation.typeMask and WindowInsetsCompat.Type.ime() != 0) {
+ imeAnimation = animation
+ break
}
- // Update keyboard height based on IME animation.
- if (imeAnimation != null) {
- val interpolatedFraction = imeAnimation.interpolatedFraction
- // Linear interpolation between start and end values.
- val keyboardHeight = startBottom * (1.0f - interpolatedFraction) + endBottom * interpolatedFraction
- GodotLib.setVirtualKeyboardHeight(keyboardHeight.toInt())
- }
- return windowInsets
}
- override fun onEnd(animation: WindowInsetsAnimation) {}
- })
- } else {
- // Infer the virtual keyboard height using visible area.
- renderView?.view?.viewTreeObserver?.addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
- // Don't allocate a new Rect every time the callback is called.
- val visibleSize = Rect()
- override fun onGlobalLayout() {
- renderView?.let {
- val surfaceView = it.view
-
- surfaceView.getWindowVisibleDisplayFrame(visibleSize)
- val keyboardHeight = surfaceView.height - visibleSize.bottom
- GodotLib.setVirtualKeyboardHeight(keyboardHeight)
- }
+ // Update keyboard height based on IME animation.
+ if (imeAnimation != null) {
+ val interpolatedFraction = imeAnimation.interpolatedFraction
+ // Linear interpolation between start and end values.
+ val keyboardHeight = startBottom * (1.0f - interpolatedFraction) + endBottom * interpolatedFraction
+ GodotLib.setVirtualKeyboardHeight(keyboardHeight.toInt())
}
- })
- }
+ return windowInsets
+ }
+
+ override fun onEnd(animation: WindowInsetsAnimationCompat) {}
+ })
if (host == primaryHost) {
renderView?.queueOnRenderThread {
@@ -894,16 +879,25 @@ class Godot(private val context: Context) : SensorEventListener {
*/
@SuppressLint("MissingPermission")
@Keep
- private fun vibrate(durationMs: Int) {
+ private fun vibrate(durationMs: Int, amplitude: Int) {
if (durationMs > 0 && requestPermission("VIBRATE")) {
val vibratorService = getActivity()?.getSystemService(Context.VIBRATOR_SERVICE) as Vibrator? ?: return
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- vibratorService.vibrate(
- VibrationEffect.createOneShot(
- durationMs.toLong(),
- VibrationEffect.DEFAULT_AMPLITUDE
+ if (amplitude <= -1) {
+ vibratorService.vibrate(
+ VibrationEffect.createOneShot(
+ durationMs.toLong(),
+ VibrationEffect.DEFAULT_AMPLITUDE
+ )
)
- )
+ } else {
+ vibratorService.vibrate(
+ VibrationEffect.createOneShot(
+ durationMs.toLong(),
+ amplitude
+ )
+ )
+ }
} else {
// deprecated in API 26
vibratorService.vibrate(durationMs.toLong())
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
index 7b8fad8952..4c5e857b7a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotActivity.kt
@@ -36,6 +36,7 @@ import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import androidx.annotation.CallSuper
+import androidx.annotation.LayoutRes
import androidx.fragment.app.FragmentActivity
import org.godotengine.godot.utils.PermissionsUtil
import org.godotengine.godot.utils.ProcessPhoenix
@@ -65,7 +66,7 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
- setContentView(R.layout.godot_app_layout)
+ setContentView(getGodotAppLayout())
handleStartIntent(intent, true)
@@ -80,6 +81,9 @@ abstract class GodotActivity : FragmentActivity(), GodotHost {
}
}
+ @LayoutRes
+ protected open fun getGodotAppLayout() = R.layout.godot_app_layout
+
override fun onDestroy() {
Log.v(TAG, "Destroying Godot app...")
super.onDestroy()
diff --git a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
index bd8c58ad69..c316812404 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/gl/GLSurfaceView.java
@@ -1955,4 +1955,3 @@ public class GLSurfaceView extends SurfaceView implements SurfaceHolder.Callback
private int mEGLContextClientVersion;
private boolean mPreserveEGLContextOnPause;
}
-
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index dc8a0e54bb..c085bb8886 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -266,8 +266,13 @@ public class GodotEditText extends EditText {
boolean hasHardwareKeyboard() {
Configuration config = getResources().getConfiguration();
- return config.keyboard != Configuration.KEYBOARD_NOKEYS &&
+ boolean hasHardwareKeyboardConfig = config.keyboard != Configuration.KEYBOARD_NOKEYS &&
config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
+ if (hasHardwareKeyboardConfig) {
+ return true;
+ }
+
+ return mRenderView.getInputHandler().hasHardwareKeyboard();
}
// ===========================================================
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
index 89fbb9f580..49b34a5229 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.kt
@@ -61,8 +61,11 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
private var contextClickInProgress = false
private var pointerCaptureInProgress = false
+ private var lastDragX: Float = 0.0f
+ private var lastDragY: Float = 0.0f
+
override fun onDown(event: MotionEvent): Boolean {
- GodotInputHandler.handleMotionEvent(event.source, MotionEvent.ACTION_DOWN, event.buttonState, event.x, event.y, nextDownIsDoubleTap)
+ GodotInputHandler.handleMotionEvent(event, MotionEvent.ACTION_DOWN, nextDownIsDoubleTap)
nextDownIsDoubleTap = false
return true
}
@@ -82,20 +85,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
}
// Cancel the previous down event
- GodotInputHandler.handleMotionEvent(
- event.source,
- MotionEvent.ACTION_CANCEL,
- event.buttonState,
- event.x,
- event.y
- )
+ GodotInputHandler.handleMotionEvent(event, MotionEvent.ACTION_CANCEL)
// Turn a context click into a single tap right mouse button click.
GodotInputHandler.handleMouseEvent(
+ event,
MotionEvent.ACTION_DOWN,
MotionEvent.BUTTON_SECONDARY,
- event.x,
- event.y
+ false
)
contextClickInProgress = true
}
@@ -107,16 +104,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (!hasCapture) {
// Dispatch a mouse relative ACTION_UP event to signal the end of the capture
- GodotInputHandler.handleMouseEvent(
- MotionEvent.ACTION_UP,
- 0,
- 0f,
- 0f,
- 0f,
- 0f,
- false,
- true
- )
+ GodotInputHandler.handleMouseEvent(MotionEvent.ACTION_UP, true)
}
pointerCaptureInProgress = hasCapture
}
@@ -139,32 +127,19 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
return true
}
- val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
- } else {
- false
- }
-
if (pointerCaptureInProgress || dragInProgress || contextClickInProgress) {
if (contextClickInProgress || GodotInputHandler.isMouseEvent(event)) {
// This may be an ACTION_BUTTON_RELEASE event which we don't handle,
// so we convert it to an ACTION_UP event.
- GodotInputHandler.handleMouseEvent(
- MotionEvent.ACTION_UP,
- event.buttonState,
- event.x,
- event.y,
- 0f,
- 0f,
- false,
- sourceMouseRelative
- )
+ GodotInputHandler.handleMouseEvent(event, MotionEvent.ACTION_UP)
} else {
GodotInputHandler.handleTouchEvent(event)
}
pointerCaptureInProgress = false
dragInProgress = false
contextClickInProgress = false
+ lastDragX = 0.0f
+ lastDragY = 0.0f
return true
}
@@ -173,22 +148,19 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
private fun onActionMove(event: MotionEvent): Boolean {
if (contextClickInProgress) {
- val sourceMouseRelative = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE)
- } else {
- false
- }
- GodotInputHandler.handleMouseEvent(
- event.actionMasked,
- MotionEvent.BUTTON_SECONDARY,
- event.x,
- event.y,
- 0f,
- 0f,
- false,
- sourceMouseRelative
- )
+ GodotInputHandler.handleMouseEvent(event, event.actionMasked, MotionEvent.BUTTON_SECONDARY, false)
return true
+ } else if (!scaleInProgress) {
+ // The 'onScroll' event is triggered with a long delay.
+ // Force the 'InputEventScreenDrag' event earlier here.
+ // We don't toggle 'dragInProgress' here so that the scaling logic can override the drag operation if needed.
+ // Once the 'onScroll' event kicks-in, 'dragInProgress' will be properly set.
+ if (lastDragX != event.getX(0) || lastDragY != event.getY(0)) {
+ lastDragX = event.getX(0)
+ lastDragY = event.getY(0)
+ GodotInputHandler.handleMotionEvent(event)
+ return true
+ }
}
return false
}
@@ -197,7 +169,7 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
if (event.actionMasked == MotionEvent.ACTION_UP) {
nextDownIsDoubleTap = false
GodotInputHandler.handleMotionEvent(event)
- } else if (event.actionMasked == MotionEvent.ACTION_MOVE && panningAndScalingEnabled == false) {
+ } else if (event.actionMasked == MotionEvent.ACTION_MOVE && !panningAndScalingEnabled) {
GodotInputHandler.handleMotionEvent(event)
}
@@ -216,18 +188,14 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
distanceY: Float
): Boolean {
if (scaleInProgress) {
- if (dragInProgress) {
+ if (dragInProgress || lastDragX != 0.0f || lastDragY != 0.0f) {
if (originEvent != null) {
// Cancel the drag
- GodotInputHandler.handleMotionEvent(
- originEvent.source,
- MotionEvent.ACTION_CANCEL,
- originEvent.buttonState,
- originEvent.x,
- originEvent.y
- )
+ GodotInputHandler.handleMotionEvent(originEvent, MotionEvent.ACTION_CANCEL)
}
dragInProgress = false
+ lastDragX = 0.0f
+ lastDragY = 0.0f
}
}
@@ -235,8 +203,10 @@ internal class GodotGestureHandler : SimpleOnGestureListener(), OnScaleGestureLi
val y = terminusEvent.y
if (terminusEvent.pointerCount >= 2 && panningAndScalingEnabled && !pointerCaptureInProgress && !dragInProgress) {
GodotLib.pan(x, y, distanceX / 5f, distanceY / 5f)
- } else if (!scaleInProgress){
+ } else if (!scaleInProgress) {
dragInProgress = true
+ lastDragX = terminusEvent.getX(0)
+ lastDragY = terminusEvent.getY(0)
GodotInputHandler.handleMotionEvent(terminusEvent)
}
return true
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index fe971cf442..83e76e49c9 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -62,6 +62,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
private final SparseIntArray mJoystickIds = new SparseIntArray(4);
private final SparseArray<Joystick> mJoysticksDevices = new SparseArray<>(4);
+ private final HashSet<Integer> mHardwareKeyboardIds = new HashSet<>();
private final GodotRenderView mRenderView;
private final InputManager mInputManager;
@@ -114,6 +115,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
rotaryInputAxis = axis;
}
+ boolean hasHardwareKeyboard() {
+ return !mHardwareKeyboardIds.isEmpty();
+ }
+
private boolean isKeyEventGameDevice(int source) {
// Note that keyboards are often (SOURCE_KEYBOARD | SOURCE_DPAD)
if (source == (InputDevice.SOURCE_KEYBOARD | InputDevice.SOURCE_DPAD))
@@ -195,7 +200,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
public boolean onTouchEvent(final MotionEvent event) {
- lastSeenToolType = event.getToolType(0);
+ lastSeenToolType = getEventToolType(event);
this.scaleGestureDetector.onTouchEvent(event);
if (this.gestureDetector.onTouchEvent(event)) {
@@ -221,17 +226,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
public boolean onGenericMotionEvent(MotionEvent event) {
- lastSeenToolType = event.getToolType(0);
-
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
- // The gesture detector has handled the event.
- return true;
- }
-
- if (godotGestureHandler.onMotionEvent(event)) {
- // The gesture handler has handled the event.
- return true;
- }
+ lastSeenToolType = getEventToolType(event);
if (event.isFromSource(InputDevice.SOURCE_JOYSTICK) && event.getActionMasked() == MotionEvent.ACTION_MOVE) {
// Check if the device exists
@@ -268,11 +263,20 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
return true;
}
- } else {
- return handleMouseEvent(event);
+ return false;
}
- return false;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && gestureDetector.onGenericMotionEvent(event)) {
+ // The gesture detector has handled the event.
+ return true;
+ }
+
+ if (godotGestureHandler.onMotionEvent(event)) {
+ // The gesture handler has handled the event.
+ return true;
+ }
+
+ return handleMouseEvent(event);
}
public void initInputDevices() {
@@ -310,11 +314,17 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return;
}
- int sources = device.getSources();
+ // Device may be an external keyboard; store the device id
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
+ device.supportsSource(InputDevice.SOURCE_KEYBOARD) &&
+ device.isExternal() &&
+ device.getKeyboardType() == InputDevice.KEYBOARD_TYPE_ALPHABETIC) {
+ mHardwareKeyboardIds.add(deviceId);
+ }
// Device may not be a joystick or gamepad
- if ((sources & InputDevice.SOURCE_GAMEPAD) != InputDevice.SOURCE_GAMEPAD &&
- (sources & InputDevice.SOURCE_JOYSTICK) != InputDevice.SOURCE_JOYSTICK) {
+ if (!device.supportsSource(InputDevice.SOURCE_GAMEPAD) &&
+ !device.supportsSource(InputDevice.SOURCE_JOYSTICK)) {
return;
}
@@ -359,6 +369,8 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
@Override
public void onInputDeviceRemoved(int deviceId) {
+ mHardwareKeyboardIds.remove(deviceId);
+
// Check if the device has not been already removed
if (mJoystickIds.indexOfKey(deviceId) < 0) {
return;
@@ -440,50 +452,65 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
return button;
}
- static boolean isMouseEvent(MotionEvent event) {
- return isMouseEvent(event.getSource());
+ private static int getEventToolType(MotionEvent event) {
+ return event.getPointerCount() > 0 ? event.getToolType(0) : MotionEvent.TOOL_TYPE_UNKNOWN;
}
- private static boolean isMouseEvent(int eventSource) {
- boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
+ static boolean isMouseEvent(MotionEvent event) {
+ int toolType = getEventToolType(event);
+ int eventSource = event.getSource();
+
+ switch (toolType) {
+ case MotionEvent.TOOL_TYPE_FINGER:
+ return false;
+
+ case MotionEvent.TOOL_TYPE_MOUSE:
+ case MotionEvent.TOOL_TYPE_STYLUS:
+ case MotionEvent.TOOL_TYPE_ERASER:
+ return true;
+
+ case MotionEvent.TOOL_TYPE_UNKNOWN:
+ default:
+ boolean mouseSource =
+ ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) ||
+ ((eventSource & (InputDevice.SOURCE_TOUCHSCREEN | InputDevice.SOURCE_STYLUS)) == InputDevice.SOURCE_STYLUS);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ mouseSource = mouseSource ||
+ ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
+ }
+ return mouseSource;
}
- return mouseSource;
}
static boolean handleMotionEvent(final MotionEvent event) {
- if (isMouseEvent(event)) {
- return handleMouseEvent(event);
- }
-
- return handleTouchEvent(event);
+ return handleMotionEvent(event, event.getActionMasked());
}
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y) {
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, false);
+ static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride) {
+ return handleMotionEvent(event, eventActionOverride, false);
}
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, boolean doubleTap) {
- return handleMotionEvent(eventSource, eventAction, buttonsMask, x, y, 0, 0, doubleTap);
+ static boolean handleMotionEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
+ if (isMouseEvent(event)) {
+ return handleMouseEvent(event, eventActionOverride, doubleTap);
+ }
+ return handleTouchEvent(event, eventActionOverride, doubleTap);
}
- static boolean handleMotionEvent(int eventSource, int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleTap) {
- if (isMouseEvent(eventSource)) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleTap, false);
- }
+ private 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();
- return handleTouchEvent(eventAction, x, y, doubleTap);
- }
+ // Tilt is zero is perpendicular to the screen and pi/2 is flat on the surface.
+ final float tilt = event.getAxisValue(MotionEvent.AXIS_TILT);
- static boolean handleMouseEvent(final MotionEvent event) {
- final int eventAction = event.getActionMasked();
- final float x = event.getX();
- final float y = event.getY();
- final int buttonsMask = event.getButtonState();
+ float tiltMult = (float)Math.sin(tilt);
- final float pressure = event.getPressure();
+ // To be consistent with expected tilt.
+ return (float)-Math.sin(orientation) * tiltMult;
+ }
+ private 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();
@@ -493,8 +520,26 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
float tiltMult = (float)Math.sin(tilt);
// To be consistent with expected tilt.
- final float tiltX = (float)-Math.sin(orientation) * tiltMult;
- final float tiltY = (float)Math.cos(orientation) * tiltMult;
+ return (float)Math.cos(orientation) * tiltMult;
+ }
+
+ static boolean handleMouseEvent(final MotionEvent event) {
+ return handleMouseEvent(event, event.getActionMasked());
+ }
+
+ static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride) {
+ return handleMouseEvent(event, eventActionOverride, false);
+ }
+
+ static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
+ return handleMouseEvent(event, eventActionOverride, event.getButtonState(), doubleTap);
+ }
+
+ static boolean handleMouseEvent(final MotionEvent event, int eventActionOverride, int buttonMaskOverride, boolean doubleTap) {
+ final float x = event.getX();
+ final float y = event.getY();
+
+ final float pressure = event.getPressure();
float verticalFactor = 0;
float horizontalFactor = 0;
@@ -516,15 +561,11 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
}
- return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative, pressure, tiltX, tiltY);
- }
-
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, 0, 0, false, false);
+ return handleMouseEvent(eventActionOverride, buttonMaskOverride, x, y, horizontalFactor, verticalFactor, doubleTap, sourceMouseRelative, pressure, getEventTiltX(event), getEventTiltY(event));
}
- static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
- return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, 1, 0, 0);
+ static boolean handleMouseEvent(int eventAction, boolean sourceMouseRelative) {
+ return handleMouseEvent(eventAction, 0, 0f, 0f, 0f, 0f, false, sourceMouseRelative, 1f, 0f, 0f);
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
@@ -563,37 +604,39 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
static boolean handleTouchEvent(final MotionEvent event) {
+ return handleTouchEvent(event, event.getActionMasked());
+ }
+
+ static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride) {
+ return handleTouchEvent(event, eventActionOverride, false);
+ }
+
+ static boolean handleTouchEvent(final MotionEvent event, int eventActionOverride, boolean doubleTap) {
final int pointerCount = event.getPointerCount();
if (pointerCount == 0) {
return true;
}
- final float[] positions = new float[pointerCount * 3]; // pointerId1, x1, y1, pointerId2, etc...
+ final float[] positions = new float[pointerCount * 6]; // pointerId1, x1, y1, pressure1, tiltX1, tiltY1, pointerId2, etc...
for (int i = 0; i < pointerCount; i++) {
- positions[i * 3 + 0] = event.getPointerId(i);
- positions[i * 3 + 1] = event.getX(i);
- positions[i * 3 + 2] = event.getY(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);
}
- final int action = event.getActionMasked();
final int actionPointerId = event.getPointerId(event.getActionIndex());
- return handleTouchEvent(action, actionPointerId, pointerCount, positions, false);
- }
-
- static boolean handleTouchEvent(int eventAction, float x, float y, boolean doubleTap) {
- return handleTouchEvent(eventAction, 0, 1, new float[] { 0, x, y }, doubleTap);
- }
-
- static boolean handleTouchEvent(int eventAction, int actionPointerId, int pointerCount, float[] positions, boolean doubleTap) {
- switch (eventAction) {
+ switch (eventActionOverride) {
case MotionEvent.ACTION_DOWN:
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_POINTER_DOWN: {
- GodotLib.dispatchTouchEvent(eventAction, actionPointerId, pointerCount, positions, doubleTap);
+ GodotLib.dispatchTouchEvent(eventActionOverride, actionPointerId, pointerCount, positions, doubleTap);
return true;
}
}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
index 0f447f0b05..11cf7b3566 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/DataAccess.kt
@@ -36,7 +36,9 @@ import android.util.Log
import org.godotengine.godot.io.StorageScope
import java.io.IOException
import java.nio.ByteBuffer
+import java.nio.channels.ClosedChannelException
import java.nio.channels.FileChannel
+import java.nio.channels.NonWritableChannelException
import kotlin.math.max
/**
@@ -135,6 +137,21 @@ internal abstract class DataAccess(private val filePath: String) {
seek(positionFromBeginning)
}
+ fun resize(length: Long): Int {
+ return try {
+ fileChannel.truncate(length)
+ FileErrors.OK.nativeValue
+ } catch (e: NonWritableChannelException) {
+ FileErrors.FILE_CANT_OPEN.nativeValue
+ } catch (e: ClosedChannelException) {
+ FileErrors.FILE_CANT_OPEN.nativeValue
+ } catch (e: IllegalArgumentException) {
+ FileErrors.INVALID_PARAMETER.nativeValue
+ } catch (e: IOException) {
+ FileErrors.FAILED.nativeValue
+ }
+ }
+
fun position(): Long {
return try {
fileChannel.position()
diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt
index 50741c1aab..1d773467e8 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt
+++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileAccessHandler.kt
@@ -45,7 +45,6 @@ class FileAccessHandler(val context: Context) {
companion object {
private val TAG = FileAccessHandler::class.java.simpleName
- private const val FILE_NOT_FOUND_ERROR_ID = -1
internal const val INVALID_FILE_ID = 0
private const val STARTING_FILE_ID = 1
@@ -118,7 +117,7 @@ class FileAccessHandler(val context: Context) {
lastFileId
} ?: INVALID_FILE_ID
} catch (e: FileNotFoundException) {
- FILE_NOT_FOUND_ERROR_ID
+ FileErrors.FILE_NOT_FOUND.nativeValue
} catch (e: Exception) {
Log.w(TAG, "Error while opening $path", e)
INVALID_FILE_ID
@@ -190,6 +189,14 @@ class FileAccessHandler(val context: Context) {
}
}
+ fun fileResize(fileId: Int, length: Long): Int {
+ if (!hasFileId(fileId)) {
+ return FileErrors.FAILED.nativeValue
+ }
+
+ return files[fileId].resize(length)
+ }
+
fun fileGetPosition(fileId: Int): Long {
if (!hasFileId(fileId)) {
return 0L
diff --git a/platform/android/java/lib/src/org/godotengine/godot/io/file/FileErrors.kt b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileErrors.kt
new file mode 100644
index 0000000000..2df0195de7
--- /dev/null
+++ b/platform/android/java/lib/src/org/godotengine/godot/io/file/FileErrors.kt
@@ -0,0 +1,53 @@
+/**************************************************************************/
+/* FileErrors.kt */
+/**************************************************************************/
+/* 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.io.file
+
+/**
+ * Set of errors that may occur when performing data access.
+ */
+internal enum class FileErrors(val nativeValue: Int) {
+ OK(0),
+ FAILED(-1),
+ FILE_NOT_FOUND(-2),
+ FILE_CANT_OPEN(-3),
+ INVALID_PARAMETER(-4);
+
+ companion object {
+ fun fromNativeError(error: Int): FileErrors? {
+ for (fileError in entries) {
+ if (fileError.nativeValue == error) {
+ return fileError
+ }
+ }
+ return null
+ }
+ }
+}
diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
index c0912ca4dc..c975c29e96 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPlugin.java
@@ -112,19 +112,18 @@ public abstract class GodotPlugin {
/**
* Register the plugin with Godot native code.
* <p>
- * This method is invoked by the Godot Engine on the render thread.
+ * This method is invoked on the render thread to register the plugin on engine startup.
*/
public final void onRegisterPluginWithGodotNative() {
- registeredSignals.putAll(
- registerPluginWithGodotNative(this, getPluginName(), getPluginMethods(), getPluginSignals()));
- }
+ final String pluginName = getPluginName();
+ if (!nativeRegisterSingleton(pluginName, this)) {
+ return;
+ }
- private static Map<String, SignalInfo> registerPluginWithGodotNative(Object pluginObject,
- String pluginName, List<String> pluginMethods, Set<SignalInfo> pluginSignals) {
- nativeRegisterSingleton(pluginName, pluginObject);
+ List<String> pluginMethods = getPluginMethods();
Set<Method> filteredMethods = new HashSet<>();
- Class<?> clazz = pluginObject.getClass();
+ Class<?> clazz = getClass();
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) {
@@ -156,15 +155,14 @@ public abstract class GodotPlugin {
nativeRegisterMethod(pluginName, method.getName(), method.getReturnType().getName(), pt);
}
+ Set<SignalInfo> pluginSignals = getPluginSignals();
+
// Register the signals for this plugin.
- Map<String, SignalInfo> registeredSignals = new HashMap<>();
for (SignalInfo signalInfo : pluginSignals) {
String signalName = signalInfo.getName();
nativeRegisterSignal(pluginName, signalName, signalInfo.getParamTypesNames());
registeredSignals.put(signalName, signalInfo);
}
-
- return registeredSignals;
}
/**
@@ -408,7 +406,7 @@ public abstract class GodotPlugin {
* Used to setup a {@link GodotPlugin} instance.
* @param p_name Name of the instance.
*/
- private static native void nativeRegisterSingleton(String p_name, Object object);
+ private static native boolean nativeRegisterSingleton(String p_name, Object object);
/**
* Used to complete registration of the {@link GodotPlugin} instance's methods.
diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
index 9df890e6bd..4e8e82a70a 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/utils/PermissionsUtil.java
@@ -125,7 +125,7 @@ public final class PermissionsUtil {
}
activity.requestPermissions(requestedPermissions.toArray(new String[0]), REQUEST_ALL_PERMISSION_REQ_CODE);
- return true;
+ return false;
}
/**
@@ -281,8 +281,9 @@ public final class PermissionsUtil {
public static boolean hasManifestPermission(Context context, String permission) {
try {
for (String p : getManifestPermissions(context)) {
- if (permission.equals(p))
+ if (permission.equals(p)) {
return true;
+ }
}
} catch (PackageManager.NameNotFoundException ignored) {
}
@@ -299,8 +300,9 @@ public final class PermissionsUtil {
public static ArrayList<String> getManifestPermissions(Context context) throws PackageManager.NameNotFoundException {
PackageManager packageManager = context.getPackageManager();
PackageInfo packageInfo = packageManager.getPackageInfo(context.getPackageName(), PackageManager.GET_PERMISSIONS);
- if (packageInfo.requestedPermissions == null)
- return new ArrayList<String>();
+ if (packageInfo.requestedPermissions == null) {
+ return new ArrayList<>();
+ }
return new ArrayList<>(Arrays.asList(packageInfo.requestedPermissions));
}