diff --git a/app/src/main/cpp/sdl3bridge/CMakeLists.txt b/app/src/main/cpp/sdl3bridge/CMakeLists.txt index a9f2757fd..1ca8a275f 100644 --- a/app/src/main/cpp/sdl3bridge/CMakeLists.txt +++ b/app/src/main/cpp/sdl3bridge/CMakeLists.txt @@ -10,6 +10,14 @@ set(SDL_INSTALL OFF CACHE BOOL "" FORCE) # The bridge draws nothing (SDL3 runs headless for controllers): no OpenGL ES, so libSDL3.so needs no libGLESv1_CM.so, # which DroidDeck's APK check (tools/release/check_android_libraries.py) does not count as a system library. set(SDL_OPENGLES OFF CACHE BOOL "" FORCE) -add_subdirectory(SDL) +include(FetchContent) +if(POLICY CMP0135) + cmake_policy(SET CMP0135 NEW) +endif() +FetchContent_Declare(sdl3 + URL https://github.com/libsdl-org/SDL/releases/download/release-3.4.18/SDL3-3.4.18.tar.gz + URL_HASH SHA256=9c75cf16330322c217dedd2e0609f1124f1b54b8633e763467b4684d0f4334a3 +) +FetchContent_MakeAvailable(sdl3) add_library(main SHARED src/main.c) target_link_libraries(main PRIVATE SDL3::SDL3 log) diff --git a/app/src/test/java/com/example/dsedge/EmbeddedBridgeTest.kt b/app/src/test/java/com/example/dsedge/EmbeddedBridgeTest.kt new file mode 100644 index 000000000..e5442d08f --- /dev/null +++ b/app/src/test/java/com/example/dsedge/EmbeddedBridgeTest.kt @@ -0,0 +1,44 @@ +package com.example.dsedge + +import android.app.Application +import android.content.ComponentName +import android.content.pm.PackageManager +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.RobolectricTestRunner +import org.robolectric.RuntimeEnvironment +import org.robolectric.annotation.Config + +@RunWith(RobolectricTestRunner::class) +@Config(sdk = [28], application = Application::class) +class EmbeddedBridgeTest { + @Test + fun driverComponentsStayPrivateAndRunOutsideTheSessionProcess() { + val app = RuntimeEnvironment.getApplication() + val pm = app.packageManager + val service = pm.getServiceInfo(ComponentName(app, "com.example.dsedge.BridgeService"), 0) + assertFalse(service.exported) + assertEquals("${app.packageName}:sdl3", service.processName) + for (name in listOf("BridgeActivity", "SdlHostActivity")) { + val activity = pm.getActivityInfo(ComponentName(app, "com.example.dsedge.$name"), 0) + assertFalse(activity.exported) + assertEquals(service.processName, activity.processName) + } + val usb = pm.getActivityInfo(ComponentName(app, "com.example.dsedge.UsbAttachActivity"), + PackageManager.GET_META_DATA) + assertTrue(usb.exported) + assertEquals(service.processName, usb.processName) + assertTrue(usb.metaData.containsKey("android.hardware.usb.action.USB_DEVICE_ATTACHED")) + } + + @Test + fun embeddedBridgePreferencesDoNotShareDroidDeckSettings() { + val app = RuntimeEnvironment.getApplication() + assertTrue(Host.embedded(app)) + assertEquals("sdl3bridge_settings", Host.prefs(app, "settings")) + assertEquals("sdl3bridge_engine", Host.prefs(app, "engine")) + } +} diff --git a/docs/development/sdl3-controllers.md b/docs/development/sdl3-controllers.md new file mode 100644 index 000000000..014348631 --- /dev/null +++ b/docs/development/sdl3-controllers.md @@ -0,0 +1,42 @@ +# SDL3 controller bridge + +The integrated bridge runs in DroidDeck's `:sdl3` process. Open **Settings → SDL3Bridge** +or the SDL3Bridge page in the session drawer to configure up to four controllers. +USB controllers use SDL3's HID drivers; Android input remains the fallback for +Bluetooth and built-in controllers. Steam Native Hook-up forwards a USB controller's +identity and reports to Steam so Steam can use its own controller driver. + +USB access requires Android's device permission. The optional floating control also +requires permission to display over other apps. A separate SDL3Bridge installation +should be stopped before using the integrated bridge with the same USB controller. +Gyro, touchpad, remapping and lightbar settings belong to Steam while Hook-up is active. + +## Source and attribution + +The controller implementation is by [pablo89898991](https://github.com/pablo89898991), +imported from [SdlBridge at 63feeac6](https://github.com/pablo89898991/SdlBridge/tree/63feeac6) +through [SDLApiDroidDeck at 131f1cef](https://github.com/pablo89898991/SDLApiDroidDeck/tree/131f1cef). +The imported commit retains Pablo's Git author identity. DroidDeck integration and +build adjustments are recorded separately. + +The port keeps DroidDeck's name, signing, workflows and test failure handling. It +excludes the fork's ADPF changes, cursor-compositing default, Steam controller-rate +override, and CI/download fallbacks. + +SDL 3.4.18 is downloaded by CMake from its official release archive and verified +against its SHA-256 digest. Its Android Java classes are imported from the same +release. `HIDDeviceManager.java` retains the bridge's marked Bluetooth-permission +adjustment. SDL uses the zlib license, included in +`app/src/main/assets/licenses/sdl3/LICENSE.txt`; the bridge is distributed under +DroidDeck's GPLv3 license. + +## Hardware checks + +Check that the built-in controller still navigates DroidDeck and Steam with the +SDL3 driver both enabled and disabled. Open the bridge settings and controller test +screen, then start and stop a session without a USB controller attached. + +With a USB controller, grant access and verify hot-plug, buttons, sticks, gyro, +touchpad and rumble in presented-controller mode. Repeat with Steam Native Hook-up, +including switching back, disconnecting, and reconnecting. Verify multiple player +slots and Steam on the desktop when the corresponding hardware is available.