diff --git a/android/SDL_Java_RMB_fix.patch b/android/SDL_Java_RMB_fix.patch new file mode 100644 index 000000000..cc0eb4772 --- /dev/null +++ b/android/SDL_Java_RMB_fix.patch @@ -0,0 +1,18 @@ +diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java +index fd5a056e3..83e3cf657 100644 +--- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java ++++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java +@@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh + } + } + +- if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { ++ if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE || ++ /* ++ * CUSTOM ADDITION FOR MINETEST ++ * should be upstreamed ++ */ ++ (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) { + // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses + // they are ignored here because sending them as mouse input to SDL is messy + if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) { diff --git a/android/app/src/main/java/net/minetest/minetest/GameActivity.java b/android/app/src/main/java/net/minetest/minetest/GameActivity.java index 85336ac7e..2646721d1 100644 --- a/android/app/src/main/java/net/minetest/minetest/GameActivity.java +++ b/android/app/src/main/java/net/minetest/minetest/GameActivity.java @@ -20,7 +20,8 @@ with this program; if not, write to the Free Software Foundation, Inc., package net.minetest.minetest; -import android.app.NativeActivity; +import org.libsdl.app.SDLActivity; + import android.content.Intent; import android.net.Uri; import android.os.Bundle; @@ -32,6 +33,7 @@ import android.view.WindowManager; import android.view.inputmethod.InputMethodManager; import android.widget.Button; import android.widget.LinearLayout; +import android.content.res.Configuration; import androidx.annotation.Keep; import androidx.appcompat.app.AlertDialog; @@ -45,12 +47,29 @@ import java.util.Objects; // This annotation prevents the minifier/Proguard from mangling them. @Keep @SuppressWarnings("unused") -public class GameActivity extends NativeActivity { - static { - System.loadLibrary("c++_shared"); - System.loadLibrary("minetest"); +public class GameActivity extends SDLActivity { + @Override + protected String getMainSharedObject() { + return getContext().getApplicationInfo().nativeLibraryDir + "/libminetest.so"; } + @Override + protected String getMainFunction() { + return "SDL_Main"; + } + + @Override + protected String[] getLibraries() { + return new String[] { + "minetest" + }; + } + + // Prevent SDL from changing orientation settings since we already set the + // correct orientation in our AndroidManifest.xml + @Override + public void setOrientationBis(int w, int h, boolean resizable, String hint) {} + enum DialogType { TEXT_INPUT, SELECTION_INPUT } enum DialogState { DIALOG_SHOWN, DIALOG_INPUTTED, DIALOG_CANCELED } @@ -59,32 +78,6 @@ public class GameActivity extends NativeActivity { private String messageReturnValue = ""; private int selectionReturnValue = 0; - @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); - } - - private void makeFullScreen() { - this.getWindow().getDecorView().setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | - View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); - } - - @Override - public void onWindowFocusChanged(boolean hasFocus) { - super.onWindowFocusChanged(hasFocus); - if (hasFocus) - makeFullScreen(); - } - - @Override - protected void onResume() { - super.onResume(); - makeFullScreen(); - } - private native void saveSettings(); @Override @@ -96,11 +89,6 @@ public class GameActivity extends NativeActivity { saveSettings(); } - @Override - public void onBackPressed() { - // Ignore the back press so Minetest can handle it - } - public void showTextInputDialog(String hint, String current, int editType) { runOnUiThread(() -> showTextInputDialogUI(hint, current, editType)); } @@ -265,4 +253,8 @@ public class GameActivity extends NativeActivity { return langCode; } + + public boolean hasPhysicalKeyboard() { + return getContext().getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS; + } } diff --git a/android/app/src/main/java/org/libsdl/app/SDLActivity.java b/android/app/src/main/java/org/libsdl/app/SDLActivity.java index fd5a056e3..83e3cf657 100644 --- a/android/app/src/main/java/org/libsdl/app/SDLActivity.java +++ b/android/app/src/main/java/org/libsdl/app/SDLActivity.java @@ -1345,7 +1345,12 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh } } - if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) { + if ((source & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE || + /* + * CUSTOM ADDITION FOR MINETEST + * should be upstreamed + */ + (source & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE) { // on some devices key events are sent for mouse BUTTON_BACK/FORWARD presses // they are ignored here because sending them as mouse input to SDL is messy if ((keyCode == KeyEvent.KEYCODE_BACK) || (keyCode == KeyEvent.KEYCODE_FORWARD)) { diff --git a/builtin/settingtypes.txt b/builtin/settingtypes.txt index 8ffb1c3c1..610144067 100644 --- a/builtin/settingtypes.txt +++ b/builtin/settingtypes.txt @@ -153,8 +153,6 @@ invert_hotbar_mouse_wheel (Hotbar: Invert mouse wheel direction) bool false [*Touchscreen] # Enables touchscreen mode, allowing you to play the game with a touchscreen. -# -# Requires: !android enable_touch (Enable touchscreen) bool true # Touchscreen sensitivity multiplier. diff --git a/cmake/Modules/MinetestAndroidLibs.cmake b/cmake/Modules/MinetestAndroidLibs.cmake index 02383903f..0f8e4fa29 100644 --- a/cmake/Modules/MinetestAndroidLibs.cmake +++ b/cmake/Modules/MinetestAndroidLibs.cmake @@ -25,3 +25,5 @@ set(VORBIS_LIBRARY ${DEPS}/Vorbis/libvorbis.a) set(VORBISFILE_LIBRARY ${DEPS}/Vorbis/libvorbisfile.a) set(ZSTD_INCLUDE_DIR ${DEPS}/Zstd/include) set(ZSTD_LIBRARY ${DEPS}/Zstd/libzstd.a) +set(SDL2_INCLUDE_DIRS ${DEPS}/SDL2/include/SDL2) +set(SDL2_LIBRARIES ${DEPS}/SDL2/libSDL2.a) diff --git a/irr/include/IEventReceiver.h b/irr/include/IEventReceiver.h index 6134b79f5..e0660a6f1 100644 --- a/irr/include/IEventReceiver.h +++ b/irr/include/IEventReceiver.h @@ -79,9 +79,6 @@ enum EEVENT_TYPE */ EET_USER_EVENT, - //! Pass on raw events from the OS - EET_SYSTEM_EVENT, - //! Application state events like a resume, pause etc. EET_APPLICATION_EVENT, @@ -187,17 +184,6 @@ enum ETOUCH_INPUT_EVENT ETIE_COUNT }; -enum ESYSTEM_EVENT_TYPE -{ - //! From Android command handler for native activity messages - ESET_ANDROID_CMD = 0, - - // TODO: for example ESET_WINDOWS_MESSAGE for win32 message loop events - - //! No real event, but to get number of event types - ESET_COUNT -}; - //! Enumeration for a commonly used application state events (it's useful mainly for mobile devices) enum EAPPLICATION_EVENT_TYPE { @@ -528,25 +514,6 @@ struct SEvent size_t UserData2; }; - // Raw events from the OS - struct SSystemEvent - { - //! Android command handler native activity messages. - struct SAndroidCmd - { - //! APP_CMD_ enums defined in android_native_app_glue.h from the Android NDK - s32 Cmd; - }; - - // TOOD: more structs for iphone, Windows, X11, etc. - - ESYSTEM_EVENT_TYPE EventType; - union - { - struct SAndroidCmd AndroidCmd; - }; - }; - // Application state event struct SApplicationEvent { @@ -567,7 +534,6 @@ struct SEvent struct SJoystickEvent JoystickEvent; struct SLogEvent LogEvent; struct SUserEvent UserEvent; - struct SSystemEvent SystemEvent; struct SApplicationEvent ApplicationEvent; }; }; diff --git a/irr/include/IrrlichtDevice.h b/irr/include/IrrlichtDevice.h index f0ec9f005..38ba8c63d 100644 --- a/irr/include/IrrlichtDevice.h +++ b/irr/include/IrrlichtDevice.h @@ -180,10 +180,7 @@ public: virtual bool isFullscreen() const = 0; //! Checks if the window could possibly be visible. - //! Currently, this only returns false when the activity is stopped on - //! Android. Note that for Android activities, "stopped" means something - //! different than you might expect (and also something different than - //! "paused"). Read the Android lifecycle documentation. + /** If this returns false, you should not do any rendering. */ virtual bool isWindowVisible() const { return true; }; //! Get the current color format of the window diff --git a/irr/src/Android/CAndroidAssetFileArchive.cpp b/irr/src/Android/CAndroidAssetFileArchive.cpp deleted file mode 100644 index 59df2d2a1..000000000 --- a/irr/src/Android/CAndroidAssetFileArchive.cpp +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright (C) 2002-2011 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CAndroidAssetReader.h" - -#include "CReadFile.h" -#include "coreutil.h" -#include "CAndroidAssetFileArchive.h" -#include "CIrrDeviceAndroid.h" -#include "os.h" // for logging (just keep it in even when not needed right now as it's used all the time) - -#include -#include -#include - -namespace irr -{ -namespace io -{ - -CAndroidAssetFileArchive::CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths) : - CFileList("/asset", ignoreCase, ignorePaths), AssetManager(assetManager) -{ -} - -CAndroidAssetFileArchive::~CAndroidAssetFileArchive() -{ -} - -//! get the archive type -E_FILE_ARCHIVE_TYPE CAndroidAssetFileArchive::getType() const -{ - return EFAT_ANDROID_ASSET; -} - -const IFileList *CAndroidAssetFileArchive::getFileList() const -{ - // The assert_manager can not read directory names, so - // getFileList returns only files in folders which have been added. - return this; -} - -//! opens a file by file name -IReadFile *CAndroidAssetFileArchive::createAndOpenFile(const io::path &filename) -{ - CAndroidAssetReader *reader = new CAndroidAssetReader(AssetManager, filename); - - if (reader->isOpen()) - return reader; - - reader->drop(); - return NULL; -} - -//! opens a file by index -IReadFile *CAndroidAssetFileArchive::createAndOpenFile(u32 index) -{ - const io::path &filename(getFullFileName(index)); - if (filename.empty()) - return 0; - - return createAndOpenFile(filename); -} - -void CAndroidAssetFileArchive::addDirectoryToFileList(const io::path &dirname_) -{ - io::path dirname(dirname_); - fschar_t lastChar = dirname.lastChar(); - if (lastChar == '/' || lastChar == '\\') - dirname.erase(dirname.size() - 1); - - // os::Printer::log("addDirectoryToFileList:", dirname.c_str(), ELL_DEBUG); - if (findFile(dirname, true) >= 0) - return; // was already added - - AAssetDir *dir = AAssetManager_openDir(AssetManager, core::stringc(dirname).c_str()); - if (!dir) - return; - - // add directory itself - addItem(dirname, 0, 0, /*isDir*/ true, getFileCount()); - - // add all files in folder. - // Note: AAssetDir_getNextFileName does not return directory names (neither does any other NDK function) - while (const char *filename = AAssetDir_getNextFileName(dir)) { - core::stringc full_filename = dirname == "" ? filename - : dirname + "/" + filename; - - // We can't get the size without opening the file - so for performance - // reasons we set the file size to 0. - // TODO: Does this really cost so much performance that it's worth losing this information? Dirs are usually just added once at startup... - addItem(full_filename, /*offet*/ 0, /*size*/ 0, /*isDir*/ false, getFileCount()); - // os::Printer::log("addItem:", full_filename.c_str(), ELL_DEBUG); - } - AAssetDir_close(dir); -} - -} // end namespace io -} // end namespace irr diff --git a/irr/src/Android/CAndroidAssetFileArchive.h b/irr/src/Android/CAndroidAssetFileArchive.h deleted file mode 100644 index 3ca815ed5..000000000 --- a/irr/src/Android/CAndroidAssetFileArchive.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (C) 2012 Joerg Henrichs -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include "IReadFile.h" -#include "IFileArchive.h" -#include "CFileList.h" - -#include - -namespace irr -{ -namespace io -{ - -/*! - Android asset file system written August 2012 by J.Henrichs (later reworked by others). -*/ -class CAndroidAssetFileArchive : public virtual IFileArchive, - virtual CFileList -{ -public: - //! constructor - CAndroidAssetFileArchive(AAssetManager *assetManager, bool ignoreCase, bool ignorePaths); - - //! destructor - virtual ~CAndroidAssetFileArchive(); - - //! opens a file by file name - virtual IReadFile *createAndOpenFile(const io::path &filename); - - //! opens a file by index - virtual IReadFile *createAndOpenFile(u32 index); - - //! returns the list of files - virtual const IFileList *getFileList() const; - - //! get the archive type - virtual E_FILE_ARCHIVE_TYPE getType() const; - - //! Add a directory to read files from. Since the Android - //! API does not return names of directories, they need to - //! be added manually. - virtual void addDirectoryToFileList(const io::path &filename); - - //! return the name (id) of the file Archive - const io::path &getArchiveName() const override { return Path; } - -protected: - //! Android's asset manager - AAssetManager *AssetManager; - -}; // CAndroidAssetFileArchive - -} // end namespace io -} // end namespace irr diff --git a/irr/src/Android/CAndroidAssetReader.cpp b/irr/src/Android/CAndroidAssetReader.cpp deleted file mode 100644 index bf3c51af8..000000000 --- a/irr/src/Android/CAndroidAssetReader.cpp +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (C) 2002-2011 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CAndroidAssetReader.h" - -#include "CReadFile.h" -#include "coreutil.h" -#include "CAndroidAssetReader.h" -#include "CIrrDeviceAndroid.h" - -#include -#include - -namespace irr -{ -namespace io -{ - -CAndroidAssetReader::CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename) : - AssetManager(assetManager), Filename(filename) -{ - Asset = AAssetManager_open(AssetManager, - core::stringc(filename).c_str(), - AASSET_MODE_RANDOM); -} - -CAndroidAssetReader::~CAndroidAssetReader() -{ - if (Asset) - AAsset_close(Asset); -} - -size_t CAndroidAssetReader::read(void *buffer, size_t sizeToRead) -{ - int readBytes = AAsset_read(Asset, buffer, sizeToRead); - if (readBytes >= 0) - return size_t(readBytes); - return 0; // direct fd access is not possible (for example, if the asset is compressed). -} - -bool CAndroidAssetReader::seek(long finalPos, bool relativeMovement) -{ - off_t status = AAsset_seek(Asset, finalPos, relativeMovement ? SEEK_CUR : SEEK_SET); - - return status + 1; -} - -long CAndroidAssetReader::getSize() const -{ - return AAsset_getLength(Asset); -} - -long CAndroidAssetReader::getPos() const -{ - return AAsset_getLength(Asset) - AAsset_getRemainingLength(Asset); -} - -const io::path &CAndroidAssetReader::getFileName() const -{ - return Filename; -} - -} // end namespace io -} // end namespace irr diff --git a/irr/src/Android/CAndroidAssetReader.h b/irr/src/Android/CAndroidAssetReader.h deleted file mode 100644 index 9f6156f3f..000000000 --- a/irr/src/Android/CAndroidAssetReader.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright (C) 2012 Joerg Henrichs -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include "IReadFile.h" - -struct AAssetManager; -struct AAsset; -struct ANativeActivity; - -namespace irr -{ -namespace io -{ - -class CAndroidAssetReader : public virtual IReadFile -{ -public: - CAndroidAssetReader(AAssetManager *assetManager, const io::path &filename); - - virtual ~CAndroidAssetReader(); - - //! Reads an amount of bytes from the file. - /** \param buffer Pointer to buffer where read bytes are written to. - \param sizeToRead Amount of bytes to read from the file. - \return How many bytes were read. */ - virtual size_t read(void *buffer, size_t sizeToRead); - - //! Changes position in file - /** \param finalPos Destination position in the file. - \param relativeMovement If set to true, the position in the file is - changed relative to current position. Otherwise the position is changed - from beginning of file. - \return True if successful, otherwise false. */ - virtual bool seek(long finalPos, bool relativeMovement = false); - - //! Get size of file. - /** \return Size of the file in bytes. */ - virtual long getSize() const; - - //! Get the current position in the file. - /** \return Current position in the file in bytes. */ - virtual long getPos() const; - - //! Get name of file. - /** \return File name as zero terminated character string. */ - virtual const io::path &getFileName() const; - - /** Return true if the file could be opened. */ - bool isOpen() const { return Asset != NULL; } - -private: - //! Android's asset manager - AAssetManager *AssetManager; - - // An asset, i.e. file - AAsset *Asset; - path Filename; -}; - -} // end namespace io -} // end namespace irr diff --git a/irr/src/Android/CIrrDeviceAndroid.cpp b/irr/src/Android/CIrrDeviceAndroid.cpp deleted file mode 100644 index 35c33ef6f..000000000 --- a/irr/src/Android/CIrrDeviceAndroid.cpp +++ /dev/null @@ -1,828 +0,0 @@ -// Copyright (C) 2002-2007 Nikolaus Gebhardt -// Copyright (C) 2007-2011 Christian Stehno -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CIrrDeviceAndroid.h" - -#include "os.h" -#include "CFileSystem.h" -#include "CAndroidAssetReader.h" -#include "CAndroidAssetFileArchive.h" -#include "CKeyEventWrapper.h" -#include "CEGLManager.h" -#include "ISceneManager.h" -#include "IGUIEnvironment.h" -#include "CEGLManager.h" - -namespace irr -{ -namespace video -{ -IVideoDriver *createOGLES1Driver(const SIrrlichtCreationParameters ¶ms, - io::IFileSystem *io, video::IContextManager *contextManager); - -IVideoDriver *createOGLES2Driver(const SIrrlichtCreationParameters ¶ms, - io::IFileSystem *io, video::IContextManager *contextManager); -} -} - -namespace irr -{ - -CIrrDeviceAndroid::CIrrDeviceAndroid(const SIrrlichtCreationParameters ¶m) : - CIrrDeviceStub(param), Accelerometer(0), Gyroscope(0), Initialized(false), - Stopped(true), Paused(true), Focused(false), JNIEnvAttachedToVM(0) -{ -#ifdef _DEBUG - setDebugName("CIrrDeviceAndroid"); -#endif - - // Get the interface to the native Android activity. - Android = (android_app *)(param.PrivateData); - - // Set the private data so we can use it in any static callbacks. - Android->userData = this; - - // Set the default command handler. This is a callback function that the Android - // OS invokes to send the native activity messages. - Android->onAppCmd = handleAndroidCommand; - - createKeyMap(); - - // Create a sensor manager to receive touch screen events from the java activity. - SensorManager = ASensorManager_getInstance(); - SensorEventQueue = ASensorManager_createEventQueue(SensorManager, Android->looper, LOOPER_ID_USER, 0, 0); - Android->onInputEvent = handleInput; - - // Create EGL manager. - ContextManager = new video::CEGLManager(); - - os::Printer::log("Waiting for Android activity window to be created.", ELL_DEBUG); - - do { - s32 Events = 0; - android_poll_source *Source = 0; - - while ((ALooper_pollAll((!Initialized || isWindowActive()) ? 0 : -1, 0, &Events, (void **)&Source)) >= 0) { - if (Source) - Source->process(Android, Source); - } - } while (!Initialized); -} - -CIrrDeviceAndroid::~CIrrDeviceAndroid() -{ - if (GUIEnvironment) { - GUIEnvironment->drop(); - GUIEnvironment = 0; - } - - if (SceneManager) { - SceneManager->drop(); - SceneManager = 0; - } - - if (VideoDriver) { - VideoDriver->drop(); - VideoDriver = 0; - } -} - -bool CIrrDeviceAndroid::run() -{ - if (!Initialized) - return false; - - os::Timer::tick(); - - s32 id; - s32 Events = 0; - android_poll_source *Source = 0; - - while ((id = ALooper_pollAll(0, 0, &Events, (void **)&Source)) >= 0) { - if (Source) - Source->process(Android, Source); - - // if a sensor has data, we'll process it now. - if (id == LOOPER_ID_USER) { - ASensorEvent sensorEvent; - while (ASensorEventQueue_getEvents(SensorEventQueue, &sensorEvent, 1) > 0) { - switch (sensorEvent.type) { - case ASENSOR_TYPE_ACCELEROMETER: - SEvent accEvent; - accEvent.EventType = EET_ACCELEROMETER_EVENT; - accEvent.AccelerometerEvent.X = sensorEvent.acceleration.x; - accEvent.AccelerometerEvent.Y = sensorEvent.acceleration.y; - accEvent.AccelerometerEvent.Z = sensorEvent.acceleration.z; - - postEventFromUser(accEvent); - break; - - case ASENSOR_TYPE_GYROSCOPE: - SEvent gyroEvent; - gyroEvent.EventType = EET_GYROSCOPE_EVENT; - gyroEvent.GyroscopeEvent.X = sensorEvent.vector.x; - gyroEvent.GyroscopeEvent.Y = sensorEvent.vector.y; - gyroEvent.GyroscopeEvent.Z = sensorEvent.vector.z; - - postEventFromUser(gyroEvent); - break; - default: - break; - } - } - } - - if (!Initialized) - break; - } - - return Initialized; -} - -void CIrrDeviceAndroid::yield() -{ - struct timespec ts = {0, 1}; - nanosleep(&ts, NULL); -} - -void CIrrDeviceAndroid::sleep(u32 timeMs, bool pauseTimer) -{ - const bool wasStopped = Timer ? Timer->isStopped() : true; - - struct timespec ts; - ts.tv_sec = (time_t)(timeMs / 1000); - ts.tv_nsec = (long)(timeMs % 1000) * 1000000; - - if (pauseTimer && !wasStopped) - Timer->stop(); - - nanosleep(&ts, NULL); - - if (pauseTimer && !wasStopped) - Timer->start(); -} - -void CIrrDeviceAndroid::setWindowCaption(const wchar_t *text) -{ -} - -bool CIrrDeviceAndroid::isWindowActive() const -{ - return (Focused && !Paused && !Stopped); -} - -bool CIrrDeviceAndroid::isWindowFocused() const -{ - return Focused; -} - -bool CIrrDeviceAndroid::isWindowMinimized() const -{ - return !Focused; -} - -bool CIrrDeviceAndroid::isWindowVisible() const -{ - return !Stopped; -} - -void CIrrDeviceAndroid::closeDevice() -{ - ANativeActivity_finish(Android->activity); -} - -void CIrrDeviceAndroid::setResizable(bool resize) -{ -} - -void CIrrDeviceAndroid::minimizeWindow() -{ -} - -void CIrrDeviceAndroid::maximizeWindow() -{ -} - -void CIrrDeviceAndroid::restoreWindow() -{ -} - -core::position2di CIrrDeviceAndroid::getWindowPosition() -{ - return core::position2di(0, 0); -} - -E_DEVICE_TYPE CIrrDeviceAndroid::getType() const -{ - return EIDT_ANDROID; -} - -void CIrrDeviceAndroid::handleAndroidCommand(android_app *app, int32_t cmd) -{ - CIrrDeviceAndroid *device = (CIrrDeviceAndroid *)app->userData; - - SEvent event; - event.EventType = EET_SYSTEM_EVENT; - event.SystemEvent.EventType = ESET_ANDROID_CMD; - event.SystemEvent.AndroidCmd.Cmd = cmd; - if (device->postEventFromUser(event)) - return; - - switch (cmd) { - case APP_CMD_INPUT_CHANGED: - os::Printer::log("Android command APP_CMD_INPUT_CHANGED", ELL_DEBUG); - break; - case APP_CMD_WINDOW_RESIZED: - os::Printer::log("Android command APP_CMD_WINDOW_RESIZED", ELL_DEBUG); - break; - case APP_CMD_WINDOW_REDRAW_NEEDED: - os::Printer::log("Android command APP_CMD_WINDOW_REDRAW_NEEDED", ELL_DEBUG); - break; - case APP_CMD_SAVE_STATE: - os::Printer::log("Android command APP_CMD_SAVE_STATE", ELL_DEBUG); - break; - case APP_CMD_CONTENT_RECT_CHANGED: - os::Printer::log("Android command APP_CMD_CONTENT_RECT_CHANGED", ELL_DEBUG); - break; - case APP_CMD_CONFIG_CHANGED: - os::Printer::log("Android command APP_CMD_CONFIG_CHANGED", ELL_DEBUG); - break; - case APP_CMD_LOW_MEMORY: - os::Printer::log("Android command APP_CMD_LOW_MEMORY", ELL_DEBUG); - break; - case APP_CMD_START: - os::Printer::log("Android command APP_CMD_START", ELL_DEBUG); - device->Stopped = false; - break; - case APP_CMD_INIT_WINDOW: - os::Printer::log("Android command APP_CMD_INIT_WINDOW", ELL_DEBUG); - device->getExposedVideoData().OGLESAndroid.Window = app->window; - - if (device->CreationParams.WindowSize.Width == 0 || device->CreationParams.WindowSize.Height == 0) { - device->CreationParams.WindowSize.Width = ANativeWindow_getWidth(app->window); - device->CreationParams.WindowSize.Height = ANativeWindow_getHeight(app->window); - } - - device->getContextManager()->initialize(device->CreationParams, device->ExposedVideoData); - device->getContextManager()->generateSurface(); - device->getContextManager()->generateContext(); - device->getContextManager()->activateContext(device->getContextManager()->getContext()); - - if (!device->Initialized) { - io::CAndroidAssetFileArchive *assets = new io::CAndroidAssetFileArchive(device->Android->activity->assetManager, false, false); - assets->addDirectoryToFileList(""); - device->FileSystem->addFileArchive(assets); - assets->drop(); - - device->createDriver(); - - if (device->VideoDriver) - device->createGUIAndScene(); - } - device->Initialized = true; - break; - case APP_CMD_TERM_WINDOW: - os::Printer::log("Android command APP_CMD_TERM_WINDOW", ELL_DEBUG); - device->getContextManager()->destroySurface(); - break; - case APP_CMD_GAINED_FOCUS: - os::Printer::log("Android command APP_CMD_GAINED_FOCUS", ELL_DEBUG); - device->Focused = true; - break; - case APP_CMD_LOST_FOCUS: - os::Printer::log("Android command APP_CMD_LOST_FOCUS", ELL_DEBUG); - device->Focused = false; - break; - case APP_CMD_DESTROY: - os::Printer::log("Android command APP_CMD_DESTROY", ELL_DEBUG); - if (device->JNIEnvAttachedToVM) { - device->JNIEnvAttachedToVM = 0; - device->Android->activity->vm->DetachCurrentThread(); - } - device->Initialized = false; - break; - case APP_CMD_PAUSE: - os::Printer::log("Android command APP_CMD_PAUSE", ELL_DEBUG); - device->Paused = true; - break; - case APP_CMD_STOP: - os::Printer::log("Android command APP_CMD_STOP", ELL_DEBUG); - device->Stopped = true; - break; - case APP_CMD_RESUME: - os::Printer::log("Android command APP_CMD_RESUME", ELL_DEBUG); - device->Paused = false; - break; - default: - break; - } -} - -s32 CIrrDeviceAndroid::handleInput(android_app *app, AInputEvent *androidEvent) -{ - CIrrDeviceAndroid *device = (CIrrDeviceAndroid *)app->userData; - s32 status = 0; - - switch (AInputEvent_getType(androidEvent)) { - case AINPUT_EVENT_TYPE_MOTION: { - SEvent event; - event.EventType = EET_TOUCH_INPUT_EVENT; - - s32 eventAction = AMotionEvent_getAction(androidEvent); - s32 eventType = eventAction & AMOTION_EVENT_ACTION_MASK; - -#if 0 - // Useful for debugging. We might have to pass some of those infos on at some point. - // but preferably device independent (so iphone can use same irrlicht flags). - int32_t flags = AMotionEvent_getFlags(androidEvent); - os::Printer::log("flags: ", core::stringc(flags).c_str(), ELL_DEBUG); - int32_t metaState = AMotionEvent_getMetaState(androidEvent); - os::Printer::log("metaState: ", core::stringc(metaState).c_str(), ELL_DEBUG); - int32_t edgeFlags = AMotionEvent_getEdgeFlags(androidEvent); - os::Printer::log("edgeFlags: ", core::stringc(flags).c_str(), ELL_DEBUG); -#endif - - bool touchReceived = true; - - switch (eventType) { - case AMOTION_EVENT_ACTION_DOWN: - case AMOTION_EVENT_ACTION_POINTER_DOWN: - event.TouchInput.Event = ETIE_PRESSED_DOWN; - break; - case AMOTION_EVENT_ACTION_MOVE: - event.TouchInput.Event = ETIE_MOVED; - break; - case AMOTION_EVENT_ACTION_UP: - case AMOTION_EVENT_ACTION_POINTER_UP: - case AMOTION_EVENT_ACTION_CANCEL: - event.TouchInput.Event = ETIE_LEFT_UP; - break; - default: - touchReceived = false; - break; - } - - if (touchReceived) { - // Process all touches for move action. - if (event.TouchInput.Event == ETIE_MOVED) { - s32 pointerCount = AMotionEvent_getPointerCount(androidEvent); - - for (s32 i = 0; i < pointerCount; ++i) { - event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, i); - event.TouchInput.X = AMotionEvent_getX(androidEvent, i); - event.TouchInput.Y = AMotionEvent_getY(androidEvent, i); - event.TouchInput.touchedCount = AMotionEvent_getPointerCount(androidEvent); - - device->postEventFromUser(event); - } - } else // Process one touch for other actions. - { - s32 pointerIndex = (eventAction & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >> AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT; - - event.TouchInput.ID = AMotionEvent_getPointerId(androidEvent, pointerIndex); - event.TouchInput.X = AMotionEvent_getX(androidEvent, pointerIndex); - event.TouchInput.Y = AMotionEvent_getY(androidEvent, pointerIndex); - event.TouchInput.touchedCount = AMotionEvent_getPointerCount(androidEvent); - - device->postEventFromUser(event); - } - - status = 1; - } - } break; - case AINPUT_EVENT_TYPE_KEY: { - SEvent event; - event.EventType = EET_KEY_INPUT_EVENT; - - int32_t keyCode = AKeyEvent_getKeyCode(androidEvent); - // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); - - int32_t keyAction = AKeyEvent_getAction(androidEvent); - int32_t keyMetaState = AKeyEvent_getMetaState(androidEvent); - - if (keyCode >= 0 && (u32)keyCode < device->KeyMap.size()) - event.KeyInput.Key = device->KeyMap[keyCode]; - else - event.KeyInput.Key = KEY_UNKNOWN; - event.KeyInput.SystemKeyCode = (u32)keyCode; - if (keyAction == AKEY_EVENT_ACTION_DOWN) - event.KeyInput.PressedDown = true; - else if (keyAction == AKEY_EVENT_ACTION_UP) - event.KeyInput.PressedDown = false; - else if (keyAction == AKEY_EVENT_ACTION_MULTIPLE) { - // TODO: Multiple duplicate key events have occurred in a row, - // or a complex string is being delivered. The repeat_count - // property of the key event contains the number of times the - // given key code should be executed. - // I guess this might necessary for more complicated i18n key input, - // but don't see yet how to handle this correctly. - } - - /* no use for meta keys so far. - if ( keyMetaState & AMETA_ALT_ON - || keyMetaState & AMETA_ALT_LEFT_ON - || keyMetaState & AMETA_ALT_RIGHT_ON ) - ; - // what is a sym? - if ( keyMetaState & AMETA_SYM_ON ) - ; - */ - if (keyMetaState & AMETA_SHIFT_ON || keyMetaState & AMETA_SHIFT_LEFT_ON || keyMetaState & AMETA_SHIFT_RIGHT_ON) - event.KeyInput.Shift = true; - else - event.KeyInput.Shift = false; - event.KeyInput.Control = false; - - // Having memory allocations + going through JNI for each key-press is pretty bad (slow). - // So we do it only for those keys which are likely text-characters and avoid it for all other keys. - // So it's fast for keys like game controller input and special keys. And text keys are typically - // only used or entering text and not for gaming on Android, so speed likely doesn't matter there too much. - if (event.KeyInput.Key > 0) { - // TODO: - // Not sure why we have to attach a JNIEnv here, but it won't work when doing that in the constructor or - // trying to use the activity->env. My best guess is that the event-handling happens in an own thread. - // It means JNIEnvAttachedToVM will never get detached as I don't know a safe way where to do that - // (we could attach & detach each time, but that would probably be slow) - // Also - it has to be each time as it get's invalid when the application mode changes. - if (device->Initialized && device->Android && device->Android->activity && device->Android->activity->vm) { - JavaVMAttachArgs attachArgs; - attachArgs.version = JNI_VERSION_1_6; - attachArgs.name = 0; - attachArgs.group = NULL; - - // Not a big problem calling it each time - it's a no-op when the thread already is attached. - // And we have to do that as someone else can have detached the thread in the meantime. - jint result = device->Android->activity->vm->AttachCurrentThread(&device->JNIEnvAttachedToVM, &attachArgs); - if (result == JNI_ERR) { - os::Printer::log("AttachCurrentThread for the JNI environment failed.", ELL_WARNING); - device->JNIEnvAttachedToVM = 0; - } - - if (device->JNIEnvAttachedToVM) { - jni::CKeyEventWrapper *keyEventWrapper = new jni::CKeyEventWrapper(device->JNIEnvAttachedToVM, keyAction, keyCode); - event.KeyInput.Char = keyEventWrapper->getUnicodeChar(keyMetaState); - delete keyEventWrapper; - } - } - if (event.KeyInput.Key == KEY_BACK) { - event.KeyInput.Char = 0x08; // same key-code as on other operating systems. Otherwise we have to handle too much system specific stuff in the editbox. - } - // os::Printer::log("char-code: ", core::stringc((int)event.KeyInput.Char).c_str(), ELL_DEBUG); - - } else { - // os::Printer::log("keyCode: ", core::stringc(keyCode).c_str(), ELL_DEBUG); - event.KeyInput.Char = 0; - } - - status = device->postEventFromUser(event); - } break; - default: - break; - } - - return status; -} - -void CIrrDeviceAndroid::createDriver() -{ - switch (CreationParams.DriverType) { - case video::EDT_OGLES1: -#ifdef _IRR_COMPILE_WITH_OGLES1_ - VideoDriver = video::createOGLES1Driver(CreationParams, FileSystem, ContextManager); -#else - os::Printer::log("No OpenGL ES 1.0 support compiled in.", ELL_ERROR); -#endif - break; - case video::EDT_OGLES2: -#ifdef _IRR_COMPILE_WITH_OGLES2_ - VideoDriver = video::createOGLES2Driver(CreationParams, FileSystem, ContextManager); -#else - os::Printer::log("No OpenGL ES 2.0 support compiled in.", ELL_ERROR); -#endif - break; - case video::EDT_NULL: - VideoDriver = video::createNullDriver(FileSystem, CreationParams.WindowSize); - break; - case video::EDT_OPENGL: - os::Printer::log("This driver is not available in Android. Try OpenGL ES 1.0 or ES 2.0.", ELL_ERROR); - break; - default: - os::Printer::log("Unable to create video driver of unknown type.", ELL_ERROR); - break; - } -} - -video::SExposedVideoData &CIrrDeviceAndroid::getExposedVideoData() -{ - return ExposedVideoData; -} - -void CIrrDeviceAndroid::createKeyMap() -{ - KeyMap.set_used(223); - - KeyMap[0] = KEY_UNKNOWN; // AKEYCODE_UNKNOWN - KeyMap[1] = KEY_LBUTTON; // AKEYCODE_SOFT_LEFT - KeyMap[2] = KEY_RBUTTON; // AKEYCODE_SOFT_RIGHT - KeyMap[3] = KEY_HOME; // AKEYCODE_HOME - KeyMap[4] = KEY_CANCEL; // AKEYCODE_BACK - KeyMap[5] = KEY_UNKNOWN; // AKEYCODE_CALL - KeyMap[6] = KEY_UNKNOWN; // AKEYCODE_ENDCALL - KeyMap[7] = KEY_KEY_0; // AKEYCODE_0 - KeyMap[8] = KEY_KEY_1; // AKEYCODE_1 - KeyMap[9] = KEY_KEY_2; // AKEYCODE_2 - KeyMap[10] = KEY_KEY_3; // AKEYCODE_3 - KeyMap[11] = KEY_KEY_4; // AKEYCODE_4 - KeyMap[12] = KEY_KEY_5; // AKEYCODE_5 - KeyMap[13] = KEY_KEY_6; // AKEYCODE_6 - KeyMap[14] = KEY_KEY_7; // AKEYCODE_7 - KeyMap[15] = KEY_KEY_8; // AKEYCODE_8 - KeyMap[16] = KEY_KEY_9; // AKEYCODE_9 - KeyMap[17] = KEY_UNKNOWN; // AKEYCODE_STAR - KeyMap[18] = KEY_UNKNOWN; // AKEYCODE_POUND - KeyMap[19] = KEY_UP; // AKEYCODE_DPAD_UP - KeyMap[20] = KEY_DOWN; // AKEYCODE_DPAD_DOWN - KeyMap[21] = KEY_LEFT; // AKEYCODE_DPAD_LEFT - KeyMap[22] = KEY_RIGHT; // AKEYCODE_DPAD_RIGHT - KeyMap[23] = KEY_SELECT; // AKEYCODE_DPAD_CENTER - KeyMap[24] = KEY_VOLUME_DOWN; // AKEYCODE_VOLUME_UP - KeyMap[25] = KEY_VOLUME_UP; // AKEYCODE_VOLUME_DOWN - KeyMap[26] = KEY_UNKNOWN; // AKEYCODE_POWER - KeyMap[27] = KEY_UNKNOWN; // AKEYCODE_CAMERA - KeyMap[28] = KEY_CLEAR; // AKEYCODE_CLEAR - KeyMap[29] = KEY_KEY_A; // AKEYCODE_A - KeyMap[30] = KEY_KEY_B; // AKEYCODE_B - KeyMap[31] = KEY_KEY_C; // AKEYCODE_C - KeyMap[32] = KEY_KEY_D; // AKEYCODE_D - KeyMap[33] = KEY_KEY_E; // AKEYCODE_E - KeyMap[34] = KEY_KEY_F; // AKEYCODE_F - KeyMap[35] = KEY_KEY_G; // AKEYCODE_G - KeyMap[36] = KEY_KEY_H; // AKEYCODE_H - KeyMap[37] = KEY_KEY_I; // AKEYCODE_I - KeyMap[38] = KEY_KEY_J; // AKEYCODE_J - KeyMap[39] = KEY_KEY_K; // AKEYCODE_K - KeyMap[40] = KEY_KEY_L; // AKEYCODE_L - KeyMap[41] = KEY_KEY_M; // AKEYCODE_M - KeyMap[42] = KEY_KEY_N; // AKEYCODE_N - KeyMap[43] = KEY_KEY_O; // AKEYCODE_O - KeyMap[44] = KEY_KEY_P; // AKEYCODE_P - KeyMap[45] = KEY_KEY_Q; // AKEYCODE_Q - KeyMap[46] = KEY_KEY_R; // AKEYCODE_R - KeyMap[47] = KEY_KEY_S; // AKEYCODE_S - KeyMap[48] = KEY_KEY_T; // AKEYCODE_T - KeyMap[49] = KEY_KEY_U; // AKEYCODE_U - KeyMap[50] = KEY_KEY_V; // AKEYCODE_V - KeyMap[51] = KEY_KEY_W; // AKEYCODE_W - KeyMap[52] = KEY_KEY_X; // AKEYCODE_X - KeyMap[53] = KEY_KEY_Y; // AKEYCODE_Y - KeyMap[54] = KEY_KEY_Z; // AKEYCODE_Z - KeyMap[55] = KEY_COMMA; // AKEYCODE_COMMA - KeyMap[56] = KEY_PERIOD; // AKEYCODE_PERIOD - KeyMap[57] = KEY_MENU; // AKEYCODE_ALT_LEFT - KeyMap[58] = KEY_MENU; // AKEYCODE_ALT_RIGHT - KeyMap[59] = KEY_LSHIFT; // AKEYCODE_SHIFT_LEFT - KeyMap[60] = KEY_RSHIFT; // AKEYCODE_SHIFT_RIGHT - KeyMap[61] = KEY_TAB; // AKEYCODE_TAB - KeyMap[62] = KEY_SPACE; // AKEYCODE_SPACE - KeyMap[63] = KEY_UNKNOWN; // AKEYCODE_SYM - KeyMap[64] = KEY_UNKNOWN; // AKEYCODE_EXPLORER - KeyMap[65] = KEY_UNKNOWN; // AKEYCODE_ENVELOPE - KeyMap[66] = KEY_RETURN; // AKEYCODE_ENTER - KeyMap[67] = KEY_BACK; // AKEYCODE_DEL - KeyMap[68] = KEY_OEM_3; // AKEYCODE_GRAVE - KeyMap[69] = KEY_MINUS; // AKEYCODE_MINUS - KeyMap[70] = KEY_UNKNOWN; // AKEYCODE_EQUALS - KeyMap[71] = KEY_UNKNOWN; // AKEYCODE_LEFT_BRACKET - KeyMap[72] = KEY_UNKNOWN; // AKEYCODE_RIGHT_BRACKET - KeyMap[73] = KEY_UNKNOWN; // AKEYCODE_BACKSLASH - KeyMap[74] = KEY_UNKNOWN; // AKEYCODE_SEMICOLON - KeyMap[75] = KEY_UNKNOWN; // AKEYCODE_APOSTROPHE - KeyMap[76] = KEY_UNKNOWN; // AKEYCODE_SLASH - KeyMap[77] = KEY_UNKNOWN; // AKEYCODE_AT - KeyMap[78] = KEY_UNKNOWN; // AKEYCODE_NUM - KeyMap[79] = KEY_UNKNOWN; // AKEYCODE_HEADSETHOOK - KeyMap[80] = KEY_UNKNOWN; // AKEYCODE_FOCUS (*Camera* focus) - KeyMap[81] = KEY_PLUS; // AKEYCODE_PLUS - KeyMap[82] = KEY_MENU; // AKEYCODE_MENU - KeyMap[83] = KEY_UNKNOWN; // AKEYCODE_NOTIFICATION - KeyMap[84] = KEY_UNKNOWN; // AKEYCODE_SEARCH - KeyMap[85] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PLAY_PAUSE - KeyMap[86] = KEY_MEDIA_STOP; // AKEYCODE_MEDIA_STOP - KeyMap[87] = KEY_MEDIA_NEXT_TRACK; // AKEYCODE_MEDIA_NEXT - KeyMap[88] = KEY_MEDIA_PREV_TRACK; // AKEYCODE_MEDIA_PREVIOUS - KeyMap[89] = KEY_UNKNOWN; // AKEYCODE_MEDIA_REWIND - KeyMap[90] = KEY_UNKNOWN; // AKEYCODE_MEDIA_FAST_FORWARD - KeyMap[91] = KEY_VOLUME_MUTE; // AKEYCODE_MUTE - KeyMap[92] = KEY_PRIOR; // AKEYCODE_PAGE_UP - KeyMap[93] = KEY_NEXT; // AKEYCODE_PAGE_DOWN - KeyMap[94] = KEY_UNKNOWN; // AKEYCODE_PICTSYMBOLS - KeyMap[95] = KEY_UNKNOWN; // AKEYCODE_SWITCH_CHARSET - - // following look like controller inputs - KeyMap[96] = KEY_UNKNOWN; // AKEYCODE_BUTTON_A - KeyMap[97] = KEY_UNKNOWN; // AKEYCODE_BUTTON_B - KeyMap[98] = KEY_UNKNOWN; // AKEYCODE_BUTTON_C - KeyMap[99] = KEY_UNKNOWN; // AKEYCODE_BUTTON_X - KeyMap[100] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Y - KeyMap[101] = KEY_UNKNOWN; // AKEYCODE_BUTTON_Z - KeyMap[102] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L1 - KeyMap[103] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R1 - KeyMap[104] = KEY_UNKNOWN; // AKEYCODE_BUTTON_L2 - KeyMap[105] = KEY_UNKNOWN; // AKEYCODE_BUTTON_R2 - KeyMap[106] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBL - KeyMap[107] = KEY_UNKNOWN; // AKEYCODE_BUTTON_THUMBR - KeyMap[108] = KEY_UNKNOWN; // AKEYCODE_BUTTON_START - KeyMap[109] = KEY_UNKNOWN; // AKEYCODE_BUTTON_SELECT - KeyMap[110] = KEY_UNKNOWN; // AKEYCODE_BUTTON_MODE - - KeyMap[111] = KEY_ESCAPE; // AKEYCODE_ESCAPE - KeyMap[112] = KEY_DELETE; // AKEYCODE_FORWARD_DEL - KeyMap[113] = KEY_CONTROL; // AKEYCODE_CTRL_LEFT - KeyMap[114] = KEY_CONTROL; // AKEYCODE_CTRL_RIGHT - KeyMap[115] = KEY_CAPITAL; // AKEYCODE_CAPS_LOCK - KeyMap[116] = KEY_SCROLL; // AKEYCODE_SCROLL_LOCK - KeyMap[117] = KEY_UNKNOWN; // AKEYCODE_META_LEFT - KeyMap[118] = KEY_UNKNOWN; // AKEYCODE_META_RIGHT - KeyMap[119] = KEY_UNKNOWN; // AKEYCODE_FUNCTION - KeyMap[120] = KEY_SNAPSHOT; // AKEYCODE_SYSRQ - KeyMap[121] = KEY_PAUSE; // AKEYCODE_BREAK - KeyMap[122] = KEY_HOME; // AKEYCODE_MOVE_HOME - KeyMap[123] = KEY_END; // AKEYCODE_MOVE_END - KeyMap[124] = KEY_INSERT; // AKEYCODE_INSERT - KeyMap[125] = KEY_UNKNOWN; // AKEYCODE_FORWARD - KeyMap[126] = KEY_PLAY; // AKEYCODE_MEDIA_PLAY - KeyMap[127] = KEY_MEDIA_PLAY_PAUSE; // AKEYCODE_MEDIA_PAUSE - KeyMap[128] = KEY_UNKNOWN; // AKEYCODE_MEDIA_CLOSE - KeyMap[129] = KEY_UNKNOWN; // AKEYCODE_MEDIA_EJECT - KeyMap[130] = KEY_UNKNOWN; // AKEYCODE_MEDIA_RECORD - KeyMap[131] = KEY_F1; // AKEYCODE_F1 - KeyMap[132] = KEY_F2; // AKEYCODE_F2 - KeyMap[133] = KEY_F3; // AKEYCODE_F3 - KeyMap[134] = KEY_F4; // AKEYCODE_F4 - KeyMap[135] = KEY_F5; // AKEYCODE_F5 - KeyMap[136] = KEY_F6; // AKEYCODE_F6 - KeyMap[137] = KEY_F7; // AKEYCODE_F7 - KeyMap[138] = KEY_F8; // AKEYCODE_F8 - KeyMap[139] = KEY_F9; // AKEYCODE_F9 - KeyMap[140] = KEY_F10; // AKEYCODE_F10 - KeyMap[141] = KEY_F11; // AKEYCODE_F11 - KeyMap[142] = KEY_F12; // AKEYCODE_F12 - KeyMap[143] = KEY_NUMLOCK; // AKEYCODE_NUM_LOCK - KeyMap[144] = KEY_NUMPAD0; // AKEYCODE_NUMPAD_0 - KeyMap[145] = KEY_NUMPAD1; // AKEYCODE_NUMPAD_1 - KeyMap[146] = KEY_NUMPAD2; // AKEYCODE_NUMPAD_2 - KeyMap[147] = KEY_NUMPAD3; // AKEYCODE_NUMPAD_3 - KeyMap[148] = KEY_NUMPAD4; // AKEYCODE_NUMPAD_4 - KeyMap[149] = KEY_NUMPAD5; // AKEYCODE_NUMPAD_5 - KeyMap[150] = KEY_NUMPAD6; // AKEYCODE_NUMPAD_6 - KeyMap[151] = KEY_NUMPAD7; // AKEYCODE_NUMPAD_7 - KeyMap[152] = KEY_NUMPAD8; // AKEYCODE_NUMPAD_8 - KeyMap[153] = KEY_NUMPAD9; // AKEYCODE_NUMPAD_9 - KeyMap[154] = KEY_DIVIDE; // AKEYCODE_NUMPAD_DIVIDE - KeyMap[155] = KEY_MULTIPLY; // AKEYCODE_NUMPAD_MULTIPLY - KeyMap[156] = KEY_SUBTRACT; // AKEYCODE_NUMPAD_SUBTRACT - KeyMap[157] = KEY_ADD; // AKEYCODE_NUMPAD_ADD - KeyMap[158] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_DOT - KeyMap[159] = KEY_COMMA; // AKEYCODE_NUMPAD_COMMA - KeyMap[160] = KEY_RETURN; // AKEYCODE_NUMPAD_ENTER - KeyMap[161] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_EQUALS - KeyMap[162] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_LEFT_PAREN - KeyMap[163] = KEY_UNKNOWN; // AKEYCODE_NUMPAD_RIGHT_PAREN - KeyMap[164] = KEY_VOLUME_MUTE; // AKEYCODE_VOLUME_MUTE - KeyMap[165] = KEY_UNKNOWN; // AKEYCODE_INFO - KeyMap[166] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_UP - KeyMap[167] = KEY_UNKNOWN; // AKEYCODE_CHANNEL_DOWN - KeyMap[168] = KEY_ZOOM; // AKEYCODE_ZOOM_IN - KeyMap[169] = KEY_UNKNOWN; // AKEYCODE_ZOOM_OUT - KeyMap[170] = KEY_UNKNOWN; // AKEYCODE_TV - KeyMap[171] = KEY_UNKNOWN; // AKEYCODE_WINDOW - KeyMap[172] = KEY_UNKNOWN; // AKEYCODE_GUIDE - KeyMap[173] = KEY_UNKNOWN; // AKEYCODE_DVR - KeyMap[174] = KEY_UNKNOWN; // AKEYCODE_BOOKMARK - KeyMap[175] = KEY_UNKNOWN; // AKEYCODE_CAPTIONS - KeyMap[176] = KEY_UNKNOWN; // AKEYCODE_SETTINGS - KeyMap[177] = KEY_UNKNOWN; // AKEYCODE_TV_POWER - KeyMap[178] = KEY_UNKNOWN; // AKEYCODE_TV_INPUT - KeyMap[179] = KEY_UNKNOWN; // AKEYCODE_STB_POWER - KeyMap[180] = KEY_UNKNOWN; // AKEYCODE_STB_INPUT - KeyMap[181] = KEY_UNKNOWN; // AKEYCODE_AVR_POWER - KeyMap[182] = KEY_UNKNOWN; // AKEYCODE_AVR_INPUT - KeyMap[183] = KEY_UNKNOWN; // AKEYCODE_PROG_RED - KeyMap[184] = KEY_UNKNOWN; // AKEYCODE_PROG_GREEN - KeyMap[185] = KEY_UNKNOWN; // AKEYCODE_PROG_YELLOW - KeyMap[186] = KEY_UNKNOWN; // AKEYCODE_PROG_BLUE - KeyMap[187] = KEY_UNKNOWN; // AKEYCODE_APP_SWITCH - KeyMap[188] = KEY_UNKNOWN; // AKEYCODE_BUTTON_1 - KeyMap[189] = KEY_UNKNOWN; // AKEYCODE_BUTTON_2 - KeyMap[190] = KEY_UNKNOWN; // AKEYCODE_BUTTON_3 - KeyMap[191] = KEY_UNKNOWN; // AKEYCODE_BUTTON_4 - KeyMap[192] = KEY_UNKNOWN; // AKEYCODE_BUTTON_5 - KeyMap[193] = KEY_UNKNOWN; // AKEYCODE_BUTTON_6 - KeyMap[194] = KEY_UNKNOWN; // AKEYCODE_BUTTON_7 - KeyMap[195] = KEY_UNKNOWN; // AKEYCODE_BUTTON_8 - KeyMap[196] = KEY_UNKNOWN; // AKEYCODE_BUTTON_9 - KeyMap[197] = KEY_UNKNOWN; // AKEYCODE_BUTTON_10 - KeyMap[198] = KEY_UNKNOWN; // AKEYCODE_BUTTON_11 - KeyMap[199] = KEY_UNKNOWN; // AKEYCODE_BUTTON_12 - KeyMap[200] = KEY_UNKNOWN; // AKEYCODE_BUTTON_13 - KeyMap[201] = KEY_UNKNOWN; // AKEYCODE_BUTTON_14 - KeyMap[202] = KEY_UNKNOWN; // AKEYCODE_BUTTON_15 - KeyMap[203] = KEY_UNKNOWN; // AKEYCODE_BUTTON_16 - KeyMap[204] = KEY_UNKNOWN; // AKEYCODE_LANGUAGE_SWITCH - KeyMap[205] = KEY_UNKNOWN; // AKEYCODE_MANNER_MODE - KeyMap[206] = KEY_UNKNOWN; // AKEYCODE_3D_MODE - KeyMap[207] = KEY_UNKNOWN; // AKEYCODE_CONTACTS - KeyMap[208] = KEY_UNKNOWN; // AKEYCODE_CALENDAR - KeyMap[209] = KEY_UNKNOWN; // AKEYCODE_MUSIC - KeyMap[210] = KEY_UNKNOWN; // AKEYCODE_CALCULATOR - KeyMap[211] = KEY_UNKNOWN; // AKEYCODE_ZENKAKU_HANKAKU - KeyMap[212] = KEY_UNKNOWN; // AKEYCODE_EISU - KeyMap[213] = KEY_UNKNOWN; // AKEYCODE_MUHENKAN - KeyMap[214] = KEY_UNKNOWN; // AKEYCODE_HENKAN - KeyMap[215] = KEY_UNKNOWN; // AKEYCODE_KATAKANA_HIRAGANA - KeyMap[216] = KEY_UNKNOWN; // AKEYCODE_YEN - KeyMap[217] = KEY_UNKNOWN; // AKEYCODE_RO - KeyMap[218] = KEY_UNKNOWN; // AKEYCODE_KANA - KeyMap[219] = KEY_UNKNOWN; // AKEYCODE_ASSIST - KeyMap[220] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_DOWN - KeyMap[221] = KEY_UNKNOWN; // AKEYCODE_BRIGHTNESS_UP , - KeyMap[222] = KEY_UNKNOWN; // AKEYCODE_MEDIA_AUDIO_TRACK -} - -bool CIrrDeviceAndroid::activateAccelerometer(float updateInterval) -{ - if (!isAccelerometerAvailable()) - return false; - - ASensorEventQueue_enableSensor(SensorEventQueue, Accelerometer); - ASensorEventQueue_setEventRate(SensorEventQueue, Accelerometer, (int32_t)(updateInterval * 1000.f * 1000.f)); // in microseconds - - os::Printer::log("Activated accelerometer", ELL_DEBUG); - return true; -} - -bool CIrrDeviceAndroid::deactivateAccelerometer() -{ - if (Accelerometer) { - ASensorEventQueue_disableSensor(SensorEventQueue, Accelerometer); - Accelerometer = 0; - os::Printer::log("Deactivated accelerometer", ELL_DEBUG); - return true; - } - - return false; -} - -bool CIrrDeviceAndroid::isAccelerometerActive() -{ - return (Accelerometer != 0); -} - -bool CIrrDeviceAndroid::isAccelerometerAvailable() -{ - if (!Accelerometer) - Accelerometer = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_ACCELEROMETER); - - return (Accelerometer != 0); -} - -bool CIrrDeviceAndroid::activateGyroscope(float updateInterval) -{ - if (!isGyroscopeAvailable()) - return false; - - ASensorEventQueue_enableSensor(SensorEventQueue, Gyroscope); - ASensorEventQueue_setEventRate(SensorEventQueue, Gyroscope, (int32_t)(updateInterval * 1000.f * 1000.f)); // in microseconds - - os::Printer::log("Activated gyroscope", ELL_DEBUG); - return true; -} - -bool CIrrDeviceAndroid::deactivateGyroscope() -{ - if (Gyroscope) { - ASensorEventQueue_disableSensor(SensorEventQueue, Gyroscope); - Gyroscope = 0; - os::Printer::log("Deactivated gyroscope", ELL_DEBUG); - return true; - } - - return false; -} - -bool CIrrDeviceAndroid::isGyroscopeActive() -{ - return (Gyroscope != 0); -} - -bool CIrrDeviceAndroid::isGyroscopeAvailable() -{ - if (!Gyroscope) - Gyroscope = ASensorManager_getDefaultSensor(SensorManager, ASENSOR_TYPE_GYROSCOPE); - - return (Gyroscope != 0); -} - -} // end namespace irr diff --git a/irr/src/Android/CIrrDeviceAndroid.h b/irr/src/Android/CIrrDeviceAndroid.h deleted file mode 100644 index 19a35b152..000000000 --- a/irr/src/Android/CIrrDeviceAndroid.h +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright (C) 2002-2011 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include "CIrrDeviceStub.h" -#include "IrrlichtDevice.h" -#include "ICursorControl.h" - -#include -#include - -namespace irr -{ -class CIrrDeviceAndroid : public CIrrDeviceStub -{ -public: - CIrrDeviceAndroid(const SIrrlichtCreationParameters ¶m); - - virtual ~CIrrDeviceAndroid(); - - virtual bool run(); - - virtual void yield(); - - virtual void sleep(u32 timeMs, bool pauseTimer = false); - - virtual void setWindowCaption(const wchar_t *text); - - virtual bool isWindowActive() const; - - virtual bool isWindowFocused() const; - - virtual bool isWindowMinimized() const; - - virtual bool isWindowVisible() const; - - virtual void closeDevice(); - - virtual void setResizable(bool resize = false); - - virtual void minimizeWindow(); - - virtual void maximizeWindow(); - - virtual void restoreWindow(); - - virtual core::position2di getWindowPosition(); - - virtual E_DEVICE_TYPE getType() const; - - virtual bool activateAccelerometer(float updateInterval); - - virtual bool deactivateAccelerometer(); - - virtual bool isAccelerometerActive(); - - virtual bool isAccelerometerAvailable(); - - virtual bool activateGyroscope(float updateInterval); - - virtual bool deactivateGyroscope(); - - virtual bool isGyroscopeActive(); - - virtual bool isGyroscopeAvailable(); - -private: - static void handleAndroidCommand(android_app *app, int32_t cmd); - - static s32 handleInput(android_app *app, AInputEvent *event); - - void createDriver(); - - void createKeyMap(); - - video::SExposedVideoData &getExposedVideoData(); - - android_app *Android; - ASensorManager *SensorManager; - ASensorEventQueue *SensorEventQueue; - const ASensor *Accelerometer; - const ASensor *Gyroscope; - - bool Initialized; - bool Stopped; - bool Paused; - bool Focused; - - JNIEnv *JNIEnvAttachedToVM; - - video::SExposedVideoData ExposedVideoData; - - core::array KeyMap; -}; - -} // end namespace irr diff --git a/irr/src/Android/CKeyEventWrapper.cpp b/irr/src/Android/CKeyEventWrapper.cpp deleted file mode 100644 index 4008c29c2..000000000 --- a/irr/src/Android/CKeyEventWrapper.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CKeyEventWrapper.h" - -#include "os.h" - -namespace irr -{ -namespace jni -{ - -jclass CKeyEventWrapper::Class_KeyEvent = 0; -jmethodID CKeyEventWrapper::Method_constructor = 0; -jmethodID CKeyEventWrapper::Method_getUnicodeChar = 0; - -CKeyEventWrapper::CKeyEventWrapper(JNIEnv *jniEnv, int action, int code) : - JniEnv(jniEnv), JniKeyEvent(0) -{ - if (JniEnv) { - if (!Class_KeyEvent) { - // Find java classes & functions on first call - os::Printer::log("CKeyEventWrapper first initialize", ELL_DEBUG); - jclass localClass = JniEnv->FindClass("android/view/KeyEvent"); - if (localClass) { - Class_KeyEvent = reinterpret_cast(JniEnv->NewGlobalRef(localClass)); - } - - Method_constructor = JniEnv->GetMethodID(Class_KeyEvent, "", "(II)V"); - Method_getUnicodeChar = JniEnv->GetMethodID(Class_KeyEvent, "getUnicodeChar", "(I)I"); - } - - if (Class_KeyEvent && Method_constructor) { - JniKeyEvent = JniEnv->NewObject(Class_KeyEvent, Method_constructor, action, code); - } else { - os::Printer::log("CKeyEventWrapper didn't find JNI classes/methods", ELL_WARNING); - } - } -} - -CKeyEventWrapper::~CKeyEventWrapper() -{ - JniEnv->DeleteLocalRef(JniKeyEvent); -} - -int CKeyEventWrapper::getUnicodeChar(int metaState) -{ - return JniEnv->CallIntMethod(JniKeyEvent, Method_getUnicodeChar, metaState); -} - -} // namespace jni -} // namespace irr diff --git a/irr/src/Android/CKeyEventWrapper.h b/irr/src/Android/CKeyEventWrapper.h deleted file mode 100644 index 9eb68697a..000000000 --- a/irr/src/Android/CKeyEventWrapper.h +++ /dev/null @@ -1,35 +0,0 @@ -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#pragma once - -#include - -struct android_app; - -namespace irr -{ -namespace jni -{ - -//! Minimal JNI wrapper class around android.view.KeyEvent -//! NOTE: Only functions we actually use in the engine are wrapped -//! This is currently not written to support multithreading - meaning threads are not attached/detached to the Java VM (to be discussed) -class CKeyEventWrapper -{ -public: - CKeyEventWrapper(JNIEnv *jniEnv, int action, int code); - ~CKeyEventWrapper(); - - int getUnicodeChar(int metaState); - -private: - static jclass Class_KeyEvent; - static jmethodID Method_getUnicodeChar; - static jmethodID Method_constructor; - JNIEnv *JniEnv; - jobject JniKeyEvent; // this object in java -}; - -} // namespace jni -} // namespace irr diff --git a/irr/src/CEGLManager.cpp b/irr/src/CEGLManager.cpp index 971b39359..465a31613 100644 --- a/irr/src/CEGLManager.cpp +++ b/irr/src/CEGLManager.cpp @@ -10,10 +10,6 @@ #include "irrArray.h" #include "os.h" -#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) -#include -#endif - namespace irr { namespace video @@ -55,9 +51,6 @@ bool CEGLManager::initialize(const SIrrlichtCreationParameters ¶ms, const SE #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) EglWindow = (NativeWindowType)Data.OpenGLLinux.X11Window; EglDisplay = eglGetDisplay((NativeDisplayType)Data.OpenGLLinux.X11Display); -#elif defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) - EglWindow = (ANativeWindow *)Data.OGLESAndroid.Window; - EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); #elif defined(_IRR_COMPILE_WITH_FB_DEVICE_) EglWindow = (NativeWindowType)Data.OpenGLFB.Window; EglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); @@ -119,10 +112,6 @@ bool CEGLManager::generateSurface() // at this time only Android support this feature. // this needs an update method instead! -#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) - EglWindow = (ANativeWindow *)Data.OGLESAndroid.Window; -#endif - #if defined(_IRR_EMSCRIPTEN_PLATFORM_) // eglChooseConfig is currently only implemented as stub in emscripten (version 1.37.22 at point of writing) // But the other solution would also be fine as it also only generates a single context so there is not much to choose from. @@ -136,13 +125,6 @@ bool CEGLManager::generateSurface() return false; } -#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) - EGLint Format = 0; - eglGetConfigAttrib(EglDisplay, EglConfig, EGL_NATIVE_VISUAL_ID, &Format); - - ANativeWindow_setBuffersGeometry(EglWindow, 0, 0, Format); -#endif - // Now we are able to create EGL surface. EglSurface = eglCreateWindowSurface(EglDisplay, EglConfig, EglWindow, 0); diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index 2609058a6..104466e21 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -252,13 +252,31 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters ¶m) : Window((SDL_Window *)param.WindowId), SDL_Flags(0), MouseX(0), MouseY(0), MouseXRel(0), MouseYRel(0), MouseButtonStates(0), Width(param.WindowSize.Width), Height(param.WindowSize.Height), - Resizable(param.WindowResizable == 1 ? true : false), CurrentTouchCount(0) + Resizable(param.WindowResizable == 1 ? true : false), CurrentTouchCount(0), + IsInBackground(false) { #ifdef _DEBUG setDebugName("CIrrDeviceSDL"); #endif if (++SDLDeviceInstances == 1) { +#ifdef __ANDROID__ + // Blocking on pause causes problems with multiplayer. + // See https://github.com/minetest/minetest/issues/10842. + SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE, "0"); + SDL_SetHint(SDL_HINT_ANDROID_BLOCK_ON_PAUSE_PAUSEAUDIO, "0"); + + SDL_SetHint(SDL_HINT_ANDROID_TRAP_BACK_BUTTON, "1"); + + // Minetest does its own screen keyboard handling. + SDL_SetHint(SDL_HINT_ENABLE_SCREEN_KEYBOARD, "0"); +#endif + + // Minetest has its own code to synthesize mouse events from touch events, + // so we prevent SDL from doing it. + SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); + SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); + u32 flags = SDL_INIT_TIMER | SDL_INIT_EVENTS; if (CreationParams.DriverType != video::EDT_NULL) flags |= SDL_INIT_VIDEO; @@ -273,11 +291,6 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters ¶m) : } } - // Minetest has its own code to synthesize mouse events from touch events, - // so we prevent SDL from doing it. - SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0"); - SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); - // create keymap createKeyMap(); @@ -448,9 +461,13 @@ bool CIrrDeviceSDL::createWindow() default:; } +/* +Makes context creation fail on some Android devices. +See discussion in https://github.com/minetest/minetest/pull/14498. #ifdef _DEBUG SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_ROBUST_ACCESS_FLAG); #endif +*/ if (CreationParams.Bits == 16) { SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 5); @@ -510,6 +527,14 @@ bool CIrrDeviceSDL::createWindow() return false; } + // Update Width and Height to match the actual window size. + // In fullscreen mode, the window size specified in SIrrlichtCreationParameters + // is ignored, so we cannot rely on it. + int w = 0, h = 0; + SDL_GetWindowSize(Window, &w, &h); + Width = w; + Height = h; + return true; #endif // !_IRR_EMSCRIPTEN_PLATFORM_ } @@ -621,7 +646,17 @@ bool CIrrDeviceSDL::run() } #endif - switch (SDL_event.button.button) { + auto button = SDL_event.button.button; +#ifdef __ANDROID__ + // Android likes to send the right mouse button as the back button. + // According to some web searches I did, this is probably + // vendor/device-specific. + // Since a working right mouse button is very important for + // Minetest, we have this little hack. + if (button == SDL_BUTTON_X2) + button = SDL_BUTTON_RIGHT; +#endif + switch (button) { case SDL_BUTTON_LEFT: if (SDL_event.type == SDL_MOUSEBUTTONDOWN) { irrevent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN; @@ -772,6 +807,20 @@ bool CIrrDeviceSDL::run() postEventFromUser(irrevent); break; + // Contrary to what the SDL documentation says, SDL_APP_WILLENTERBACKGROUND + // and SDL_APP_WILLENTERFOREGROUND are actually sent in onStop/onStart, + // not onPause/onResume, on recent Android versions. This can be verified + // by testing or by looking at the org.libsdl.app.SDLActivity Java code. + // -> This means we can use them to implement isWindowVisible(). + + case SDL_APP_WILLENTERBACKGROUND: + IsInBackground = true; + break; + + case SDL_APP_WILLENTERFOREGROUND: + IsInBackground = false; + break; + default: break; } // end switch @@ -1053,6 +1102,11 @@ bool CIrrDeviceSDL::isFullscreen() const #endif } +bool CIrrDeviceSDL::isWindowVisible() const +{ + return !IsInBackground; +} + //! returns if window is active. if not, nothing need to be drawn bool CIrrDeviceSDL::isWindowActive() const { @@ -1111,6 +1165,8 @@ void CIrrDeviceSDL::createKeyMap() // buttons missing + KeyMap.push_back(SKeyMap(SDLK_AC_BACK, KEY_CANCEL)); + KeyMap.push_back(SKeyMap(SDLK_BACKSPACE, KEY_BACK)); KeyMap.push_back(SKeyMap(SDLK_TAB, KEY_TAB)); KeyMap.push_back(SKeyMap(SDLK_CLEAR, KEY_CLEAR)); diff --git a/irr/src/CIrrDeviceSDL.h b/irr/src/CIrrDeviceSDL.h index b1e2a7858..af3f3ca59 100644 --- a/irr/src/CIrrDeviceSDL.h +++ b/irr/src/CIrrDeviceSDL.h @@ -86,6 +86,9 @@ public: /** \return True if window is fullscreen. */ bool isFullscreen() const override; + //! Checks if the window could possibly be visible. + bool isWindowVisible() const override; + //! Get the position of this window on screen core::position2di getWindowPosition() override; @@ -319,6 +322,7 @@ private: SDL_SysWMinfo Info; s32 CurrentTouchCount; + bool IsInBackground; }; } // end namespace irr diff --git a/irr/src/CMakeLists.txt b/irr/src/CMakeLists.txt index 23944105f..c6c590841 100644 --- a/irr/src/CMakeLists.txt +++ b/irr/src/CMakeLists.txt @@ -1,4 +1,4 @@ -if(NOT ANDROID AND NOT APPLE) +if(NOT APPLE) set(DEFAULT_SDL2 ON) endif() @@ -77,10 +77,9 @@ elseif(APPLE) set(DEVICE "OSX") elseif(ANDROID) add_definitions(-D_IRR_ANDROID_PLATFORM_) - if(USE_SDL2) - message(FATAL_ERROR "SDL2 device is not (yet) supported on Android") + if(NOT USE_SDL2) + message(FATAL_ERROR "The Android build requires SDL2") endif() - set(DEVICE "ANDROID") elseif(EMSCRIPTEN) add_definitions(-D_IRR_EMSCRIPTEN_PLATFORM_ -D_IRR_COMPILE_WITH_EGL_MANAGER_) set(LINUX_PLATFORM TRUE) @@ -131,7 +130,10 @@ endif() # OpenGL if(USE_SDL2) - option(ENABLE_OPENGL3 "Enable OpenGL 3+" TRUE) + if(NOT ANDROID) + set(DEFAULT_OPENGL3 TRUE) + endif() + option(ENABLE_OPENGL3 "Enable OpenGL 3+" ${DEFAULT_OPENGL3}) else() set(ENABLE_OPENGL3 FALSE) endif() @@ -142,13 +144,10 @@ else() option(ENABLE_OPENGL "Enable OpenGL" TRUE) endif() -if(EMSCRIPTEN OR APPLE) +if(USE_SDL2 OR EMSCRIPTEN OR APPLE) set(ENABLE_GLES1 FALSE) else() - if(ANDROID) - set(DEFAULT_GLES1 TRUE) - endif() - option(ENABLE_GLES1 "Enable OpenGL ES" ${DEFAULT_GLES1}) + option(ENABLE_GLES1 "Enable OpenGL ES" FALSE) endif() if(APPLE) @@ -188,19 +187,16 @@ if(ENABLE_OPENGL3) endif() if(ENABLE_GLES1) - if (USE_SDL2) - message(FATAL_ERROR "OpenGL ES 1 is not supported with SDL2") - endif() add_definitions(-D_IRR_COMPILE_WITH_OGLES1_) set(OPENGLES_DIRECT_LINK TRUE) - if(DEVICE MATCHES "^(WINDOWS|X11|ANDROID)$") + if(DEVICE MATCHES "^(WINDOWS|X11)$") add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_) endif() endif() if(ENABLE_GLES2) add_definitions(-D_IRR_COMPILE_WITH_OGLES2_) - if(DEVICE MATCHES "^(WINDOWS|X11|ANDROID)$" OR EMSCRIPTEN) + if(DEVICE MATCHES "^(WINDOWS|X11)$" OR EMSCRIPTEN) add_definitions(-D_IRR_COMPILE_WITH_EGL_MANAGER_) endif() endif() @@ -248,11 +244,15 @@ endif() if(ENABLE_GLES2) find_package(OpenGLES2 REQUIRED) endif() -if(ENABLE_OPENGL OR ENABLE_OPENGL3) +if(ENABLE_OPENGL) find_package(OpenGL REQUIRED) endif() if(USE_SDL2) - find_package(SDL2 REQUIRED) + if(NOT ANDROID) + find_package(SDL2 REQUIRED) + else() + # provided by MinetestAndroidLibs.cmake + endif() message(STATUS "Found SDL2: ${SDL2_LIBRARIES}") # unfortunately older SDL does not provide its version to cmake, so check header. @@ -323,7 +323,6 @@ set(link_includes ${OPENGLES2_INCLUDE_DIR} ${EGL_INCLUDE_DIR} - "$<$:${ANDROID_NDK}/sources/android/native_app_glue>" "$<$:${X11_INCLUDE_DIR}>" ) @@ -453,14 +452,7 @@ if(ENABLE_OPENGL3) target_compile_definitions(IRROTHEROBJ PRIVATE ENABLE_OPENGL3) endif() -if(ANDROID) - target_sources(IRROTHEROBJ PRIVATE - Android/CIrrDeviceAndroid.cpp - Android/CAndroidAssetReader.cpp - Android/CAndroidAssetFileArchive.cpp - Android/CKeyEventWrapper.cpp - ) -elseif(APPLE) +if(APPLE) # Build all IRROTHEROBJ sources as objc++, including the .cpp's set_target_properties(IRROTHEROBJ PROPERTIES COMPILE_OPTIONS "-xobjective-c++") target_sources(IRROTHEROBJ PRIVATE @@ -535,7 +527,8 @@ target_link_libraries(IrrlichtMt PRIVATE "$<$:${OPENGLES_LIBRARY}>" ${EGL_LIBRARY} - "$<$:-landroid -llog>" + # incl. transitive SDL2 dependencies for static linking + "$<$:-landroid -llog -lGLESv2 -lGLESv1_CM -lOpenSLES>" ${COCOA_LIB} ${IOKIT_LIB} "$<$:gdi32>" diff --git a/irr/src/COGLESDriver.cpp b/irr/src/COGLESDriver.cpp index 2cd8430f2..4376fff08 100644 --- a/irr/src/COGLESDriver.cpp +++ b/irr/src/COGLESDriver.cpp @@ -19,10 +19,6 @@ #include "CImage.h" #include "os.h" -#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ -#include "android_native_app_glue.h" -#endif - namespace irr { namespace video diff --git a/irr/src/COGLESExtensionHandler.cpp b/irr/src/COGLESExtensionHandler.cpp index ba2c0c9bf..82f8e9261 100644 --- a/irr/src/COGLESExtensionHandler.cpp +++ b/irr/src/COGLESExtensionHandler.cpp @@ -12,7 +12,7 @@ #include "SMaterial.h" #include "fast_atof.h" -#if defined(_IRR_COMPILE_WITH_ANDROID_DEVICE_) || defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) +#if defined(_IRR_COMPILE_WITH_WINDOWS_DEVICE_) #include #else #include diff --git a/irr/src/Irrlicht.cpp b/irr/src/Irrlicht.cpp index c97e5d308..932d63450 100644 --- a/irr/src/Irrlicht.cpp +++ b/irr/src/Irrlicht.cpp @@ -28,10 +28,6 @@ static const char *const copyright = "Irrlicht Engine (c) 2002-2017 Nikolaus Geb #include "CIrrDeviceSDL.h" #endif -#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ -#include "Android/CIrrDeviceAndroid.h" -#endif - namespace irr { //! stub for calling createDeviceEx @@ -74,11 +70,6 @@ extern "C" IRRLICHT_API IrrlichtDevice *IRRCALLCONV createDeviceEx(const SIrrlic dev = new CIrrDeviceLinux(params); #endif -#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ - if (params.DeviceType == EIDT_ANDROID || (!dev && params.DeviceType == EIDT_BEST)) - dev = new CIrrDeviceAndroid(params); -#endif - #ifdef _IRR_COMPILE_WITH_SDL_DEVICE_ if (params.DeviceType == EIDT_SDL || (!dev && params.DeviceType == EIDT_BEST)) dev = new CIrrDeviceSDL(params); diff --git a/irr/src/OpenGL/Driver.cpp b/irr/src/OpenGL/Driver.cpp index 73c3451f7..fc66995a3 100644 --- a/irr/src/OpenGL/Driver.cpp +++ b/irr/src/OpenGL/Driver.cpp @@ -21,10 +21,6 @@ #include "CImage.h" #include "os.h" -#ifdef _IRR_COMPILE_WITH_ANDROID_DEVICE_ -#include "android_native_app_glue.h" -#endif - #include "mt_opengl.h" namespace irr diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 0f06d3f4d..56083e376 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -307,10 +307,6 @@ else() endif() if (ANDROID) - include_directories(${ANDROID_NDK}/sources/android/native_app_glue) - add_library(native_app_glue OBJECT ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) - set(PLATFORM_LIBS ${PLATFORM_LIBS} native_app_glue) - set(PLATFORM_LIBS ${PLATFORM_LIBS} android log) endif() endif() @@ -518,6 +514,9 @@ include_directories(SYSTEM ${GMP_INCLUDE_DIR} ${JSON_INCLUDE_DIR} ${LUA_BIT_INCLUDE_DIR} + # on Android, Minetest depends on SDL2 directly + # on other platforms, only IrrlichtMt depends on SDL2 + "$<$:${SDL2_INCLUDE_DIRS}>" ) if(USE_GETTEXT) @@ -562,6 +561,9 @@ if(BUILD_CLIENT) ${LUA_BIT_LIBRARY} ${FREETYPE_LIBRARY} ${PLATFORM_LIBS} + # on Android, Minetest depends on SDL2 directly + # on other platforms, only IrrlichtMt depends on SDL2 + "$<$:${SDL2_LIBRARIES}>" ) if(NOT USE_LUAJIT) set_target_properties(${PROJECT_NAME} PROPERTIES diff --git a/src/client/game.cpp b/src/client/game.cpp index 55ec480b5..d89b6639c 100644 --- a/src/client/game.cpp +++ b/src/client/game.cpp @@ -2258,9 +2258,11 @@ void Game::openConsole(float scale, const wchar_t *line) assert(scale > 0.0f && scale <= 1.0f); #ifdef __ANDROID__ - porting::showTextInputDialog("", "", 2); - m_android_chat_open = true; -#else + if (!porting::hasPhysicalKeyboardAndroid()) { + porting::showTextInputDialog("", "", 2); + m_android_chat_open = true; + } else { +#endif if (gui_chat_console->isOpenInhibited()) return; gui_chat_console->openConsole(scale); @@ -2268,6 +2270,8 @@ void Game::openConsole(float scale, const wchar_t *line) gui_chat_console->setCloseOnEnter(true); gui_chat_console->replaceAndAddToHistory(line); } +#ifdef __ANDROID__ + } // else #endif } diff --git a/src/client/renderingengine.cpp b/src/client/renderingengine.cpp index 51f5e1e92..298ecadbd 100644 --- a/src/client/renderingengine.cpp +++ b/src/client/renderingengine.cpp @@ -229,9 +229,7 @@ RenderingEngine::RenderingEngine(IEventReceiver *receiver) params.Stencilbuffer = false; params.Vsync = vsync; params.EventReceiver = receiver; -#ifdef __ANDROID__ - params.PrivateData = porting::app_global; -#endif + // there is no standardized path for these on desktop std::string rel_path = std::string("client") + DIR_DELIM + "shaders" + DIR_DELIM + "Irrlicht"; diff --git a/src/gui/modalMenu.cpp b/src/gui/modalMenu.cpp index ae2a89e96..bb287ecd1 100644 --- a/src/gui/modalMenu.cpp +++ b/src/gui/modalMenu.cpp @@ -239,7 +239,8 @@ bool GUIModalMenu::preprocessEvent(const SEvent &event) #ifdef __ANDROID__ // display software keyboard when clicking edit boxes if (event.EventType == EET_MOUSE_INPUT_EVENT && - event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { + event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN && + !porting::hasPhysicalKeyboardAndroid()) { gui::IGUIElement *hovered = Environment->getRootGUIElement()->getElementFromPoint( core::position2d(event.MouseInput.X, event.MouseInput.Y)); diff --git a/src/log.cpp b/src/log.cpp index 16d6024e7..8ab0ca4ba 100644 --- a/src/log.cpp +++ b/src/log.cpp @@ -29,6 +29,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "util/numeric.h" #include "log.h" +#ifdef __ANDROID__ +#include +#endif + #include #include #include diff --git a/src/porting_android.cpp b/src/porting_android.cpp index a649751d3..760feedfe 100644 --- a/src/porting_android.cpp +++ b/src/porting_android.cpp @@ -30,6 +30,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "log.h" #include "settings.h" +#include +#define SDL_MAIN_HANDLED 1 +#include + #include #include #include @@ -53,10 +57,8 @@ namespace porting { bool setSystemPaths(); // used in porting.cpp } -void android_main(android_app *app) +extern "C" int SDL_Main(int _argc, char *_argv[]) { - porting::app_global = app; - Thread::setName("Main"); char *argv[] = {strdup(PROJECT_NAME), strdup("--verbose"), nullptr}; @@ -70,45 +72,15 @@ void android_main(android_app *app) } namespace porting { -android_app *app_global = nullptr; JNIEnv *jnienv = nullptr; -jclass nativeActivity; - -jclass findClass(const std::string &classname) -{ - if (jnienv == nullptr) - return nullptr; - - jclass nativeactivity = jnienv->FindClass("android/app/NativeActivity"); - jmethodID getClassLoader = jnienv->GetMethodID( - nativeactivity, "getClassLoader", "()Ljava/lang/ClassLoader;"); - jobject cls = jnienv->CallObjectMethod( - app_global->activity->clazz, getClassLoader); - jclass classLoader = jnienv->FindClass("java/lang/ClassLoader"); - jmethodID findClass = jnienv->GetMethodID(classLoader, "loadClass", - "(Ljava/lang/String;)Ljava/lang/Class;"); - jstring strClassName = jnienv->NewStringUTF(classname.c_str()); - return (jclass) jnienv->CallObjectMethod(cls, findClass, strClassName); -} +jobject activity; +jclass activityClass; void osSpecificInit() { - JavaVM *jvm = app_global->activity->vm; - JavaVMAttachArgs lJavaVMAttachArgs; - lJavaVMAttachArgs.version = JNI_VERSION_1_6; - lJavaVMAttachArgs.name = PROJECT_NAME_C "NativeThread"; - lJavaVMAttachArgs.group = nullptr; - - if (jvm->AttachCurrentThread(&porting::jnienv, &lJavaVMAttachArgs) == JNI_ERR) { - errorstream << "Failed to attach native thread to jvm" << std::endl; - exit(-1); - } - - nativeActivity = findClass("net/minetest/minetest/GameActivity"); - if (nativeActivity == nullptr) - errorstream << - "porting::initAndroid unable to find Java native activity class" << - std::endl; + jnienv = (JNIEnv*)SDL_AndroidGetJNIEnv(); + activity = (jobject)SDL_AndroidGetActivity(); + activityClass = jnienv->GetObjectClass(activity); // Set default language auto lang = getLanguageAndroid(); @@ -129,9 +101,6 @@ void cleanupAndroid() setenv("CPUPROFILE", (path_user + DIR_DELIM + "gmon.out").c_str(), 1); moncleanup(); #endif - - JavaVM *jvm = app_global->activity->vm; - jvm->DetachCurrentThread(); } static std::string readJavaString(jstring j_str) @@ -149,11 +118,11 @@ bool setSystemPaths() { // Set user and share paths { - jmethodID getUserDataPath = jnienv->GetMethodID(nativeActivity, + jmethodID getUserDataPath = jnienv->GetMethodID(activityClass, "getUserDataPath", "()Ljava/lang/String;"); FATAL_ERROR_IF(getUserDataPath==nullptr, "porting::initializePathsAndroid unable to find Java getUserDataPath method"); - jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getUserDataPath); + jobject result = jnienv->CallObjectMethod(activity, getUserDataPath); std::string str = readJavaString((jstring) result); path_user = str; path_share = str; @@ -161,11 +130,11 @@ bool setSystemPaths() // Set cache path { - jmethodID getCachePath = jnienv->GetMethodID(nativeActivity, + jmethodID getCachePath = jnienv->GetMethodID(activityClass, "getCachePath", "()Ljava/lang/String;"); FATAL_ERROR_IF(getCachePath==nullptr, "porting::initializePathsAndroid unable to find Java getCachePath method"); - jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, getCachePath); + jobject result = jnienv->CallObjectMethod(activity, getCachePath); path_cache = readJavaString((jstring) result); } @@ -174,7 +143,7 @@ bool setSystemPaths() void showTextInputDialog(const std::string &hint, const std::string ¤t, int editType) { - jmethodID showdialog = jnienv->GetMethodID(nativeActivity, "showTextInputDialog", + jmethodID showdialog = jnienv->GetMethodID(activityClass, "showTextInputDialog", "(Ljava/lang/String;Ljava/lang/String;I)V"); FATAL_ERROR_IF(showdialog == nullptr, @@ -184,13 +153,13 @@ void showTextInputDialog(const std::string &hint, const std::string ¤t, in jstring jcurrent = jnienv->NewStringUTF(current.c_str()); jint jeditType = editType; - jnienv->CallVoidMethod(app_global->activity->clazz, showdialog, + jnienv->CallVoidMethod(activity, showdialog, jhint, jcurrent, jeditType); } void showComboBoxDialog(const std::string optionList[], s32 listSize, s32 selectedIdx) { - jmethodID showdialog = jnienv->GetMethodID(nativeActivity, "showSelectionInputDialog", + jmethodID showdialog = jnienv->GetMethodID(activityClass, "showSelectionInputDialog", "([Ljava/lang/String;I)V"); FATAL_ERROR_IF(showdialog == nullptr, @@ -205,79 +174,79 @@ void showComboBoxDialog(const std::string optionList[], s32 listSize, s32 select jnienv->NewStringUTF(optionList[i].c_str())); } - jnienv->CallVoidMethod(app_global->activity->clazz, showdialog, jOptionList, + jnienv->CallVoidMethod(activity, showdialog, jOptionList, jselectedIdx); } void openURIAndroid(const char *url) { - jmethodID url_open = jnienv->GetMethodID(nativeActivity, "openURI", + jmethodID url_open = jnienv->GetMethodID(activityClass, "openURI", "(Ljava/lang/String;)V"); FATAL_ERROR_IF(url_open == nullptr, "porting::openURIAndroid unable to find Java openURI method"); jstring jurl = jnienv->NewStringUTF(url); - jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl); + jnienv->CallVoidMethod(activity, url_open, jurl); } void shareFileAndroid(const std::string &path) { - jmethodID url_open = jnienv->GetMethodID(nativeActivity, "shareFile", + jmethodID url_open = jnienv->GetMethodID(activityClass, "shareFile", "(Ljava/lang/String;)V"); FATAL_ERROR_IF(url_open == nullptr, "porting::shareFileAndroid unable to find Java shareFile method"); jstring jurl = jnienv->NewStringUTF(path.c_str()); - jnienv->CallVoidMethod(app_global->activity->clazz, url_open, jurl); + jnienv->CallVoidMethod(activity, url_open, jurl); } AndroidDialogType getLastInputDialogType() { - jmethodID lastdialogtype = jnienv->GetMethodID(nativeActivity, + jmethodID lastdialogtype = jnienv->GetMethodID(activityClass, "getLastDialogType", "()I"); FATAL_ERROR_IF(lastdialogtype == nullptr, "porting::getLastInputDialogType unable to find Java getLastDialogType method"); - int dialogType = jnienv->CallIntMethod(app_global->activity->clazz, lastdialogtype); + int dialogType = jnienv->CallIntMethod(activity, lastdialogtype); return static_cast(dialogType); } AndroidDialogState getInputDialogState() { - jmethodID inputdialogstate = jnienv->GetMethodID(nativeActivity, + jmethodID inputdialogstate = jnienv->GetMethodID(activityClass, "getInputDialogState", "()I"); FATAL_ERROR_IF(inputdialogstate == nullptr, "porting::getInputDialogState unable to find Java getInputDialogState method"); - int dialogState = jnienv->CallIntMethod(app_global->activity->clazz, inputdialogstate); + int dialogState = jnienv->CallIntMethod(activity, inputdialogstate); return static_cast(dialogState); } std::string getInputDialogMessage() { - jmethodID dialogvalue = jnienv->GetMethodID(nativeActivity, + jmethodID dialogvalue = jnienv->GetMethodID(activityClass, "getDialogMessage", "()Ljava/lang/String;"); FATAL_ERROR_IF(dialogvalue == nullptr, "porting::getInputDialogMessage unable to find Java getDialogMessage method"); - jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, + jobject result = jnienv->CallObjectMethod(activity, dialogvalue); return readJavaString((jstring) result); } int getInputDialogSelection() { - jmethodID dialogvalue = jnienv->GetMethodID(nativeActivity, "getDialogSelection", "()I"); + jmethodID dialogvalue = jnienv->GetMethodID(activityClass, "getDialogSelection", "()I"); FATAL_ERROR_IF(dialogvalue == nullptr, "porting::getInputDialogSelection unable to find Java getDialogSelection method"); - return jnienv->CallIntMethod(app_global->activity->clazz, dialogvalue); + return jnienv->CallIntMethod(activity, dialogvalue); } #ifndef SERVER @@ -287,13 +256,13 @@ float getDisplayDensity() static float value = 0; if (firstrun) { - jmethodID getDensity = jnienv->GetMethodID(nativeActivity, + jmethodID getDensity = jnienv->GetMethodID(activityClass, "getDensity", "()F"); FATAL_ERROR_IF(getDensity == nullptr, "porting::getDisplayDensity unable to find Java getDensity method"); - value = jnienv->CallFloatMethod(app_global->activity->clazz, getDensity); + value = jnienv->CallFloatMethod(activity, getDensity); firstrun = false; } @@ -306,22 +275,22 @@ v2u32 getDisplaySize() static v2u32 retval; if (firstrun) { - jmethodID getDisplayWidth = jnienv->GetMethodID(nativeActivity, + jmethodID getDisplayWidth = jnienv->GetMethodID(activityClass, "getDisplayWidth", "()I"); FATAL_ERROR_IF(getDisplayWidth == nullptr, "porting::getDisplayWidth unable to find Java getDisplayWidth method"); - retval.X = jnienv->CallIntMethod(app_global->activity->clazz, + retval.X = jnienv->CallIntMethod(activity, getDisplayWidth); - jmethodID getDisplayHeight = jnienv->GetMethodID(nativeActivity, + jmethodID getDisplayHeight = jnienv->GetMethodID(activityClass, "getDisplayHeight", "()I"); FATAL_ERROR_IF(getDisplayHeight == nullptr, "porting::getDisplayHeight unable to find Java getDisplayHeight method"); - retval.Y = jnienv->CallIntMethod(app_global->activity->clazz, + retval.Y = jnienv->CallIntMethod(activity, getDisplayHeight); firstrun = false; @@ -332,16 +301,29 @@ v2u32 getDisplaySize() std::string getLanguageAndroid() { - jmethodID getLanguage = jnienv->GetMethodID(nativeActivity, + jmethodID getLanguage = jnienv->GetMethodID(activityClass, "getLanguage", "()Ljava/lang/String;"); FATAL_ERROR_IF(getLanguage == nullptr, "porting::getLanguageAndroid unable to find Java getLanguage method"); - jobject result = jnienv->CallObjectMethod(app_global->activity->clazz, + jobject result = jnienv->CallObjectMethod(activity, getLanguage); return readJavaString((jstring) result); } +bool hasPhysicalKeyboardAndroid() +{ + jmethodID hasPhysicalKeyboard = jnienv->GetMethodID(activityClass, + "hasPhysicalKeyboard", "()Z"); + + FATAL_ERROR_IF(hasPhysicalKeyboard == nullptr, + "porting::hasPhysicalKeyboardAndroid unable to find Java hasPhysicalKeyboard method"); + + jboolean result = jnienv->CallBooleanMethod(activity, + hasPhysicalKeyboard); + return result; +} + #endif // ndef SERVER } diff --git a/src/porting_android.h b/src/porting_android.h index f7407003a..8b015553b 100644 --- a/src/porting_android.h +++ b/src/porting_android.h @@ -23,21 +23,10 @@ with this program; if not, write to the Free Software Foundation, Inc., #error This header has to be included on Android port only! #endif -#include -#include -#include - #include "irrlichttypes_bloated.h" - #include namespace porting { -// Java app -extern android_app *app_global; - -// Java <-> C++ interaction interface -extern JNIEnv *jnienv; - /** * Show a text input dialog in Java * @param hint Hint to be shown @@ -105,6 +94,9 @@ std::string getInputDialogMessage(); */ int getInputDialogSelection(); + +bool hasPhysicalKeyboardAndroid(); + #ifndef SERVER float getDisplayDensity(); v2u32 getDisplaySize();