Add missing display server overrides
Improves the base functionality for the Android platform and helps reduce the amount of spurious error logs emitted.
This commit is contained in:
parent
4a82d71d73
commit
7cc47613fe
10 changed files with 166 additions and 7 deletions
|
@ -619,11 +619,11 @@ MouseButton DisplayServerAndroid::mouse_get_button_state() const {
|
|||
return (MouseButton)Input::get_singleton()->get_mouse_button_mask();
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) {
|
||||
void DisplayServerAndroid::_cursor_set_shape_helper(CursorShape p_shape, bool force) {
|
||||
if (!OS_Android::get_singleton()->get_godot_java()->get_godot_view()->can_update_pointer_icon()) {
|
||||
return;
|
||||
}
|
||||
if (cursor_shape == p_shape) {
|
||||
if (cursor_shape == p_shape && !force) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -634,10 +634,23 @@ void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape)
|
|||
}
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::cursor_set_shape(DisplayServer::CursorShape p_shape) {
|
||||
_cursor_set_shape_helper(p_shape);
|
||||
}
|
||||
|
||||
DisplayServer::CursorShape DisplayServerAndroid::cursor_get_shape() const {
|
||||
return cursor_shape;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape, const Vector2 &p_hotspot) {
|
||||
String cursor_path = p_cursor.is_valid() ? p_cursor->get_path() : "";
|
||||
if (!cursor_path.is_empty()) {
|
||||
cursor_path = ProjectSettings::get_singleton()->globalize_path(cursor_path);
|
||||
}
|
||||
OS_Android::get_singleton()->get_godot_java()->get_godot_view()->configure_pointer_icon(android_cursors[cursor_shape], cursor_path, p_hotspot);
|
||||
_cursor_set_shape_helper(p_shape, true);
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
|
||||
#if defined(VULKAN_ENABLED)
|
||||
context_vulkan->set_vsync_mode(p_window, p_vsync_mode);
|
||||
|
@ -651,3 +664,23 @@ DisplayServer::VSyncMode DisplayServerAndroid::window_get_vsync_mode(WindowID p_
|
|||
return DisplayServer::VSYNC_ENABLED;
|
||||
#endif
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::reset_swap_buffers_flag() {
|
||||
swap_buffers_flag = false;
|
||||
}
|
||||
|
||||
bool DisplayServerAndroid::should_swap_buffers() const {
|
||||
return swap_buffers_flag;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::swap_buffers() {
|
||||
swap_buffers_flag = true;
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::set_native_icon(const String &p_filename) {
|
||||
// NOT SUPPORTED
|
||||
}
|
||||
|
||||
void DisplayServerAndroid::set_icon(const Ref<Image> &p_icon) {
|
||||
// NOT SUPPORTED
|
||||
}
|
||||
|
|
|
@ -66,6 +66,7 @@ class DisplayServerAndroid : public DisplayServer {
|
|||
MouseMode mouse_mode = MouseMode::MOUSE_MODE_VISIBLE;
|
||||
|
||||
bool keep_screen_on;
|
||||
bool swap_buffers_flag;
|
||||
|
||||
CursorShape cursor_shape = CursorShape::CURSOR_ARROW;
|
||||
|
||||
|
@ -188,8 +189,10 @@ public:
|
|||
void process_magnetometer(const Vector3 &p_magnetometer);
|
||||
void process_gyroscope(const Vector3 &p_gyroscope);
|
||||
|
||||
void _cursor_set_shape_helper(CursorShape p_shape, bool force = false);
|
||||
virtual void cursor_set_shape(CursorShape p_shape) override;
|
||||
virtual CursorShape cursor_get_shape() const override;
|
||||
virtual void cursor_set_custom_image(const Ref<Resource> &p_cursor, CursorShape p_shape = CURSOR_ARROW, const Vector2 &p_hotspot = Vector2()) override;
|
||||
|
||||
virtual void mouse_set_mode(MouseMode p_mode) override;
|
||||
virtual MouseMode mouse_get_mode() const override;
|
||||
|
@ -204,6 +207,13 @@ public:
|
|||
virtual Point2i mouse_get_position() const override;
|
||||
virtual MouseButton mouse_get_button_state() const override;
|
||||
|
||||
void reset_swap_buffers_flag();
|
||||
bool should_swap_buffers() const;
|
||||
virtual void swap_buffers() override;
|
||||
|
||||
virtual void set_native_icon(const String &p_filename) override;
|
||||
virtual void set_icon(const Ref<Image> &p_icon) override;
|
||||
|
||||
DisplayServerAndroid(const String &p_rendering_driver, WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, Error &r_error);
|
||||
~DisplayServerAndroid();
|
||||
};
|
||||
|
|
|
@ -175,6 +175,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
|||
public GodotIO io;
|
||||
public GodotNetUtils netUtils;
|
||||
public GodotTTS tts;
|
||||
DirectoryAccessHandler directoryAccessHandler;
|
||||
|
||||
public interface ResultCallback {
|
||||
void callback(int requestCode, int resultCode, Intent data);
|
||||
|
@ -488,7 +489,7 @@ public class Godot extends Fragment implements SensorEventListener, IDownloaderC
|
|||
netUtils = new GodotNetUtils(activity);
|
||||
tts = new GodotTTS(activity);
|
||||
Context context = getContext();
|
||||
DirectoryAccessHandler directoryAccessHandler = new DirectoryAccessHandler(context);
|
||||
directoryAccessHandler = new DirectoryAccessHandler(context);
|
||||
FileAccessHandler fileAccessHandler = new FileAccessHandler(context);
|
||||
mSensorManager = (SensorManager)activity.getSystemService(Context.SENSOR_SERVICE);
|
||||
mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
|
||||
|
|
|
@ -43,8 +43,13 @@ import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.PixelFormat;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
|
@ -52,6 +57,8 @@ import android.view.SurfaceView;
|
|||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
/**
|
||||
* A simple GLSurfaceView sub-class that demonstrate how to perform
|
||||
* OpenGL ES 2.0 rendering into a GL Surface. Note the following important
|
||||
|
@ -74,6 +81,7 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
|
|||
private final Godot godot;
|
||||
private final GodotInputHandler inputHandler;
|
||||
private final GodotRenderer godotRenderer;
|
||||
private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>();
|
||||
|
||||
public GodotGLRenderView(Context context, Godot godot, XRMode xrMode, boolean p_use_debug_opengl) {
|
||||
super(context);
|
||||
|
@ -168,13 +176,50 @@ public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView
|
|||
inputHandler.onPointerCaptureChange(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to configure the PointerIcon for the given type.
|
||||
*
|
||||
* Called from JNI
|
||||
*/
|
||||
@Keep
|
||||
@Override
|
||||
public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
try {
|
||||
Bitmap bitmap = null;
|
||||
if (!TextUtils.isEmpty(imagePath)) {
|
||||
if (godot.directoryAccessHandler.filesystemFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the file system
|
||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||
} else if (godot.directoryAccessHandler.assetsFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the assets directory
|
||||
AssetManager am = getContext().getAssets();
|
||||
InputStream imageInputStream = am.open(imagePath);
|
||||
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY);
|
||||
customPointerIcons.put(pointerType, customPointerIcon);
|
||||
} catch (Exception e) {
|
||||
// Reset the custom pointer icon
|
||||
customPointerIcons.delete(pointerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from JNI to change pointer icon
|
||||
*/
|
||||
@Keep
|
||||
@Override
|
||||
public void setPointerIcon(int pointerType) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType));
|
||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||
if (pointerIcon == null) {
|
||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||
}
|
||||
setPointerIcon(pointerIcon);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -48,5 +48,7 @@ public interface GodotRenderView {
|
|||
|
||||
GodotInputHandler getInputHandler();
|
||||
|
||||
void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY);
|
||||
|
||||
void setPointerIcon(int pointerType);
|
||||
}
|
||||
|
|
|
@ -36,7 +36,12 @@ import org.godotengine.godot.vulkan.VkSurfaceView;
|
|||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.SparseArray;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.PointerIcon;
|
||||
|
@ -44,10 +49,13 @@ import android.view.SurfaceView;
|
|||
|
||||
import androidx.annotation.Keep;
|
||||
|
||||
import java.io.InputStream;
|
||||
|
||||
public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView {
|
||||
private final Godot godot;
|
||||
private final GodotInputHandler mInputHandler;
|
||||
private final VkRenderer mRenderer;
|
||||
private final SparseArray<PointerIcon> customPointerIcons = new SparseArray<>();
|
||||
|
||||
public GodotVulkanRenderView(Context context, Godot godot) {
|
||||
super(context);
|
||||
|
@ -142,13 +150,50 @@ public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderV
|
|||
mInputHandler.onPointerCaptureChange(hasCapture);
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to configure the PointerIcon for the given type.
|
||||
*
|
||||
* Called from JNI
|
||||
*/
|
||||
@Keep
|
||||
@Override
|
||||
public void configurePointerIcon(int pointerType, String imagePath, float hotSpotX, float hotSpotY) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
try {
|
||||
Bitmap bitmap = null;
|
||||
if (!TextUtils.isEmpty(imagePath)) {
|
||||
if (godot.directoryAccessHandler.filesystemFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the file system
|
||||
bitmap = BitmapFactory.decodeFile(imagePath);
|
||||
} else if (godot.directoryAccessHandler.assetsFileExists(imagePath)) {
|
||||
// Try to load the bitmap from the assets directory
|
||||
AssetManager am = getContext().getAssets();
|
||||
InputStream imageInputStream = am.open(imagePath);
|
||||
bitmap = BitmapFactory.decodeStream(imageInputStream);
|
||||
}
|
||||
}
|
||||
|
||||
PointerIcon customPointerIcon = PointerIcon.create(bitmap, hotSpotX, hotSpotY);
|
||||
customPointerIcons.put(pointerType, customPointerIcon);
|
||||
} catch (Exception e) {
|
||||
// Reset the custom pointer icon
|
||||
customPointerIcons.delete(pointerType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* called from JNI to change pointer icon
|
||||
*/
|
||||
@Keep
|
||||
@Override
|
||||
public void setPointerIcon(int pointerType) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
setPointerIcon(PointerIcon.getSystemIcon(getContext(), pointerType));
|
||||
PointerIcon pointerIcon = customPointerIcons.get(pointerType);
|
||||
if (pointerIcon == null) {
|
||||
pointerIcon = PointerIcon.getSystemIcon(getContext(), pointerType);
|
||||
}
|
||||
setPointerIcon(pointerIcon);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -79,6 +79,9 @@ class DirectoryAccessHandler(context: Context) {
|
|||
private val assetsDirAccess = AssetsDirectoryAccess(context)
|
||||
private val fileSystemDirAccess = FilesystemDirectoryAccess(context)
|
||||
|
||||
fun assetsFileExists(assetsPath: String) = assetsDirAccess.fileExists(assetsPath)
|
||||
fun filesystemFileExists(path: String) = fileSystemDirAccess.fileExists(path)
|
||||
|
||||
private fun hasDirId(accessType: AccessType, dirId: Int): Boolean {
|
||||
return when (accessType) {
|
||||
ACCESS_RESOURCES -> assetsDirAccess.hasDirId(dirId)
|
||||
|
|
|
@ -42,6 +42,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
|
|||
|
||||
int android_device_api_level = android_get_device_api_level();
|
||||
if (android_device_api_level >= __ANDROID_API_N__) {
|
||||
_configure_pointer_icon = env->GetMethodID(_cls, "configurePointerIcon", "(ILjava/lang/String;FF)V");
|
||||
_set_pointer_icon = env->GetMethodID(_cls, "setPointerIcon", "(I)V");
|
||||
}
|
||||
if (android_device_api_level >= __ANDROID_API_O__) {
|
||||
|
@ -51,7 +52,7 @@ GodotJavaViewWrapper::GodotJavaViewWrapper(jobject godot_view) {
|
|||
}
|
||||
|
||||
bool GodotJavaViewWrapper::can_update_pointer_icon() const {
|
||||
return _set_pointer_icon != nullptr;
|
||||
return _configure_pointer_icon != nullptr && _set_pointer_icon != nullptr;
|
||||
}
|
||||
|
||||
bool GodotJavaViewWrapper::can_capture_pointer() const {
|
||||
|
@ -76,6 +77,16 @@ void GodotJavaViewWrapper::release_pointer_capture() {
|
|||
}
|
||||
}
|
||||
|
||||
void GodotJavaViewWrapper::configure_pointer_icon(int pointer_type, const String &image_path, const Vector2 &p_hotspot) {
|
||||
if (_configure_pointer_icon != nullptr) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
ERR_FAIL_NULL(env);
|
||||
|
||||
jstring jImagePath = env->NewStringUTF(image_path.utf8().get_data());
|
||||
env->CallVoidMethod(_godot_view, _configure_pointer_icon, pointer_type, jImagePath, p_hotspot.x, p_hotspot.y);
|
||||
}
|
||||
}
|
||||
|
||||
void GodotJavaViewWrapper::set_pointer_icon(int pointer_type) {
|
||||
if (_set_pointer_icon != nullptr) {
|
||||
JNIEnv *env = get_jni_env();
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#ifndef JAVA_GODOT_VIEW_WRAPPER_H
|
||||
#define JAVA_GODOT_VIEW_WRAPPER_H
|
||||
|
||||
#include "core/math/vector2.h"
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
|
||||
|
@ -45,6 +46,8 @@ private:
|
|||
|
||||
jmethodID _request_pointer_capture = 0;
|
||||
jmethodID _release_pointer_capture = 0;
|
||||
|
||||
jmethodID _configure_pointer_icon = 0;
|
||||
jmethodID _set_pointer_icon = 0;
|
||||
|
||||
public:
|
||||
|
@ -55,6 +58,8 @@ public:
|
|||
|
||||
void request_pointer_capture();
|
||||
void release_pointer_capture();
|
||||
|
||||
void configure_pointer_icon(int pointer_type, const String &image_path, const Vector2 &p_hotspot);
|
||||
void set_pointer_icon(int pointer_type);
|
||||
|
||||
~GodotJavaViewWrapper();
|
||||
|
|
|
@ -268,12 +268,16 @@ bool OS_Android::main_loop_iterate(bool *r_should_swap_buffers) {
|
|||
if (!main_loop) {
|
||||
return false;
|
||||
}
|
||||
DisplayServerAndroid::get_singleton()->reset_swap_buffers_flag();
|
||||
DisplayServerAndroid::get_singleton()->process_events();
|
||||
uint64_t current_frames_drawn = Engine::get_singleton()->get_frames_drawn();
|
||||
bool exit = Main::iteration();
|
||||
|
||||
if (r_should_swap_buffers) {
|
||||
*r_should_swap_buffers = !is_in_low_processor_usage_mode() || RenderingServer::get_singleton()->has_changed() || current_frames_drawn != Engine::get_singleton()->get_frames_drawn();
|
||||
*r_should_swap_buffers = !is_in_low_processor_usage_mode() ||
|
||||
DisplayServerAndroid::get_singleton()->should_swap_buffers() ||
|
||||
RenderingServer::get_singleton()->has_changed() ||
|
||||
current_frames_drawn != Engine::get_singleton()->get_frames_drawn();
|
||||
}
|
||||
|
||||
return exit;
|
||||
|
|
Loading…
Reference in a new issue