diff options
Diffstat (limited to 'platform/android/java/lib/src')
40 files changed, 598 insertions, 1733 deletions
diff --git a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java index 1dcc370d83..0700b78a28 100644 --- a/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java +++ b/platform/android/java/lib/src/com/google/android/vending/expansion/downloader/Constants.java @@ -233,4 +233,4 @@ public class Constants { */ public static final long ACTIVE_THREAD_WATCHDOG = 5*1000; -}
\ No newline at end of file +} diff --git a/platform/android/java/lib/src/org/godotengine/godot/Godot.java b/platform/android/java/lib/src/org/godotengine/godot/Godot.java index 7db4aa6597..957f6223a9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/Godot.java +++ b/platform/android/java/lib/src/org/godotengine/godot/Godot.java @@ -30,6 +30,13 @@ package org.godotengine.godot; +import org.godotengine.godot.input.GodotEditText; +import org.godotengine.godot.plugin.GodotPlugin; +import org.godotengine.godot.plugin.GodotPluginRegistry; +import org.godotengine.godot.utils.GodotNetUtils; +import org.godotengine.godot.utils.PermissionsUtil; +import org.godotengine.godot.xr.XRMode; + import android.annotation.SuppressLint; import android.app.Activity; import android.app.ActivityManager; @@ -55,8 +62,6 @@ import android.hardware.SensorManager; import android.os.Build; import android.os.Bundle; import android.os.Environment; -import android.os.Handler; -import android.os.Looper; import android.os.Messenger; import android.os.VibrationEffect; import android.os.Vibrator; @@ -64,7 +69,6 @@ import android.provider.Settings.Secure; import android.support.annotation.CallSuper; import android.support.annotation.Keep; import android.support.annotation.NonNull; -import android.support.annotation.Nullable; import android.support.v4.app.FragmentActivity; import android.view.Display; import android.view.KeyEvent; @@ -80,6 +84,7 @@ import android.widget.Button; import android.widget.FrameLayout; import android.widget.ProgressBar; import android.widget.TextView; + import com.google.android.vending.expansion.downloader.DownloadProgressInfo; import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller; import com.google.android.vending.expansion.downloader.DownloaderServiceMarshaller; @@ -87,6 +92,7 @@ import com.google.android.vending.expansion.downloader.Helpers; import com.google.android.vending.expansion.downloader.IDownloaderClient; import com.google.android.vending.expansion.downloader.IDownloaderService; import com.google.android.vending.expansion.downloader.IStub; + import java.io.File; import java.io.FileInputStream; import java.io.InputStream; @@ -94,13 +100,6 @@ import java.security.MessageDigest; import java.util.LinkedList; import java.util.List; import java.util.Locale; -import org.godotengine.godot.input.GodotEditText; -import org.godotengine.godot.payments.PaymentsManager; -import org.godotengine.godot.plugin.GodotPlugin; -import org.godotengine.godot.plugin.GodotPluginRegistry; -import org.godotengine.godot.utils.GodotNetUtils; -import org.godotengine.godot.utils.PermissionsUtil; -import org.godotengine.godot.xr.XRMode; public abstract class Godot extends FragmentActivity implements SensorEventListener, IDownloaderClient { @@ -157,7 +156,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe private String[] command_line; private boolean use_apk_expansion; - public GodotView mView; + public GodotRenderView mRenderView; private boolean godot_initialized = false; private SensorManager mSensorManager; @@ -174,21 +173,17 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe } public ResultCallback result_callback; - private PaymentsManager mPaymentsManager = null; - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - if (requestCode == PaymentsManager.REQUEST_CODE_FOR_PURCHASE) { - mPaymentsManager.processPurchaseResponse(resultCode, data); - } else if (result_callback != null) { + if (result_callback != null) { result_callback.callback(requestCode, resultCode, data); result_callback = null; - }; + } for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { plugin.onMainActivityResult(requestCode, resultCode, data); } - }; + } @Override public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) { @@ -202,12 +197,12 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe }; /** - * Invoked on the GL thread when the Godot main loop has started. + * Invoked on the render thread when the Godot main loop has started. */ @CallSuper - protected void onGLGodotMainLoopStarted() { + protected void onGodotMainLoopStarted() { for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { - plugin.onGLGodotMainLoopStarted(); + plugin.onGodotMainLoopStarted(); } } @@ -221,38 +216,45 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe setContentView(layout); // GodotEditText layout - GodotEditText edittext = new GodotEditText(this); - edittext.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); + GodotEditText editText = new GodotEditText(this); + editText.setLayoutParams(new ViewGroup.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); // ...add to FrameLayout - layout.addView(edittext); + layout.addView(editText); - mView = new GodotView(this, xrMode, use_32_bits, use_debug_opengl); - layout.addView(mView, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); - edittext.setView(mView); - io.setEdit(edittext); + GodotLib.setup(command_line); - mView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + final String videoDriver = GodotLib.getGlobal("rendering/quality/driver/driver_name"); + if (videoDriver.equals("Vulkan")) { + mRenderView = new GodotVulkanRenderView(this); + } else { + mRenderView = new GodotGLRenderView(this, xrMode, use_32_bits, use_debug_opengl); + } + + View view = mRenderView.getView(); + layout.addView(view, new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)); + editText.setView(mRenderView); + io.setEdit(editText); + + view.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { Point fullSize = new Point(); getWindowManager().getDefaultDisplay().getSize(fullSize); Rect gameSize = new Rect(); - mView.getWindowVisibleDisplayFrame(gameSize); + mRenderView.getView().getWindowVisibleDisplayFrame(gameSize); final int keyboardHeight = fullSize.y - gameSize.bottom; GodotLib.setVirtualKeyboardHeight(keyboardHeight); } }); - final String[] current_command_line = command_line; - mView.queueEvent(new Runnable() { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { - GodotLib.setup(current_command_line); // Must occur after GodotLib.setup has completed. for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { - plugin.onGLRegisterPluginWithGodotNative(); + plugin.onRegisterPluginWithGodotNative(); } setKeepScreenOn("True".equals(GodotLib.getGlobal("display/window/energy_saving/keep_screen_on"))); @@ -392,7 +394,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe */ @Keep private Surface getSurface() { - return mView.getHolder().getSurface(); + return mRenderView.getView().getHolder().getSurface(); } /** @@ -445,8 +447,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe result_callback = null; - mPaymentsManager = PaymentsManager.createManager(this).initService(); - godot_initialized = true; } @@ -603,7 +603,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe @Override protected void onDestroy() { - if (mPaymentsManager != null) mPaymentsManager.destroy(); for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { plugin.onMainDestroy(); } @@ -628,7 +627,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe } return; } - mView.onPause(); + mRenderView.onActivityPaused(); mSensorManager.unregisterListener(this); @@ -666,7 +665,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe return; } - mView.onResume(); + mRenderView.onActivityResumed(); mSensorManager.registerListener(this, mAccelerometer, SensorManager.SENSOR_DELAY_GAME); mSensorManager.registerListener(this, mGravity, SensorManager.SENSOR_DELAY_GAME); @@ -732,8 +731,8 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe final float z = adjustedValues[2]; final int typeOfSensor = event.sensor.getType(); - if (mView != null) { - mView.queueEvent(new Runnable() { + if (mRenderView != null) { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { if (typeOfSensor == Sensor.TYPE_ACCELEROMETER) { @@ -784,8 +783,8 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe } } - if (shouldQuit && mView != null) { - mView.queueEvent(new Runnable() { + if (shouldQuit && mRenderView != null) { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { GodotLib.back(); @@ -795,13 +794,13 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe } /** - * Queue a runnable to be run on the GL thread. + * Queue a runnable to be run on the render thread. * <p> - * This must be called after the GL thread has started. + * This must be called after the render thread has started. */ - public final void runOnGLThread(@NonNull Runnable action) { - if (mView != null) { - mView.queueEvent(action); + public final void runOnRenderThread(@NonNull Runnable action) { + if (mRenderView != null) { + mRenderView.queueOnRenderThread(action); } } @@ -858,7 +857,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe if (evcount == 0) return true; - if (mView != null) { + if (mRenderView != null) { final int[] arr = new int[event.getPointerCount() * 3]; for (int i = 0; i < event.getPointerCount(); i++) { @@ -871,7 +870,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe //System.out.printf("gaction: %d\n",event.getAction()); final int action = event.getAction() & MotionEvent.ACTION_MASK; - mView.queueEvent(new Runnable() { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { switch (action) { @@ -922,7 +921,7 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe for (int i = cc.length; --i >= 0; cnt += cc[i] != 0 ? 1 : 0) ; if (cnt == 0) return super.onKeyMultiple(inKeyCode, repeatCount, event); - mView.queueEvent(new Runnable() { + mRenderView.queueOnRenderThread(new Runnable() { // This method will be called on the rendering thread: public void run() { for (int i = 0, n = cc.length; i < n; i++) { @@ -938,10 +937,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe return true; } - public PaymentsManager getPaymentsManager() { - return mPaymentsManager; - } - public boolean requestPermission(String p_name) { return PermissionsUtil.requestPermission(p_name, this); } @@ -1048,6 +1043,6 @@ public abstract class Godot extends FragmentActivity implements SensorEventListe progress.mOverallTotal)); } public void initInputDevices() { - mView.initInputDevices(); + mRenderView.initInputDevices(); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java b/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java index 1fb242d0bc..fa95e82e7a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderAlarmReceiver.java @@ -35,6 +35,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager.NameNotFoundException; import android.util.Log; + import com.google.android.vending.expansion.downloader.DownloaderClientMarshaller; /** diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java b/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java index 7e74e8a80d..434da95bc0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotDownloaderService.java @@ -33,6 +33,7 @@ package org.godotengine.godot; import android.content.Context; import android.content.SharedPreferences; import android.util.Log; + import com.google.android.vending.expansion.downloader.impl.DownloaderService; /** diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java index 8d3c2ae319..5d8ac09643 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotView.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotGLRenderView.java @@ -1,5 +1,5 @@ /*************************************************************************/ -/* GodotView.java */ +/* GodotGLRenderView.java */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -29,12 +29,7 @@ /*************************************************************************/ package org.godotengine.godot; -import android.annotation.SuppressLint; -import android.graphics.PixelFormat; -import android.opengl.GLSurfaceView; -import android.view.GestureDetector; -import android.view.KeyEvent; -import android.view.MotionEvent; + import org.godotengine.godot.input.GodotGestureHandler; import org.godotengine.godot.input.GodotInputHandler; import org.godotengine.godot.utils.GLUtils; @@ -46,6 +41,14 @@ import org.godotengine.godot.xr.regular.RegularConfigChooser; import org.godotengine.godot.xr.regular.RegularContextFactory; import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser; +import android.annotation.SuppressLint; +import android.graphics.PixelFormat; +import android.opengl.GLSurfaceView; +import android.view.GestureDetector; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SurfaceView; + /** * A simple GLSurfaceView sub-class that demonstrate how to perform * OpenGL ES 2.0 rendering into a GL Surface. Note the following important @@ -64,16 +67,14 @@ import org.godotengine.godot.xr.regular.RegularFallbackConfigChooser; * that matches it exactly (with regards to red/green/blue/alpha channels * bit depths). Failure to do so would result in an EGL_BAD_MATCH error. */ -public class GodotView extends GLSurfaceView { - - private static String TAG = GodotView.class.getSimpleName(); +public class GodotGLRenderView extends GLSurfaceView implements GodotRenderView { private final Godot activity; private final GodotInputHandler inputHandler; private final GestureDetector detector; private final GodotRenderer godotRenderer; - public GodotView(Godot activity, XRMode xrMode, boolean p_use_32_bits, boolean p_use_debug_opengl) { + public GodotGLRenderView(Godot activity, XRMode xrMode, boolean p_use_32_bits, boolean p_use_debug_opengl) { super(activity); GLUtils.use_32 = p_use_32_bits; GLUtils.use_debug_opengl = p_use_debug_opengl; @@ -85,10 +86,36 @@ public class GodotView extends GLSurfaceView { init(xrMode, false, 16, 0); } + @Override + public SurfaceView getView() { + return this; + } + + @Override public void initInputDevices() { this.inputHandler.initInputDevices(); } + @Override + public void queueOnRenderThread(Runnable event) { + queueEvent(event); + } + + @Override + public void onActivityPaused() { + onPause(); + } + + @Override + public void onActivityResumed() { + onResume(); + } + + @Override + public void onBackPressed() { + activity.onBackPressed(); + } + @SuppressLint("ClickableViewAccessibility") @Override public boolean onTouchEvent(MotionEvent event) { @@ -170,10 +197,6 @@ public class GodotView extends GLSurfaceView { setRenderer(godotRenderer); } - public void onBackPressed() { - activity.onBackPressed(); - } - @Override public void onResume() { super.onResume(); diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java index 68ce40ba10..2eb6f4e313 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotIO.java @@ -29,6 +29,9 @@ /*************************************************************************/ package org.godotengine.godot; + +import org.godotengine.godot.input.*; + import android.content.*; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -39,11 +42,10 @@ import android.os.*; import android.util.DisplayMetrics; import android.util.Log; import android.util.SparseArray; + import java.io.IOException; import java.io.InputStream; import java.util.Locale; -import org.godotengine.godot.input.*; -//android.os.Build // Wrapper for native library @@ -53,8 +55,6 @@ public class GodotIO { Godot activity; GodotEditText edit; - MediaPlayer mediaPlayer; - final int SCREEN_LANDSCAPE = 0; final int SCREEN_PORTRAIT = 1; final int SCREEN_REVERSE_LANDSCAPE = 2; @@ -530,44 +530,14 @@ public class GodotIO { activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR); } break; } - }; - - public void setEdit(GodotEditText _edit) { - edit = _edit; } - public void playVideo(String p_path) { - Uri filePath = Uri.parse(p_path); - mediaPlayer = new MediaPlayer(); - - try { - mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); - mediaPlayer.setDataSource(activity.getApplicationContext(), filePath); - mediaPlayer.prepare(); - mediaPlayer.start(); - } catch (IOException e) { - System.out.println("IOError while playing video"); - } - } - - public boolean isVideoPlaying() { - if (mediaPlayer != null) { - return mediaPlayer.isPlaying(); - } - return false; + public int getScreenOrientation() { + return activity.getRequestedOrientation(); } - public void pauseVideo() { - if (mediaPlayer != null) { - mediaPlayer.pause(); - } - } - - public void stopVideo() { - if (mediaPlayer != null) { - mediaPlayer.release(); - mediaPlayer = null; - } + public void setEdit(GodotEditText _edit) { + edit = _edit; } public static final int SYSTEM_DIR_DESKTOP = 0; diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java index 89a65aea24..9383781150 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java @@ -32,6 +32,8 @@ package org.godotengine.godot; import android.app.Activity; import android.hardware.SensorEvent; +import android.view.Surface; + import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; @@ -72,11 +74,11 @@ public class GodotLib { public static native void resize(int width, int height); /** - * Invoked on the GL thread when the underlying Android surface is created or recreated. + * Invoked on the render thread when the underlying Android surface is created or recreated. + * @param p_surface * @param p_32_bits - * @see android.opengl.GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig) */ - public static native void newcontext(boolean p_32_bits); + public static native void newcontext(Surface p_surface, boolean p_32_bits); /** * Forward {@link Activity#onBackPressed()} event from the main thread to the GL thread. diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/RequestParams.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java index 25fa10647d..170c433c9c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/RequestParams.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderView.java @@ -1,5 +1,5 @@ /*************************************************************************/ -/* RequestParams.java */ +/* GodotRenderView.java */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,58 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -package org.godotengine.godot.utils; +package org.godotengine.godot; -import java.util.ArrayList; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import org.apache.http.NameValuePair; -import org.apache.http.message.BasicNameValuePair; +import android.view.SurfaceView; -/** - * - * @author Luis Linietsky <luis.linietsky@gmail.com> - */ -public class RequestParams { +public interface GodotRenderView { - private HashMap<String, String> params; - private String url; + abstract public SurfaceView getView(); - public RequestParams() { - params = new HashMap<String, String>(); - } + abstract public void initInputDevices(); - public void put(String key, String value) { - params.put(key, value); - } + abstract public void queueOnRenderThread(Runnable event); - public String get(String key) { - return params.get(key); - } + abstract public void onActivityPaused(); + abstract public void onActivityResumed(); - public void remove(Object key) { - params.remove(key); - } - - public boolean has(String key) { - return params.containsKey(key); - } - - public List<NameValuePair> toPairsList() { - List<NameValuePair> fields = new ArrayList<NameValuePair>(); - - for (String key : params.keySet()) { - fields.add(new BasicNameValuePair(key, this.get(key))); - } - return fields; - } - - public String getUrl() { - return url; - } - - public void setUrl(String url) { - this.url = url; - } + abstract public void onBackPressed(); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java index ee9a2aee4f..39858e5fee 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotRenderer.java @@ -30,13 +30,15 @@ package org.godotengine.godot; +import org.godotengine.godot.plugin.GodotPlugin; +import org.godotengine.godot.plugin.GodotPluginRegistry; +import org.godotengine.godot.utils.GLUtils; + import android.content.Context; import android.opengl.GLSurfaceView; + import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; -import org.godotengine.godot.plugin.GodotPlugin; -import org.godotengine.godot.plugin.GodotPluginRegistry; -import org.godotengine.godot.utils.GLUtils; /** * Godot's renderer implementation. @@ -70,7 +72,7 @@ class GodotRenderer implements GLSurfaceView.Renderer { } public void onSurfaceCreated(GL10 gl, EGLConfig config) { - GodotLib.newcontext(GLUtils.use_32); + GodotLib.newcontext(null, GLUtils.use_32); for (GodotPlugin plugin : pluginRegistry.getAllPlugins()) { plugin.onGLSurfaceCreated(gl, config); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java new file mode 100644 index 0000000000..3a36c512a2 --- /dev/null +++ b/platform/android/java/lib/src/org/godotengine/godot/GodotVulkanRenderView.java @@ -0,0 +1,143 @@ +/*************************************************************************/ +/* GodotVulkanRenderView.java */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* 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; + +import org.godotengine.godot.input.GodotGestureHandler; +import org.godotengine.godot.input.GodotInputHandler; +import org.godotengine.godot.vulkan.VkRenderer; +import org.godotengine.godot.vulkan.VkSurfaceView; + +import android.annotation.SuppressLint; +import android.view.GestureDetector; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.SurfaceView; + +public class GodotVulkanRenderView extends VkSurfaceView implements GodotRenderView { + + private final Godot mActivity; + private final GodotInputHandler mInputHandler; + private final GestureDetector mGestureDetector; + private final VkRenderer mRenderer; + + public GodotVulkanRenderView(Godot activity) { + super(activity); + + mActivity = activity; + mInputHandler = new GodotInputHandler(this); + mGestureDetector = new GestureDetector(mActivity, new GodotGestureHandler(this)); + mRenderer = new VkRenderer(); + + setFocusableInTouchMode(true); + startRenderer(mRenderer); + } + + @Override + public SurfaceView getView() { + return this; + } + + @Override + public void initInputDevices() { + mInputHandler.initInputDevices(); + } + + @Override + public void queueOnRenderThread(Runnable event) { + queueOnVkThread(event); + } + + @Override + public void onActivityPaused() { + onPause(); + } + + @Override + public void onActivityResumed() { + onResume(); + } + + @Override + public void onBackPressed() { + mActivity.onBackPressed(); + } + + @SuppressLint("ClickableViewAccessibility") + @Override + public boolean onTouchEvent(MotionEvent event) { + super.onTouchEvent(event); + mGestureDetector.onTouchEvent(event); + return mActivity.gotTouchEvent(event); + } + + @Override + public boolean onKeyUp(final int keyCode, KeyEvent event) { + return mInputHandler.onKeyUp(keyCode, event) || super.onKeyUp(keyCode, event); + } + + @Override + public boolean onKeyDown(final int keyCode, KeyEvent event) { + return mInputHandler.onKeyDown(keyCode, event) || super.onKeyDown(keyCode, event); + } + + @Override + public boolean onGenericMotionEvent(MotionEvent event) { + return mInputHandler.onGenericMotionEvent(event) || super.onGenericMotionEvent(event); + } + + @Override + public void onResume() { + super.onResume(); + + queueOnVkThread(new Runnable() { + @Override + public void run() { + // Resume the renderer + mRenderer.onVkResume(); + GodotLib.focusin(); + } + }); + } + + @Override + public void onPause() { + super.onPause(); + + queueOnVkThread(new Runnable() { + @Override + public void run() { + GodotLib.focusout(); + // Pause the renderer + mRenderer.onVkPause(); + } + }); + } +} 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 e901b4b36d..547c093419 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 @@ -29,6 +29,9 @@ /*************************************************************************/ package org.godotengine.godot.input; + +import org.godotengine.godot.*; + import android.content.Context; import android.os.Handler; import android.os.Message; @@ -38,8 +41,8 @@ import android.view.KeyEvent; import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.EditText; + import java.lang.ref.WeakReference; -import org.godotengine.godot.*; public class GodotEditText extends EditText { // =========================================================== @@ -51,7 +54,7 @@ public class GodotEditText extends EditText { // =========================================================== // Fields // =========================================================== - private GodotView mView; + private GodotRenderView mRenderView; private GodotTextInputWrapper mInputWrapper; private EditHandler sHandler = new EditHandler(this); private String mOriginText; @@ -76,22 +79,22 @@ public class GodotEditText extends EditText { // =========================================================== public GodotEditText(final Context context) { super(context); - this.initView(); + initView(); } public GodotEditText(final Context context, final AttributeSet attrs) { super(context, attrs); - this.initView(); + initView(); } public GodotEditText(final Context context, final AttributeSet attrs, final int defStyle) { super(context, attrs, defStyle); - this.initView(); + initView(); } protected void initView() { - this.setPadding(0, 0, 0, 0); - this.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); + setPadding(0, 0, 0, 0); + setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI); } private void handleMessage(final Message msg) { @@ -106,7 +109,7 @@ public class GodotEditText extends EditText { edit.mInputWrapper.setOriginText(text); edit.addTextChangedListener(edit.mInputWrapper); setMaxInputLength(edit, msg.arg1); - final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.showSoftInput(edit, 0); } } break; @@ -115,9 +118,9 @@ public class GodotEditText extends EditText { GodotEditText edit = (GodotEditText)msg.obj; edit.removeTextChangedListener(mInputWrapper); - final InputMethodManager imm = (InputMethodManager)mView.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); + final InputMethodManager imm = (InputMethodManager)mRenderView.getView().getContext().getSystemService(Context.INPUT_METHOD_SERVICE); imm.hideSoftInputFromWindow(edit.getWindowToken(), 0); - edit.mView.requestFocus(); + edit.mRenderView.getView().requestFocus(); } break; } } @@ -135,12 +138,12 @@ public class GodotEditText extends EditText { // =========================================================== // Getter & Setter // =========================================================== - public void setView(final GodotView view) { - this.mView = view; + public void setView(final GodotRenderView view) { + mRenderView = view; if (mInputWrapper == null) - mInputWrapper = new GodotTextInputWrapper(mView, this); - this.setOnEditorActionListener(mInputWrapper); - view.requestFocus(); + mInputWrapper = new GodotTextInputWrapper(mRenderView, this); + setOnEditorActionListener(mInputWrapper); + view.getView().requestFocus(); } // =========================================================== @@ -152,7 +155,7 @@ public class GodotEditText extends EditText { /* Let GlSurfaceView get focus if back key is input. */ if (keyCode == KeyEvent.KEYCODE_BACK) { - this.mView.requestFocus(); + mRenderView.getView().requestFocus(); } return true; @@ -162,7 +165,7 @@ public class GodotEditText extends EditText { // Methods // =========================================================== public void showKeyboard(String p_existing_text, int p_max_input_length) { - this.mOriginText = p_existing_text; + mOriginText = p_existing_text; final Message msg = new Message(); msg.what = HANDLER_OPEN_IME_KEYBOARD; diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java index 1a38a9c3d2..0ac82dbfe4 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotGestureHandler.java @@ -30,26 +30,27 @@ package org.godotengine.godot.input; +import org.godotengine.godot.GodotLib; +import org.godotengine.godot.GodotRenderView; + import android.util.Log; import android.view.GestureDetector; import android.view.MotionEvent; -import org.godotengine.godot.GodotLib; -import org.godotengine.godot.GodotView; /** - * Handles gesture input related events for the {@link GodotView} view. + * Handles gesture input related events for the {@link GodotRenderView} view. * https://developer.android.com/reference/android/view/GestureDetector.SimpleOnGestureListener */ public class GodotGestureHandler extends GestureDetector.SimpleOnGestureListener { - private final GodotView godotView; + private final GodotRenderView mRenderView; - public GodotGestureHandler(GodotView godotView) { - this.godotView = godotView; + public GodotGestureHandler(GodotRenderView godotView) { + mRenderView = godotView; } private void queueEvent(Runnable task) { - godotView.queueEvent(task); + mRenderView.queueOnRenderThread(task); } @Override 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 e00ca86c41..cea58f27e6 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 @@ -32,37 +32,39 @@ package org.godotengine.godot.input; import static org.godotengine.godot.utils.GLUtils.DEBUG; +import org.godotengine.godot.GodotLib; +import org.godotengine.godot.GodotRenderView; +import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener; + import android.util.Log; import android.view.InputDevice; import android.view.InputDevice.MotionRange; import android.view.KeyEvent; import android.view.MotionEvent; + import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import org.godotengine.godot.GodotLib; -import org.godotengine.godot.GodotView; -import org.godotengine.godot.input.InputManagerCompat.InputDeviceListener; /** - * Handles input related events for the {@link GodotView} view. + * Handles input related events for the {@link GodotRenderView} view. */ public class GodotInputHandler implements InputDeviceListener { - private final ArrayList<Joystick> joysticksDevices = new ArrayList<Joystick>(); + private final ArrayList<Joystick> mJoysticksDevices = new ArrayList<Joystick>(); - private final GodotView godotView; - private final InputManagerCompat inputManager; + private final GodotRenderView mRenderView; + private final InputManagerCompat mInputManager; - public GodotInputHandler(GodotView godotView) { - this.godotView = godotView; - this.inputManager = InputManagerCompat.Factory.getInputManager(godotView.getContext()); - this.inputManager.registerInputDeviceListener(this, null); + public GodotInputHandler(GodotRenderView godotView) { + mRenderView = godotView; + mInputManager = InputManagerCompat.Factory.getInputManager(mRenderView.getView().getContext()); + mInputManager.registerInputDeviceListener(this, null); } private void queueEvent(Runnable task) { - godotView.queueEvent(task); + mRenderView.queueOnRenderThread(task); } private boolean isKeyEvent_GameDevice(int source) { @@ -113,7 +115,7 @@ public class GodotInputHandler implements InputDeviceListener { public boolean onKeyDown(final int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { - godotView.onBackPressed(); + mRenderView.onBackPressed(); // press 'back' button should not terminate program //normal handle 'back' event in game logic return true; @@ -164,7 +166,7 @@ public class GodotInputHandler implements InputDeviceListener { // Check if the device exists if (device_id > -1) { - Joystick joy = joysticksDevices.get(device_id); + Joystick joy = mJoysticksDevices.get(device_id); for (int i = 0; i < joy.axes.size(); i++) { InputDevice.MotionRange range = joy.axes.get(i); @@ -208,11 +210,11 @@ public class GodotInputHandler implements InputDeviceListener { public void initInputDevices() { /* initially add input devices*/ - int[] deviceIds = inputManager.getInputDeviceIds(); + int[] deviceIds = mInputManager.getInputDeviceIds(); for (int deviceId : deviceIds) { - InputDevice device = inputManager.getInputDevice(deviceId); + InputDevice device = mInputManager.getInputDevice(deviceId); if (DEBUG) { - Log.v("GodotView", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); + Log.v("GodotInputHandler", String.format("init() deviceId:%d, Name:%s\n", deviceId, device.getName())); } onInputDeviceAdded(deviceId); } @@ -224,13 +226,13 @@ public class GodotInputHandler implements InputDeviceListener { // Check if the device has not been already added if (id < 0) { - InputDevice device = inputManager.getInputDevice(deviceId); + InputDevice device = mInputManager.getInputDevice(deviceId); //device can be null if deviceId is not found if (device != null) { int sources = device.getSources(); if (((sources & InputDevice.SOURCE_GAMEPAD) == InputDevice.SOURCE_GAMEPAD) || ((sources & InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK)) { - id = joysticksDevices.size(); + id = mJoysticksDevices.size(); Joystick joy = new Joystick(); joy.device_id = deviceId; @@ -249,7 +251,7 @@ public class GodotInputHandler implements InputDeviceListener { } } - joysticksDevices.add(joy); + mJoysticksDevices.add(joy); final int device_id = id; final String name = joy.name; @@ -270,7 +272,7 @@ public class GodotInputHandler implements InputDeviceListener { // Check if the evice has not been already removed if (device_id > -1) { - joysticksDevices.remove(device_id); + mJoysticksDevices.remove(device_id); queueEvent(new Runnable() { @Override @@ -360,8 +362,8 @@ public class GodotInputHandler implements InputDeviceListener { } private int findJoystickDevice(int device_id) { - for (int i = 0; i < joysticksDevices.size(); i++) { - if (joysticksDevices.get(i).device_id == device_id) { + for (int i = 0; i < mJoysticksDevices.size(); i++) { + if (mJoysticksDevices.get(i).device_id == device_id) { return i; } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java index 8d9b5461a1..9cd08de529 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotTextInputWrapper.java @@ -29,6 +29,9 @@ /*************************************************************************/ package org.godotengine.godot.input; + +import org.godotengine.godot.*; + import android.content.Context; import android.text.Editable; import android.text.TextWatcher; @@ -37,7 +40,6 @@ import android.view.inputmethod.EditorInfo; import android.view.inputmethod.InputMethodManager; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; -import org.godotengine.godot.*; public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListener { // =========================================================== @@ -48,7 +50,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene // =========================================================== // Fields // =========================================================== - private final GodotView mView; + private final GodotRenderView mRenderView; private final GodotEditText mEdit; private String mOriginText; @@ -56,9 +58,9 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene // Constructors // =========================================================== - public GodotTextInputWrapper(final GodotView view, final GodotEditText edit) { - this.mView = view; - this.mEdit = edit; + public GodotTextInputWrapper(final GodotRenderView view, final GodotEditText edit) { + mRenderView = view; + mEdit = edit; } // =========================================================== @@ -66,13 +68,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene // =========================================================== private boolean isFullScreenEdit() { - final TextView textField = this.mEdit; + final TextView textField = mEdit; final InputMethodManager imm = (InputMethodManager)textField.getContext().getSystemService(Context.INPUT_METHOD_SERVICE); return imm.isFullscreenMode(); } public void setOriginText(final String originText) { - this.mOriginText = originText; + mOriginText = originText; } // =========================================================== @@ -87,7 +89,7 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene public void beforeTextChanged(final CharSequence pCharSequence, final int start, final int count, final int after) { //Log.d(TAG, "beforeTextChanged(" + pCharSequence + ")start: " + start + ",count: " + count + ",after: " + after); - mView.queueEvent(new Runnable() { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { for (int i = 0; i < count; ++i) { @@ -106,12 +108,17 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene for (int i = start; i < start + count; ++i) { newChars[i - start] = pCharSequence.charAt(i); } - mView.queueEvent(new Runnable() { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { for (int i = 0; i < count; ++i) { - GodotLib.key(0, 0, newChars[i], true); - GodotLib.key(0, 0, newChars[i], false); + int key = newChars[i]; + if (key == '\n') { + // Return keys are handled through action events + continue; + } + GodotLib.key(0, 0, key, true); + GodotLib.key(0, 0, key, false); } } }); @@ -119,10 +126,10 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene @Override public boolean onEditorAction(final TextView pTextView, final int pActionID, final KeyEvent pKeyEvent) { - if (this.mEdit == pTextView && this.isFullScreenEdit()) { + if (mEdit == pTextView && isFullScreenEdit()) { final String characters = pKeyEvent.getCharacters(); - mView.queueEvent(new Runnable() { + mRenderView.queueOnRenderThread(new Runnable() { @Override public void run() { for (int i = 0; i < characters.length(); i++) { @@ -134,8 +141,13 @@ public class GodotTextInputWrapper implements TextWatcher, OnEditorActionListene }); } - if (pActionID == EditorInfo.IME_ACTION_DONE) { - this.mView.requestFocus(); + if (pActionID == EditorInfo.IME_NULL) { + // Enter key has been pressed + GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, true); + GodotLib.key(KeyEvent.KEYCODE_ENTER, KeyEvent.KEYCODE_ENTER, 0, false); + + mRenderView.getView().requestFocus(); + return true; } return false; } diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java b/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java index e4bafa7ff9..3b88609cc9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/InputManagerV16.java @@ -23,6 +23,7 @@ import android.os.Build; import android.os.Handler; import android.view.InputDevice; import android.view.MotionEvent; + import java.util.HashMap; import java.util.Map; diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java b/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java index 0c1bdb32aa..1f3fe1e527 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java +++ b/platform/android/java/lib/src/org/godotengine/godot/input/Joystick.java @@ -31,6 +31,7 @@ package org.godotengine.godot.input; import android.view.InputDevice.MotionRange; + import java.util.ArrayList; /** diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java deleted file mode 100644 index 95cc48f536..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/ConsumeTask.java +++ /dev/null @@ -1,116 +0,0 @@ -/*************************************************************************/ -/* ConsumeTask.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.content.Context; -import android.os.AsyncTask; -import android.os.RemoteException; -import com.android.vending.billing.IInAppBillingService; -import java.lang.ref.WeakReference; - -abstract public class ConsumeTask { - - private Context context; - private IInAppBillingService mService; - - private String mSku; - private String mToken; - - private static class ConsumeAsyncTask extends AsyncTask<String, String, String> { - - private WeakReference<ConsumeTask> mTask; - - ConsumeAsyncTask(ConsumeTask consume) { - mTask = new WeakReference<>(consume); - } - - @Override - protected String doInBackground(String... strings) { - ConsumeTask consume = mTask.get(); - if (consume != null) { - return consume.doInBackground(strings); - } - return null; - } - - @Override - protected void onPostExecute(String param) { - ConsumeTask consume = mTask.get(); - if (consume != null) { - consume.onPostExecute(param); - } - } - } - - public ConsumeTask(IInAppBillingService mService, Context context) { - this.context = context; - this.mService = mService; - } - - public void consume(final String sku) { - mSku = sku; - PaymentsCache pc = new PaymentsCache(context); - Boolean isBlocked = pc.getConsumableFlag("block", sku); - mToken = pc.getConsumableValue("token", sku); - if (!isBlocked && mToken == null) { - // Consuming task is processing - } else if (!isBlocked) { - return; - } else if (mToken == null) { - this.error("No token for sku:" + sku); - return; - } - new ConsumeAsyncTask(this).execute(); - } - - private String doInBackground(String... params) { - try { - int response = mService.consumePurchase(3, context.getPackageName(), mToken); - if (response == 0 || response == 8) { - return null; - } - } catch (RemoteException e) { - return e.getMessage(); - } - return "Some error"; - } - - private void onPostExecute(String param) { - if (param == null) { - success(new PaymentsCache(context).getConsumableValue("ticket", mSku)); - } else { - error(param); - } - } - - abstract protected void success(String ticket); - abstract protected void error(String message); -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java deleted file mode 100644 index 23d693cc8c..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/HandlePurchaseTask.java +++ /dev/null @@ -1,93 +0,0 @@ -/*************************************************************************/ -/* HandlePurchaseTask.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.app.Activity; -import android.content.Intent; -import org.json.JSONException; -import org.json.JSONObject; - -abstract public class HandlePurchaseTask { - - private Activity context; - - public HandlePurchaseTask(Activity context) { - this.context = context; - } - - public void handlePurchaseRequest(int resultCode, Intent data) { - //Log.d("XXX", "Handling purchase response"); - if (resultCode == Activity.RESULT_OK) { - try { - //int responseCode = data.getIntExtra("RESPONSE_CODE", 0); - PaymentsCache pc = new PaymentsCache(context); - - String purchaseData = data.getStringExtra("INAPP_PURCHASE_DATA"); - //Log.d("XXX", "Purchase data:" + purchaseData); - String dataSignature = data.getStringExtra("INAPP_DATA_SIGNATURE"); - //Log.d("XXX", "Purchase signature:" + dataSignature); - //Log.d("SARLANGA", purchaseData); - - JSONObject jo = new JSONObject(purchaseData); - //String sku = jo.getString("productId"); - //alert("You have bought the " + sku + ". Excellent choice, aventurer!"); - //String orderId = jo.getString("orderId"); - //String packageName = jo.getString("packageName"); - String productId = jo.getString("productId"); - //Long purchaseTime = jo.getLong("purchaseTime"); - //Integer state = jo.getInt("purchaseState"); - String developerPayload = jo.getString("developerPayload"); - String purchaseToken = jo.getString("purchaseToken"); - - if (!pc.getConsumableValue("validation_hash", productId).equals(developerPayload)) { - error("Untrusted callback"); - return; - } - //Log.d("XXX", "Este es el product ID:" + productId); - pc.setConsumableValue("ticket_signautre", productId, dataSignature); - pc.setConsumableValue("ticket", productId, purchaseData); - pc.setConsumableFlag("block", productId, true); - pc.setConsumableValue("token", productId, purchaseToken); - - success(productId, dataSignature, purchaseData); - return; - } catch (JSONException e) { - error(e.getMessage()); - } - } else if (resultCode == Activity.RESULT_CANCELED) { - canceled(); - } - } - - abstract protected void success(String sku, String signature, String ticket); - abstract protected void error(String message); - abstract protected void canceled(); -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java b/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java deleted file mode 100644 index 84a7eda6e0..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsCache.java +++ /dev/null @@ -1,72 +0,0 @@ -/*************************************************************************/ -/* PaymentsCache.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; - -public class PaymentsCache { - - public Context context; - - public PaymentsCache(Context context) { - this.context = context; - } - - public void setConsumableFlag(String set, String sku, Boolean flag) { - SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putBoolean(sku, flag); - editor.apply(); - } - - public boolean getConsumableFlag(String set, String sku) { - SharedPreferences sharedPref = context.getSharedPreferences( - "consumables_" + set, Context.MODE_PRIVATE); - return sharedPref.getBoolean(sku, false); - } - - public void setConsumableValue(String set, String sku, String value) { - SharedPreferences sharedPref = context.getSharedPreferences("consumables_" + set, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString(sku, value); - //Log.d("XXX", "Setting asset: consumables_" + set + ":" + sku); - editor.apply(); - } - - public String getConsumableValue(String set, String sku) { - SharedPreferences sharedPref = context.getSharedPreferences( - "consumables_" + set, Context.MODE_PRIVATE); - //Log.d("XXX", "Getting asset: consumables_" + set + ":" + sku); - return sharedPref.getString(sku, null); - } -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java b/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java deleted file mode 100644 index 9bf6650f84..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/PaymentsManager.java +++ /dev/null @@ -1,418 +0,0 @@ -/*************************************************************************/ -/* PaymentsManager.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.app.Activity; -import android.content.ComponentName; -import android.content.Context; -import android.content.Intent; -import android.content.ServiceConnection; -import android.os.Bundle; -import android.os.IBinder; -import android.os.RemoteException; -import android.text.TextUtils; -import android.util.Log; -import com.android.vending.billing.IInAppBillingService; -import java.util.ArrayList; -import java.util.Arrays; -import org.json.JSONException; -import org.json.JSONObject; - -public class PaymentsManager { - - public static final int BILLING_RESPONSE_RESULT_OK = 0; - public static final int REQUEST_CODE_FOR_PURCHASE = 0x1001; - private static boolean auto_consume = true; - - private Activity activity; - IInAppBillingService mService; - - public void setActivity(Activity activity) { - this.activity = activity; - } - - public static PaymentsManager createManager(Activity activity) { - PaymentsManager manager = new PaymentsManager(activity); - return manager; - } - - private PaymentsManager(Activity activity) { - this.activity = activity; - } - - public PaymentsManager initService() { - Intent intent = new Intent("com.android.vending.billing.InAppBillingService.BIND"); - intent.setPackage("com.android.vending"); - activity.bindService( - intent, - mServiceConn, - Context.BIND_AUTO_CREATE); - return this; - } - - public void destroy() { - if (mService != null) { - activity.unbindService(mServiceConn); - } - } - - ServiceConnection mServiceConn = new ServiceConnection() { - @Override - public void onServiceDisconnected(ComponentName name) { - mService = null; - - // At this stage, godotPayment might not have been initialized yet. - if (godotPayment != null) { - godotPayment.callbackDisconnected(); - } - } - - @Override - public void onServiceConnected(ComponentName name, IBinder service) { - mService = IInAppBillingService.Stub.asInterface(service); - - // At this stage, godotPayment might not have been initialized yet. - if (godotPayment != null) { - godotPayment.callbackConnected(); - } - } - }; - - public void requestPurchase(final String sku, String transactionId) { - new PurchaseTask(mService, activity) { - @Override - protected void error(String message) { - godotPayment.callbackFail(message); - } - - @Override - protected void canceled() { - godotPayment.callbackCancel(); - } - - @Override - protected void alreadyOwned() { - godotPayment.callbackAlreadyOwned(sku); - } - } - .purchase(sku, transactionId); - } - - public boolean isConnected() { - return mService != null; - } - - public void consumeUnconsumedPurchases() { - new ReleaseAllConsumablesTask(mService, activity) { - @Override - protected void success(String sku, String receipt, String signature, String token) { - godotPayment.callbackSuccessProductMassConsumed(receipt, signature, sku); - } - - @Override - protected void error(String message) { - Log.d("godot", "consumeUnconsumedPurchases :" + message); - godotPayment.callbackFailConsume(message); - } - - @Override - protected void notRequired() { - Log.d("godot", "callbackSuccessNoUnconsumedPurchases :"); - godotPayment.callbackSuccessNoUnconsumedPurchases(); - } - } - .consumeItAll(); - } - - public void requestPurchased() { - try { - PaymentsCache pc = new PaymentsCache(activity); - - String continueToken = null; - - do { - Bundle bundle = mService.getPurchases(3, activity.getPackageName(), "inapp", continueToken); - - if (bundle.getInt("RESPONSE_CODE") == 0) { - - final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); - final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); - - if (myPurchases == null || myPurchases.size() == 0) { - godotPayment.callbackPurchased("", "", ""); - return; - } - - for (int i = 0; i < myPurchases.size(); i++) { - - try { - String receipt = myPurchases.get(i); - JSONObject inappPurchaseData = new JSONObject(receipt); - String sku = inappPurchaseData.getString("productId"); - String token = inappPurchaseData.getString("purchaseToken"); - String signature = mySignatures.get(i); - - pc.setConsumableValue("ticket_signautre", sku, signature); - pc.setConsumableValue("ticket", sku, receipt); - pc.setConsumableFlag("block", sku, true); - pc.setConsumableValue("token", sku, token); - - godotPayment.callbackPurchased(receipt, signature, sku); - } catch (JSONException e) { - } - } - } - continueToken = bundle.getString("INAPP_CONTINUATION_TOKEN"); - Log.d("godot", "continue token = " + continueToken); - } while (!TextUtils.isEmpty(continueToken)); - } catch (Exception e) { - Log.d("godot", "Error requesting purchased products:" + e.getClass().getName() + ":" + e.getMessage()); - } - } - - public void processPurchaseResponse(int resultCode, Intent data) { - new HandlePurchaseTask(activity) { - @Override - protected void success(final String sku, final String signature, final String ticket) { - godotPayment.callbackSuccess(ticket, signature, sku); - - if (auto_consume) { - new ConsumeTask(mService, activity) { - @Override - protected void success(String ticket) { - } - - @Override - protected void error(String message) { - godotPayment.callbackFail(message); - } - } - .consume(sku); - } - } - - @Override - protected void error(String message) { - godotPayment.callbackFail(message); - } - - @Override - protected void canceled() { - godotPayment.callbackCancel(); - } - } - .handlePurchaseRequest(resultCode, data); - } - - public void validatePurchase(String purchaseToken, final String sku) { - - new ValidateTask(activity, godotPayment) { - @Override - protected void success() { - - new ConsumeTask(mService, activity) { - @Override - protected void success(String ticket) { - godotPayment.callbackSuccess(ticket, null, sku); - } - - @Override - protected void error(String message) { - godotPayment.callbackFail(message); - } - } - .consume(sku); - } - - @Override - protected void error(String message) { - godotPayment.callbackFail(message); - } - - @Override - protected void canceled() { - godotPayment.callbackCancel(); - } - } - .validatePurchase(sku); - } - - public void setAutoConsume(boolean autoConsume) { - auto_consume = autoConsume; - } - - public void consume(final String sku) { - new ConsumeTask(mService, activity) { - @Override - protected void success(String ticket) { - godotPayment.callbackSuccessProductMassConsumed(ticket, "", sku); - } - - @Override - protected void error(String message) { - godotPayment.callbackFailConsume(message); - } - } - .consume(sku); - } - - // Workaround to bug where sometimes response codes come as Long instead of Integer - int getResponseCodeFromBundle(Bundle b) { - Object o = b.get("RESPONSE_CODE"); - if (o == null) { - //logDebug("Bundle with null response code, assuming OK (known issue)"); - return BILLING_RESPONSE_RESULT_OK; - } else if (o instanceof Integer) - return ((Integer)o).intValue(); - else if (o instanceof Long) - return (int)((Long)o).longValue(); - else { - //logError("Unexpected type for bundle response code."); - //logError(o.getClass().getName()); - throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName()); - } - } - - /** - * Returns a human-readable description for the given response code. - * - * @param code The response code - * @return A human-readable string explaining the result code. - * It also includes the result code numerically. - */ - public static String getResponseDesc(int code) { - String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" - + - "3:Billing Unavailable/4:Item unavailable/" - + - "5:Developer Error/6:Error/7:Item Already Owned/" - + - "8:Item not owned") - .split("/"); - String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" - + - "-1002:Bad response received/" - + - "-1003:Purchase signature verification failed/" - + - "-1004:Send intent failed/" - + - "-1005:User cancelled/" - + - "-1006:Unknown purchase response/" - + - "-1007:Missing token/" - + - "-1008:Unknown error/" - + - "-1009:Subscriptions not available/" - + - "-1010:Invalid consumption attempt") - .split("/"); - - if (code <= -1000) { - int index = -1000 - code; - if (index >= 0 && index < iabhelper_msgs.length) - return iabhelper_msgs[index]; - else - return String.valueOf(code) + ":Unknown IAB Helper Error"; - } else if (code < 0 || code >= iab_msgs.length) - return String.valueOf(code) + ":Unknown"; - else - return iab_msgs[code]; - } - - public void querySkuDetails(final String[] list) { - (new Thread(new Runnable() { - @Override - public void run() { - ArrayList<String> skuList = new ArrayList<String>(Arrays.asList(list)); - if (skuList.size() == 0) { - return; - } - // Split the sku list in blocks of no more than 20 elements. - ArrayList<ArrayList<String>> packs = new ArrayList<ArrayList<String>>(); - ArrayList<String> tempList; - int n = skuList.size() / 20; - int mod = skuList.size() % 20; - for (int i = 0; i < n; i++) { - tempList = new ArrayList<String>(); - for (String s : skuList.subList(i * 20, i * 20 + 20)) { - tempList.add(s); - } - packs.add(tempList); - } - if (mod != 0) { - tempList = new ArrayList<String>(); - for (String s : skuList.subList(n * 20, n * 20 + mod)) { - tempList.add(s); - } - packs.add(tempList); - } - for (ArrayList<String> skuPartList : packs) { - Bundle querySkus = new Bundle(); - querySkus.putStringArrayList("ITEM_ID_LIST", skuPartList); - Bundle skuDetails = null; - try { - skuDetails = mService.getSkuDetails(3, activity.getPackageName(), "inapp", querySkus); - if (!skuDetails.containsKey("DETAILS_LIST")) { - int response = getResponseCodeFromBundle(skuDetails); - if (response != BILLING_RESPONSE_RESULT_OK) { - godotPayment.errorSkuDetail(getResponseDesc(response)); - } else { - godotPayment.errorSkuDetail("No error but no detail list."); - } - return; - } - - ArrayList<String> responseList = skuDetails.getStringArrayList("DETAILS_LIST"); - - for (String thisResponse : responseList) { - Log.d("godot", "response = " + thisResponse); - godotPayment.addSkuDetail(thisResponse); - } - } catch (RemoteException e) { - e.printStackTrace(); - godotPayment.errorSkuDetail("RemoteException error!"); - } - } - godotPayment.completeSkuDetail(); - } - })) - .start(); - } - - private GodotPaymentInterface godotPayment; - - public void setBaseSingleton(GodotPaymentInterface godotPaymentInterface) { - this.godotPayment = godotPaymentInterface; - } -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java deleted file mode 100644 index 09c9349124..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/PurchaseTask.java +++ /dev/null @@ -1,118 +0,0 @@ -/*************************************************************************/ -/* PurchaseTask.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.app.Activity; -import android.app.PendingIntent; -import android.content.Intent; -import android.content.IntentSender.SendIntentException; -import android.os.Bundle; -import android.os.RemoteException; -import android.util.Log; -import com.android.vending.billing.IInAppBillingService; - -abstract public class PurchaseTask { - - private Activity context; - - private IInAppBillingService mService; - public PurchaseTask(IInAppBillingService mService, Activity context) { - this.context = context; - this.mService = mService; - } - - private boolean isLooping = false; - - public void purchase(final String sku, final String transactionId) { - Log.d("XXX", "Starting purchase for: " + sku); - PaymentsCache pc = new PaymentsCache(context); - Boolean isBlocked = pc.getConsumableFlag("block", sku); - /* - if(isBlocked){ - Log.d("XXX", "Is awaiting payment confirmation"); - error("Awaiting payment confirmation"); - return; - } - */ - final String hash = transactionId; - - Bundle buyIntentBundle; - try { - buyIntentBundle = mService.getBuyIntent(3, context.getApplicationContext().getPackageName(), sku, "inapp", hash); - } catch (RemoteException e) { - //Log.d("XXX", "Error: " + e.getMessage()); - error(e.getMessage()); - return; - } - Object rc = buyIntentBundle.get("RESPONSE_CODE"); - int responseCode = 0; - if (rc == null) { - responseCode = PaymentsManager.BILLING_RESPONSE_RESULT_OK; - } else if (rc instanceof Integer) { - responseCode = ((Integer)rc).intValue(); - } else if (rc instanceof Long) { - responseCode = (int)((Long)rc).longValue(); - } - //Log.d("XXX", "Buy intent response code: " + responseCode); - if (responseCode == 1 || responseCode == 3 || responseCode == 4) { - canceled(); - return; - } - if (responseCode == 7) { - alreadyOwned(); - return; - } - - PendingIntent pendingIntent = buyIntentBundle.getParcelable("BUY_INTENT"); - pc.setConsumableValue("validation_hash", sku, hash); - try { - if (context == null) { - //Log.d("XXX", "No context!"); - } - if (pendingIntent == null) { - //Log.d("XXX", "No pending intent"); - } - //Log.d("XXX", "Starting activity for purchase!"); - context.startIntentSenderForResult( - pendingIntent.getIntentSender(), - PaymentsManager.REQUEST_CODE_FOR_PURCHASE, - new Intent(), - Integer.valueOf(0), Integer.valueOf(0), - Integer.valueOf(0)); - } catch (SendIntentException e) { - error(e.getMessage()); - } - } - - abstract protected void error(String message); - abstract protected void canceled(); - abstract protected void alreadyOwned(); -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java deleted file mode 100644 index a101780511..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/ReleaseAllConsumablesTask.java +++ /dev/null @@ -1,141 +0,0 @@ -/*************************************************************************/ -/* ReleaseAllConsumablesTask.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.content.Context; -import android.os.AsyncTask; -import android.os.Bundle; -import android.util.Log; -import com.android.vending.billing.IInAppBillingService; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import org.json.JSONException; -import org.json.JSONObject; - -abstract public class ReleaseAllConsumablesTask { - - private Context context; - private IInAppBillingService mService; - - private static class ReleaseAllConsumablesAsyncTask extends AsyncTask<String, String, String> { - - private WeakReference<ReleaseAllConsumablesTask> mTask; - private String mSku; - private String mReceipt; - private String mSignature; - private String mToken; - - ReleaseAllConsumablesAsyncTask(ReleaseAllConsumablesTask task, String sku, String receipt, String signature, String token) { - mTask = new WeakReference<ReleaseAllConsumablesTask>(task); - - mSku = sku; - mReceipt = receipt; - mSignature = signature; - mToken = token; - } - - @Override - protected String doInBackground(String... params) { - ReleaseAllConsumablesTask consume = mTask.get(); - if (consume != null) { - return consume.doInBackground(mToken); - } - return null; - } - - @Override - protected void onPostExecute(String param) { - ReleaseAllConsumablesTask consume = mTask.get(); - if (consume != null) { - consume.success(mSku, mReceipt, mSignature, mToken); - } - } - } - - public ReleaseAllConsumablesTask(IInAppBillingService mService, Context context) { - this.context = context; - this.mService = mService; - } - - public void consumeItAll() { - try { - //Log.d("godot", "consumeItall for " + context.getPackageName()); - Bundle bundle = mService.getPurchases(3, context.getPackageName(), "inapp", null); - - if (bundle.getInt("RESPONSE_CODE") == 0) { - - final ArrayList<String> myPurchases = bundle.getStringArrayList("INAPP_PURCHASE_DATA_LIST"); - final ArrayList<String> mySignatures = bundle.getStringArrayList("INAPP_DATA_SIGNATURE_LIST"); - - if (myPurchases == null || myPurchases.size() == 0) { - //Log.d("godot", "No purchases!"); - notRequired(); - return; - } - - //Log.d("godot", "# products to be consumed:" + myPurchases.size()); - for (int i = 0; i < myPurchases.size(); i++) { - - try { - String receipt = myPurchases.get(i); - JSONObject inappPurchaseData = new JSONObject(receipt); - String sku = inappPurchaseData.getString("productId"); - String token = inappPurchaseData.getString("purchaseToken"); - String signature = mySignatures.get(i); - //Log.d("godot", "A punto de consumir un item con token:" + token + "\n" + receipt); - new ReleaseAllConsumablesAsyncTask(this, sku, receipt, signature, token).execute(); - } catch (JSONException e) { - } - } - } - } catch (Exception e) { - Log.d("godot", "Error releasing products:" + e.getClass().getName() + ":" + e.getMessage()); - } - } - - private String doInBackground(String token) { - try { - //Log.d("godot", "Requesting to consume an item with token ." + token); - int response = mService.consumePurchase(3, context.getPackageName(), token); - //Log.d("godot", "consumePurchase response: " + response); - if (response == 0 || response == 8) { - return null; - } - } catch (Exception e) { - Log.d("godot", "Error " + e.getClass().getName() + ":" + e.getMessage()); - } - return null; - } - - abstract protected void success(String sku, String receipt, String signature, String token); - abstract protected void error(String message); - abstract protected void notRequired(); -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java b/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java deleted file mode 100644 index 10c314aecf..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/ValidateTask.java +++ /dev/null @@ -1,141 +0,0 @@ -/*************************************************************************/ -/* ValidateTask.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.payments; - -import android.app.Activity; -import android.app.ProgressDialog; -import android.os.AsyncTask; -import java.lang.ref.WeakReference; -import org.godotengine.godot.utils.HttpRequester; -import org.godotengine.godot.utils.RequestParams; -import org.json.JSONException; -import org.json.JSONObject; - -abstract public class ValidateTask { - - private Activity context; - private GodotPaymentInterface godotPayments; - private ProgressDialog dialog; - private String mSku; - - private static class ValidateAsyncTask extends AsyncTask<String, String, String> { - private WeakReference<ValidateTask> mTask; - - ValidateAsyncTask(ValidateTask task) { - mTask = new WeakReference<>(task); - } - - @Override - protected void onPreExecute() { - ValidateTask task = mTask.get(); - if (task != null) { - task.onPreExecute(); - } - } - - @Override - protected String doInBackground(String... params) { - ValidateTask task = mTask.get(); - if (task != null) { - return task.doInBackground(params); - } - return null; - } - - @Override - protected void onPostExecute(String response) { - ValidateTask task = mTask.get(); - if (task != null) { - task.onPostExecute(response); - } - } - } - - public ValidateTask(Activity context, GodotPaymentInterface godotPayments) { - this.context = context; - this.godotPayments = godotPayments; - } - - public void validatePurchase(final String sku) { - mSku = sku; - new ValidateAsyncTask(this).execute(); - } - - private void onPreExecute() { - dialog = ProgressDialog.show(context, null, "Please wait..."); - } - - private String doInBackground(String... params) { - PaymentsCache pc = new PaymentsCache(context); - String url = godotPayments.getPurchaseValidationUrlPrefix(); - RequestParams param = new RequestParams(); - param.setUrl(url); - param.put("ticket", pc.getConsumableValue("ticket", mSku)); - param.put("purchaseToken", pc.getConsumableValue("token", mSku)); - param.put("sku", mSku); - //Log.d("XXX", "Haciendo request a " + url); - //Log.d("XXX", "ticket: " + pc.getConsumableValue("ticket", sku)); - //Log.d("XXX", "purchaseToken: " + pc.getConsumableValue("token", sku)); - //Log.d("XXX", "sku: " + sku); - param.put("package", context.getApplicationContext().getPackageName()); - HttpRequester requester = new HttpRequester(); - String jsonResponse = requester.post(param); - //Log.d("XXX", "Validation response:\n"+jsonResponse); - return jsonResponse; - } - - private void onPostExecute(String response) { - if (dialog != null) { - dialog.dismiss(); - dialog = null; - } - JSONObject j; - try { - j = new JSONObject(response); - if (j.getString("status").equals("OK")) { - success(); - return; - } else if (j.getString("status") != null) { - error(j.getString("message")); - } else { - error("Connection error"); - } - } catch (JSONException e) { - error(e.getMessage()); - } catch (Exception e) { - error(e.getMessage()); - } - } - - abstract protected void success(); - abstract protected void error(String message); - abstract protected void canceled(); -} 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 d5bf4fc70e..a42bcb28ce 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 @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,19 +30,27 @@ package org.godotengine.godot.plugin; +import org.godotengine.godot.BuildConfig; +import org.godotengine.godot.Godot; + import android.app.Activity; import android.content.Intent; import android.support.annotation.NonNull; import android.support.annotation.Nullable; +import android.text.TextUtils; +import android.util.Log; +import android.view.Surface; import android.view.View; + import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.opengles.GL10; -import org.godotengine.godot.Godot; /** * Base class for the Godot Android plugins. @@ -69,7 +77,10 @@ import org.godotengine.godot.Godot; */ public abstract class GodotPlugin { + private static final String TAG = GodotPlugin.class.getSimpleName(); + private final Godot godot; + private final ConcurrentHashMap<String, SignalInfo> registeredSignals = new ConcurrentHashMap<>(); public GodotPlugin(Godot godot) { this.godot = godot; @@ -84,8 +95,10 @@ public abstract class GodotPlugin { /** * Register the plugin with Godot native code. + * + * This method is invoked on the render thread. */ - public final void onGLRegisterPluginWithGodotNative() { + public final void onRegisterPluginWithGodotNative() { nativeRegisterSingleton(getPluginName()); Class clazz = getClass(); @@ -115,6 +128,13 @@ public abstract class GodotPlugin { nativeRegisterMethod(getPluginName(), method.getName(), method.getReturnType().getName(), pt); } + // Register the signals for this plugin. + for (SignalInfo signalInfo : getPluginSignals()) { + String signalName = signalInfo.getName(); + nativeRegisterSignal(getPluginName(), signalName, signalInfo.getParamTypesNames()); + registeredSignals.put(signalName, signalInfo); + } + // Get the list of gdnative libraries to register. Set<String> gdnativeLibrariesPaths = getPluginGDNativeLibrariesPaths(); if (!gdnativeLibrariesPaths.isEmpty()) { @@ -169,9 +189,9 @@ public abstract class GodotPlugin { public boolean onMainBackPressed() { return false; } /** - * Invoked on the GL thread when the Godot main loop has started. + * Invoked on the render thread when the Godot main loop has started. */ - public void onGLGodotMainLoopStarted() {} + public void onGodotMainLoopStarted() {} /** * Invoked once per frame on the GL thread after the frame is drawn. @@ -190,6 +210,22 @@ public abstract class GodotPlugin { public void onGLSurfaceCreated(GL10 gl, EGLConfig config) {} /** + * Invoked once per frame on the Vulkan thread after the frame is drawn. + */ + public void onVkDrawFrame() {} + + /** + * Called on the Vulkan thread after the surface is created and whenever the surface size + * changes. + */ + public void onVkSurfaceChanged(Surface surface, int width, int height) {} + + /** + * Called on the Vulkan thread when the surface is created or recreated. + */ + public void onVkSurfaceCreated(Surface surface) {} + + /** * Returns the name of the plugin. * <p> * This value must match the one listed in the plugin '<meta-data>' manifest entry. @@ -201,7 +237,17 @@ public abstract class GodotPlugin { * Returns the list of methods to be exposed to Godot. */ @NonNull - public abstract List<String> getPluginMethods(); + public List<String> getPluginMethods() { + return Collections.emptyList(); + } + + /** + * Returns the list of signals to be exposed to Godot. + */ + @NonNull + public Set<SignalInfo> getPluginSignals() { + return Collections.emptySet(); + } /** * Returns the paths for the plugin's gdnative libraries. @@ -225,12 +271,55 @@ public abstract class GodotPlugin { } /** - * Queue the specified action to be run on the GL thread. + * Queue the specified action to be run on the render thread. * - * @param action the action to run on the GL thread + * @param action the action to run on the render thread */ - protected void runOnGLThread(Runnable action) { - godot.runOnGLThread(action); + protected void runOnRenderThread(Runnable action) { + godot.runOnRenderThread(action); + } + + /** + * Emit a registered Godot signal. + * @param signalName + * @param signalArgs + */ + protected void emitSignal(final String signalName, final Object... signalArgs) { + try { + // Check that the given signal is among the registered set. + SignalInfo signalInfo = registeredSignals.get(signalName); + if (signalInfo == null) { + throw new IllegalArgumentException( + "Signal " + signalName + " is not registered for this plugin."); + } + + // Validate the arguments count. + Class<?>[] signalParamTypes = signalInfo.getParamTypes(); + if (signalArgs.length != signalParamTypes.length) { + throw new IllegalArgumentException( + "Invalid arguments count. Should be " + signalParamTypes.length + " but is " + signalArgs.length); + } + + // Validate the argument's types. + for (int i = 0; i < signalParamTypes.length; i++) { + if (!signalParamTypes[i].isInstance(signalArgs[i])) { + throw new IllegalArgumentException( + "Invalid type for argument #" + i + ". Should be of type " + signalParamTypes[i].getName()); + } + } + + runOnRenderThread(new Runnable() { + @Override + public void run() { + nativeEmitSignal(getPluginName(), signalName, signalArgs); + } + }); + } catch (IllegalArgumentException exception) { + Log.w(TAG, exception.getMessage()); + if (BuildConfig.DEBUG) { + throw exception; + } + } } /** @@ -253,4 +342,20 @@ public abstract class GodotPlugin { * @param gdnlibPaths Paths to the libraries relative to the 'assets' directory. */ private native void nativeRegisterGDNativeLibraries(String[] gdnlibPaths); + + /** + * Used to complete registration of the {@link GodotPlugin} instance's methods. + * @param pluginName Name of the plugin + * @param signalName Name of the signal to register + * @param signalParamTypes Signal parameters types + */ + private native void nativeRegisterSignal(String pluginName, String signalName, String[] signalParamTypes); + + /** + * Used to emit signal by {@link GodotPlugin} instance. + * @param pluginName Name of the plugin + * @param signalName Name of the signal to emit + * @param signalParams Signal parameters + */ + private native void nativeEmitSignal(String pluginName, String signalName, Object[] signalParams); } diff --git a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java index b6d949b7bf..7bc8f2c03f 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/GodotPluginRegistry.java @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ /* */ /* Permission is hereby granted, free of charge, to any person obtaining */ /* a copy of this software and associated documentation files (the */ @@ -30,12 +30,15 @@ package org.godotengine.godot.plugin; +import org.godotengine.godot.Godot; + import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.os.Bundle; import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; + import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.util.Arrays; @@ -43,7 +46,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import org.godotengine.godot.Godot; /** * Registry used to load and access the registered Godot Android plugins. diff --git a/platform/android/java/lib/src/org/godotengine/godot/payments/GodotPaymentInterface.java b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java index 6ac7338b30..b940d679f0 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/payments/GodotPaymentInterface.java +++ b/platform/android/java/lib/src/org/godotengine/godot/plugin/SignalInfo.java @@ -1,5 +1,5 @@ /*************************************************************************/ -/* GodotPaymentInterface.java */ +/* SignalInfo.java */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,70 +28,72 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -package org.godotengine.godot.payments; - -public interface GodotPaymentInterface { - void purchase(String sku, String transactionId); - - void consumeUnconsumedPurchases(); - - String getSignature(); - - void callbackSuccess(String ticket, String signature, String sku); - - void callbackSuccessProductMassConsumed(String ticket, String signature, String sku); - - void callbackSuccessNoUnconsumedPurchases(); - - void callbackFailConsume(String message); - - void callbackFail(String message); - - void callbackCancel(); - - void callbackAlreadyOwned(String sku); - - int getPurchaseCallbackId(); - - void setPurchaseCallbackId(int purchaseCallbackId); - - String getPurchaseValidationUrlPrefix(); - - void setPurchaseValidationUrlPrefix(String url); - - String getAccessToken(); - - void setAccessToken(String accessToken); - - void setTransactionId(String transactionId); - - String getTransactionId(); - - // request purchased items are not consumed - void requestPurchased(); - - // callback for requestPurchased() - void callbackPurchased(String receipt, String signature, String sku); - - void callbackDisconnected(); - - void callbackConnected(); - - // true if connected, false otherwise - boolean isConnected(); - - // consume item automatically after purchase. default is true. - void setAutoConsume(boolean autoConsume); - - // consume a specific item - void consume(String sku); - - // query in app item detail info - void querySkuDetails(String[] list); - - void addSkuDetail(String itemJson); - - void completeSkuDetail(); - - void errorSkuDetail(String errorMessage); +package org.godotengine.godot.plugin; + +import android.support.annotation.NonNull; +import android.text.TextUtils; + +import java.util.Arrays; + +/** + * Store information about a {@link GodotPlugin}'s signal. + */ +public final class SignalInfo { + + private final String name; + private final Class<?>[] paramTypes; + private final String[] paramTypesNames; + + public SignalInfo(@NonNull String signalName, Class<?>... paramTypes) { + if (TextUtils.isEmpty(signalName)) { + throw new IllegalArgumentException("Invalid signal name: " + signalName); + } + + this.name = signalName; + this.paramTypes = paramTypes == null ? new Class<?>[ 0 ] : paramTypes; + this.paramTypesNames = new String[this.paramTypes.length]; + for (int i = 0; i < this.paramTypes.length; i++) { + this.paramTypesNames[i] = this.paramTypes[i].getName(); + } + } + + public String getName() { + return name; + } + + Class<?>[] getParamTypes() { + return paramTypes; + } + + String[] getParamTypesNames() { + return paramTypesNames; + } + + @Override + public String toString() { + return "SignalInfo{" + + + "name='" + name + '\'' + + ", paramsTypes=" + Arrays.toString(paramTypes) + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (!(o instanceof SignalInfo)) { + return false; + } + + SignalInfo that = (SignalInfo)o; + + return name.equals(that.name); + } + + @Override + public int hashCode() { + return name.hashCode(); + } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java b/platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java deleted file mode 100644 index c78e8c1c66..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/CustomSSLSocketFactory.java +++ /dev/null @@ -1,69 +0,0 @@ -/*************************************************************************/ -/* CustomSSLSocketFactory.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.utils; -import java.io.IOException; -import java.net.Socket; -import java.net.UnknownHostException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.UnrecoverableKeyException; -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManagerFactory; -import org.apache.http.conn.ssl.SSLSocketFactory; - -/** - * - * @author Luis Linietsky <luis.linietsky@gmail.com> - */ -public class CustomSSLSocketFactory extends SSLSocketFactory { - SSLContext sslContext = SSLContext.getInstance("TLS"); - - public CustomSSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException { - super(truststore); - - TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); - tmf.init(truststore); - - sslContext.init(null, tmf.getTrustManagers(), null); - } - - @Override - public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException { - return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose); - } - - @Override - public Socket createSocket() throws IOException { - return sslContext.getSocketFactory().createSocket(); - } -} diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java index 9d29551f89..291847723c 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GLUtils.java @@ -31,6 +31,7 @@ package org.godotengine.godot.utils; import android.util.Log; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java index 011d426c7e..bb1667afda 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java +++ b/platform/android/java/lib/src/org/godotengine/godot/utils/GodotNetUtils.java @@ -30,10 +30,11 @@ package org.godotengine.godot.utils; +import org.godotengine.godot.Godot; + import android.content.Context; import android.net.wifi.WifiManager; import android.util.Log; -import org.godotengine.godot.Godot; /** * This class handles Android-specific networking functions. diff --git a/platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java b/platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java deleted file mode 100644 index 68f9a83597..0000000000 --- a/platform/android/java/lib/src/org/godotengine/godot/utils/HttpRequester.java +++ /dev/null @@ -1,227 +0,0 @@ -/*************************************************************************/ -/* HttpRequester.java */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* 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.utils; - -import android.content.Context; -import android.content.SharedPreferences; -import android.util.Log; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.UnsupportedEncodingException; -import java.security.KeyStore; -import java.util.Date; -import org.apache.http.HttpResponse; -import org.apache.http.HttpVersion; -import org.apache.http.client.ClientProtocolException; -import org.apache.http.client.HttpClient; -import org.apache.http.client.entity.UrlEncodedFormEntity; -import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.client.methods.HttpUriRequest; -import org.apache.http.conn.ClientConnectionManager; -import org.apache.http.conn.scheme.PlainSocketFactory; -import org.apache.http.conn.scheme.Scheme; -import org.apache.http.conn.scheme.SchemeRegistry; -import org.apache.http.conn.ssl.SSLSocketFactory; -import org.apache.http.impl.client.DefaultHttpClient; -import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager; -import org.apache.http.params.BasicHttpParams; -import org.apache.http.params.HttpConnectionParams; -import org.apache.http.params.HttpParams; -import org.apache.http.params.HttpProtocolParams; -import org.apache.http.protocol.HTTP; -import org.apache.http.util.EntityUtils; - -/** - * - * @author Luis Linietsky <luis.linietsky@gmail.com> - */ -public class HttpRequester { - - private Context context; - private static final int TTL = 600000; // 10 minutos - private long cttl = 0; - - public HttpRequester() { - //Log.d("XXX", "Creando http request sin contexto"); - } - - public HttpRequester(Context context) { - this.context = context; - //Log.d("XXX", "Creando http request con contexto"); - } - - public String post(RequestParams params) { - HttpPost httppost = new HttpPost(params.getUrl()); - try { - httppost.setEntity(new UrlEncodedFormEntity(params.toPairsList())); - return request(httppost); - } catch (UnsupportedEncodingException e) { - return null; - } - } - - public String get(RequestParams params) { - String response = getResponseFromCache(params.getUrl()); - if (response == null) { - //Log.d("XXX", "Cache miss!"); - HttpGet httpget = new HttpGet(params.getUrl()); - long timeInit = new Date().getTime(); - response = request(httpget); - long delay = new Date().getTime() - timeInit; - Log.d("HttpRequest::get(url)", "Url: " + params.getUrl() + " downloaded in " + String.format("%.03f", delay / 1000.0f) + " seconds"); - if (response == null || response.length() == 0) { - response = ""; - } else { - saveResponseIntoCache(params.getUrl(), response); - } - } - Log.d("XXX", "Req: " + params.getUrl()); - Log.d("XXX", "Resp: " + response); - return response; - } - - private String request(HttpUriRequest request) { - //Log.d("XXX", "Haciendo request a: " + request.getURI() ); - Log.d("PPP", "Haciendo request a: " + request.getURI()); - long init = new Date().getTime(); - HttpClient httpclient = getNewHttpClient(); - HttpParams httpParameters = httpclient.getParams(); - HttpConnectionParams.setConnectionTimeout(httpParameters, 0); - HttpConnectionParams.setSoTimeout(httpParameters, 0); - HttpConnectionParams.setTcpNoDelay(httpParameters, true); - try { - HttpResponse response = httpclient.execute(request); - Log.d("PPP", "Fin de request (" + (new Date().getTime() - init) + ") a: " + request.getURI()); - //Log.d("XXX1", "Status:" + response.getStatusLine().toString()); - if (response.getStatusLine().getStatusCode() == 200) { - String strResponse = EntityUtils.toString(response.getEntity()); - //Log.d("XXX2", strResponse); - return strResponse; - } else { - Log.d("XXX3", "Response status code:" + response.getStatusLine().getStatusCode() + "\n" + EntityUtils.toString(response.getEntity())); - return null; - } - - } catch (ClientProtocolException e) { - Log.d("XXX3", e.getMessage()); - } catch (IOException e) { - Log.d("XXX4", e.getMessage()); - } - return null; - } - - private HttpClient getNewHttpClient() { - try { - KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); - trustStore.load(null, null); - - SSLSocketFactory sf = new CustomSSLSocketFactory(trustStore); - sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); - - HttpParams params = new BasicHttpParams(); - HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1); - HttpProtocolParams.setContentCharset(params, HTTP.UTF_8); - - SchemeRegistry registry = new SchemeRegistry(); - registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); - registry.register(new Scheme("https", sf, 443)); - - ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry); - - return new DefaultHttpClient(ccm, params); - } catch (Exception e) { - return new DefaultHttpClient(); - } - } - - private static String convertStreamToString(InputStream is) { - BufferedReader reader = new BufferedReader(new InputStreamReader(is)); - StringBuilder sb = new StringBuilder(); - String line = null; - try { - while ((line = reader.readLine()) != null) { - sb.append((line + "\n")); - } - } catch (IOException e) { - e.printStackTrace(); - } finally { - try { - is.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return sb.toString(); - } - - public void saveResponseIntoCache(String request, String response) { - if (context == null) { - //Log.d("XXX", "No context, cache failed!"); - return; - } - SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPref.edit(); - editor.putString("request_" + Crypt.md5(request), response); - editor.putLong("request_" + Crypt.md5(request) + "_ttl", new Date().getTime() + getTtl()); - editor.apply(); - } - - public String getResponseFromCache(String request) { - if (context == null) { - Log.d("XXX", "No context, cache miss"); - return null; - } - SharedPreferences sharedPref = context.getSharedPreferences("http_get_cache", Context.MODE_PRIVATE); - long ttl = getResponseTtl(request); - if (ttl == 0l || (new Date().getTime() - ttl) > 0l) { - Log.d("XXX", "Cache invalid ttl:" + ttl + " vs now:" + new Date().getTime()); - return null; - } - return sharedPref.getString("request_" + Crypt.md5(request), null); - } - - public long getResponseTtl(String request) { - SharedPreferences sharedPref = context.getSharedPreferences( - "http_get_cache", Context.MODE_PRIVATE); - return sharedPref.getLong("request_" + Crypt.md5(request) + "_ttl", 0l); - } - - public long getTtl() { - return cttl > 0 ? cttl : TTL; - } - - public void setTtl(long ttl) { - this.cttl = (ttl * 1000) + new Date().getTime(); - } -} 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 7cf32b00fe..4000e63fbe 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 @@ -30,15 +30,18 @@ package org.godotengine.godot.utils; +import org.godotengine.godot.Godot; + import android.Manifest; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.PermissionInfo; import android.os.Build; import android.support.v4.content.ContextCompat; +import android.util.Log; + import java.util.ArrayList; import java.util.List; -import org.godotengine.godot.Godot; /** * This class includes utility functions for Android permissions related operations. @@ -46,6 +49,8 @@ import org.godotengine.godot.Godot; */ public final class PermissionsUtil { + private static final String TAG = PermissionsUtil.class.getSimpleName(); + static final int REQUEST_RECORD_AUDIO_PERMISSION = 1; static final int REQUEST_CAMERA_PERMISSION = 2; static final int REQUEST_VIBRATE_PERMISSION = 3; @@ -113,8 +118,8 @@ public final class PermissionsUtil { dangerousPermissions.add(manifestPermission); } } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - return false; + // Skip this permission and continue. + Log.w(TAG, "Unable to identify permission " + manifestPermission, e); } } @@ -153,8 +158,8 @@ public final class PermissionsUtil { dangerousPermissions.add(manifestPermission); } } catch (PackageManager.NameNotFoundException e) { - e.printStackTrace(); - return new String[0]; + // Skip this permission and continue. + Log.w(TAG, "Unable to identify permission " + manifestPermission, e); } } diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt index 67faad8ddd..608ad48df9 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkRenderer.kt @@ -33,6 +33,11 @@ package org.godotengine.godot.vulkan import android.view.Surface +import org.godotengine.godot.Godot +import org.godotengine.godot.GodotLib +import org.godotengine.godot.plugin.GodotPlugin +import org.godotengine.godot.plugin.GodotPluginRegistry + /** * Responsible to setting up and driving the Vulkan rendering logic. * @@ -48,52 +53,64 @@ import android.view.Surface */ internal class VkRenderer { + private val pluginRegistry: GodotPluginRegistry = GodotPluginRegistry.getPluginRegistry() + /** * Called when the surface is created and signals the beginning of rendering. */ fun onVkSurfaceCreated(surface: Surface) { - nativeOnVkSurfaceCreated(surface) + // TODO: properly implement surface re-creation: + // GodotLib.newcontext should be called here once it's done. + //GodotLib.newcontext(surface, false) + + for (plugin in pluginRegistry.getAllPlugins()) { + plugin.onVkSurfaceCreated(surface) + } } /** * Called after the surface is created and whenever its size changes. */ fun onVkSurfaceChanged(surface: Surface, width: Int, height: Int) { - nativeOnVkSurfaceChanged(surface, width, height) + GodotLib.resize(width, height) + + // TODO: properly implement surface re-creation: + // Update the native renderer instead of restarting the app. + // GodotLib.newcontext should not be called here once it's done. + GodotLib.newcontext(surface, false) + + for (plugin in pluginRegistry.getAllPlugins()) { + plugin.onVkSurfaceChanged(surface, width, height) + } } /** * Called to draw the current frame. */ fun onVkDrawFrame() { - nativeOnVkDrawFrame() + GodotLib.step() + for (plugin in pluginRegistry.getAllPlugins()) { + plugin.onVkDrawFrame() + } } /** * Called when the rendering thread is resumed. */ fun onVkResume() { - nativeOnVkResume() + GodotLib.onRendererResumed() } /** * Called when the rendering thread is paused. */ fun onVkPause() { - nativeOnVkPause() + GodotLib.onRendererPaused() } /** * Called when the rendering thread is destroyed and used as signal to tear down the Vulkan logic. */ fun onVkDestroy() { - nativeOnVkDestroy() } - - private external fun nativeOnVkSurfaceCreated(surface: Surface) - private external fun nativeOnVkSurfaceChanged(surface: Surface, width: Int, height: Int) - private external fun nativeOnVkResume() - private external fun nativeOnVkDrawFrame() - private external fun nativeOnVkPause() - private external fun nativeOnVkDestroy() } diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt index 1c594f3201..6b0e12b21a 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkSurfaceView.kt @@ -49,7 +49,7 @@ import android.view.SurfaceView * UI thread. * </ul> */ -internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback { +open internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHolder.Callback { companion object { fun checkState(expression: Boolean, errorMessage: Any) { @@ -100,7 +100,7 @@ internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHo * * Must not be called before a [VkRenderer] has been set. */ - fun onResume() { + open fun onResume() { vkThread.onResume() } @@ -109,7 +109,7 @@ internal class VkSurfaceView(context: Context) : SurfaceView(context), SurfaceHo * * Must not be called before a [VkRenderer] has been set. */ - fun onPause() { + open fun onPause() { vkThread.onPause() } diff --git a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt index 2e332840bf..7557c8aa22 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt +++ b/platform/android/java/lib/src/org/godotengine/godot/vulkan/VkThread.kt @@ -219,9 +219,9 @@ internal class VkThread(private val vkSurfaceView: VkSurfaceView, private val vk vkRenderer.onVkDrawFrame() } } catch (ex: InterruptedException) { - Log.i(TAG, ex.message) + Log.i(TAG, "InterruptedException", ex) } catch (ex: IllegalStateException) { - Log.i(TAG, ex.message) + Log.i(TAG, "IllegalStateException", ex) } finally { threadExiting() } diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java index 9209d6ccf2..c66d75bb2d 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrConfigChooser.java @@ -32,6 +32,7 @@ package org.godotengine.godot.xr.ovr; import android.opengl.EGLExt; import android.opengl.GLSurfaceView; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java index 36f4416df2..16d4a998f2 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrContextFactory.java @@ -32,6 +32,7 @@ package org.godotengine.godot.xr.ovr; import android.opengl.EGL14; import android.opengl.GLSurfaceView; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java index b2aa130f37..7ca0777f11 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/ovr/OvrWindowSurfaceFactory.java @@ -31,6 +31,7 @@ package org.godotengine.godot.xr.ovr; import android.opengl.GLSurfaceView; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java index 8409e37f8f..924d12f0bc 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularConfigChooser.java @@ -30,11 +30,13 @@ package org.godotengine.godot.xr.regular; +import org.godotengine.godot.utils.GLUtils; + import android.opengl.GLSurfaceView; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; -import org.godotengine.godot.utils.GLUtils; /** * Used to select the egl config for pancake games. diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java index f2b4c95a2c..126f3ad5f5 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularContextFactory.java @@ -30,14 +30,16 @@ package org.godotengine.godot.xr.regular; +import org.godotengine.godot.GodotLib; +import org.godotengine.godot.utils.GLUtils; + import android.opengl.GLSurfaceView; import android.util.Log; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; -import org.godotengine.godot.GodotLib; -import org.godotengine.godot.utils.GLUtils; /** * Factory used to setup the opengl context for pancake games. @@ -51,7 +53,6 @@ public class RegularContextFactory implements GLSurfaceView.EGLContextFactory { private static int EGL_CONTEXT_CLIENT_VERSION = 0x3098; public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig) { - String driver_name = GodotLib.getGlobal("rendering/quality/driver/driver_name"); // FIXME: Add support for Vulkan. Log.w(TAG, "creating OpenGL ES 2.0 context :"); diff --git a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java index 71fcf06020..64bc4ac1da 100644 --- a/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java +++ b/platform/android/java/lib/src/org/godotengine/godot/xr/regular/RegularFallbackConfigChooser.java @@ -30,11 +30,13 @@ package org.godotengine.godot.xr.regular; +import org.godotengine.godot.utils.GLUtils; + import android.util.Log; + import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLDisplay; -import org.godotengine.godot.utils.GLUtils; /* Fallback if 32bit View is not supported*/ public class RegularFallbackConfigChooser extends RegularConfigChooser { |