mirror of
https://github.com/liberatedsystems/openCom-Companion.git
synced 2024-11-22 05:20:36 +01:00
Added USB support and foreground service basics
This commit is contained in:
parent
ff47102b92
commit
39d39de914
@ -15,17 +15,35 @@ cleanall: clean cleanlibs
|
|||||||
activate:
|
activate:
|
||||||
(. venv/bin/activate)
|
(. venv/bin/activate)
|
||||||
|
|
||||||
|
pacthfiles: patchsdl injectxml
|
||||||
|
|
||||||
|
patchsdl:
|
||||||
|
cp patches/HIDDeviceUSB.java .buildozer/android/platform/build-arm64-v8a/build/bootstrap_builds/sdl2/jni/SDL/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
|
||||||
|
cp patches/HIDDeviceUSB.java .buildozer/android/platform/build-arm64-v8a/dists/sideband/src/main/java/org/libsdl/app/HIDDeviceUSB.java
|
||||||
|
cp patches/HIDDeviceUSB.java .buildozer/android/platform/build-arm64-v8a/dists/sideband/jni/SDL/android-project/app/src/main/java/org/libsdl/app/HIDDeviceUSB.java
|
||||||
|
|
||||||
|
injectxml:
|
||||||
|
mkdir -p .buildozer/android/platform/build-arm64-v8a/dists/sideband/src/main/res/xml
|
||||||
|
mkdir -p .buildozer/android/platform/build-arm64-v8a/dists/sideband/templates
|
||||||
|
cp patches/device_filter.xml .buildozer/android/platform/build-arm64-v8a/dists/sideband/src/main/res/xml/
|
||||||
|
cp patches/AndroidManifest.tmpl.xml .buildozer/android/platform/build-arm64-v8a/dists/sideband/templates/
|
||||||
|
|
||||||
debug:
|
debug:
|
||||||
buildozer android debug
|
buildozer android debug
|
||||||
|
|
||||||
|
prebake:
|
||||||
|
-(buildozer android release)
|
||||||
|
@(echo Prebake finished, applying patches and rebuilding...)
|
||||||
|
-(sleep 2)
|
||||||
|
|
||||||
release:
|
release:
|
||||||
buildozer android release
|
buildozer android release
|
||||||
|
|
||||||
postbuild: cleanrns
|
postbuild: cleanrns
|
||||||
|
|
||||||
apk: prepare release postbuild
|
apk: prepare prebake pacthfiles release postbuild
|
||||||
|
|
||||||
devapk: prepare debug postbuild
|
devapk: prepare prebake pacthfiles debug postbuild
|
||||||
|
|
||||||
version:
|
version:
|
||||||
@(echo $$(python ./gv.py))
|
@(echo $$(python ./gv.py))
|
||||||
|
@ -13,7 +13,7 @@ version.filename = %(source.dir)s/main.py
|
|||||||
|
|
||||||
android.numeric_version = 1
|
android.numeric_version = 1
|
||||||
|
|
||||||
requirements = python3==3.9.5,hostpython3==3.9.5,cryptography,cffi,pycparser,kivy==2.1.0,pygments,sdl2_ttf==2.0.15,pillow,lxmf==0.1.7,netifaces,libbz2,pydenticon
|
requirements = python3==3.9.5,hostpython3==3.9.5,cryptography,cffi,pycparser,kivy==2.1.0,pygments,sdl2,sdl2_ttf==2.0.15,pillow,lxmf==0.1.7,netifaces,libbz2,pydenticon
|
||||||
p4a.local_recipes = ../Others/python-for-android/pythonforandroid/recipes
|
p4a.local_recipes = ../Others/python-for-android/pythonforandroid/recipes
|
||||||
requirements.source.kivymd = ../../Others/KivyMD-master
|
requirements.source.kivymd = ../../Others/KivyMD-master
|
||||||
# requirements.source.plyer = ../../Others/plyer
|
# requirements.source.plyer = ../../Others/plyer
|
||||||
@ -25,7 +25,7 @@ android.presplash_color = #00000000
|
|||||||
orientation = all
|
orientation = all
|
||||||
fullscreen = 0
|
fullscreen = 0
|
||||||
|
|
||||||
android.permissions = INTERNET,POST_NOTIFICATIONS
|
android.permissions = INTERNET,POST_NOTIFICATIONS,WAKE_LOCK,FOREGROUND_SERVICE
|
||||||
android.api = 30
|
android.api = 30
|
||||||
android.minapi = 27
|
android.minapi = 27
|
||||||
android.ndk = 19b
|
android.ndk = 19b
|
||||||
@ -34,6 +34,9 @@ android.accept_sdk_license = True
|
|||||||
android.arch = arm64-v8a
|
android.arch = arm64-v8a
|
||||||
#android.logcat_filters = *:S python:D
|
#android.logcat_filters = *:S python:D
|
||||||
|
|
||||||
|
# services = sidebandservice:services/sidebandservice.py:foreground
|
||||||
|
android.manifest.intent_filters = patches/intent-filter.xml
|
||||||
|
|
||||||
[buildozer]
|
[buildozer]
|
||||||
log_level = 2
|
log_level = 2
|
||||||
warn_on_root = 0
|
warn_on_root = 0
|
||||||
|
@ -83,6 +83,13 @@ class SidebandApp(MDApp):
|
|||||||
Clock.schedule_once(dismiss_splash, 0)
|
Clock.schedule_once(dismiss_splash, 0)
|
||||||
|
|
||||||
|
|
||||||
|
def start_android_service(self):
|
||||||
|
service = autoclass('io.unsigned.sideband.ServiceSidebandservice')
|
||||||
|
mActivity = autoclass('org.kivy.android.PythonActivity').mActivity
|
||||||
|
argument = ""
|
||||||
|
service.start(mActivity, argument)
|
||||||
|
|
||||||
|
|
||||||
#################################################
|
#################################################
|
||||||
# General helpers #
|
# General helpers #
|
||||||
#################################################
|
#################################################
|
||||||
@ -859,7 +866,7 @@ If you are not connected to the network, it is still possible for other people t
|
|||||||
|
|
||||||
The Propagation Nodes also distribute copies of messages between each other, such that even the failure of almost every node in the network will still allow users to sync their waiting messages. If all Propagation Nodes disappear or are destroyed, users can still communicate directly. Reticulum and LXMF will degrade gracefully all the way down to single users communicating directly via long-range data radios. Anyone can start up new propagation nodes and integrate them into existing networks without permission or coordination. Even a small and cheap device like a Rasperry Pi can handle messages for millions of users. LXMF networks are designed to be quite resilient, as long as there are people using them.
|
The Propagation Nodes also distribute copies of messages between each other, such that even the failure of almost every node in the network will still allow users to sync their waiting messages. If all Propagation Nodes disappear or are destroyed, users can still communicate directly. Reticulum and LXMF will degrade gracefully all the way down to single users communicating directly via long-range data radios. Anyone can start up new propagation nodes and integrate them into existing networks without permission or coordination. Even a small and cheap device like a Rasperry Pi can handle messages for millions of users. LXMF networks are designed to be quite resilient, as long as there are people using them.
|
||||||
|
|
||||||
Connections in Reticulum networks can be wired or wireless, span many intermediary hops, run over fast links or ultra-low bandwidth radio, tunnel over the Invisible Internet (I2P), private networks, satellite connections, serial lines or anything else that Reticulum can carry data over. In most cases it will not be possible to know what path data takes in a Reticulum network, and no transmitted data carries any identifying characteristics, apart from a destination address. There is no source addresses in Reticulum. As long as you do not establish a link between you personal identity and your LXMF address through some other method, you can remain anonymous. Sending messages to others does not reveal [i]your[/i] address.
|
Connections in Reticulum networks can be wired or wireless, span many intermediary hops, run over fast links or ultra-low bandwidth radio, tunnel over the Invisible Internet (I2P), private networks, satellite connections, serial lines or anything else that Reticulum can carry data over. In most cases it will not be possible to know what path data takes in a Reticulum network, and no transmitted data carries any identifying characteristics, apart from a destination address. There is no source addresses in Reticulum. As long as you do not reveal any connecting details between your person and your LXMF address, you can remain anonymous. Sending messages to others does not reveal [i]your[/i] address to anyone else than the intended recipient.
|
||||||
|
|
||||||
That being said, you [b]must remember[/b] that LXMF and Reticulum is not a technology that can guarantee anonymising connections that are already de-anonymised! If you use Sideband to connect to TCP Reticulum hubs over the clear Internet, from a network that can be tied to your personal identity, an adversary may learn that you are generating LXMF traffic. If you want to avoid this, it is recommended to use I2P to connect to Reticulum hubs on the Internet. Or only connecting from within pure Reticulum networks, that take one or more hops to reach connections that span the Internet. This is a complex topic, with many more nuances than can not be covered here. You are encouraged to ask on the various Reticulum discussion forums if you are in doubt.
|
That being said, you [b]must remember[/b] that LXMF and Reticulum is not a technology that can guarantee anonymising connections that are already de-anonymised! If you use Sideband to connect to TCP Reticulum hubs over the clear Internet, from a network that can be tied to your personal identity, an adversary may learn that you are generating LXMF traffic. If you want to avoid this, it is recommended to use I2P to connect to Reticulum hubs on the Internet. Or only connecting from within pure Reticulum networks, that take one or more hops to reach connections that span the Internet. This is a complex topic, with many more nuances than can not be covered here. You are encouraged to ask on the various Reticulum discussion forums if you are in doubt.
|
||||||
|
|
||||||
|
147
sbapp/patches/AndroidManifest.tmpl.xml
Normal file
147
sbapp/patches/AndroidManifest.tmpl.xml
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<!-- Replace org.libsdl.app with the identifier of your game below, e.g.
|
||||||
|
com.gamemaker.game
|
||||||
|
-->
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
package="{{ args.package }}"
|
||||||
|
android:versionCode="{{ args.numeric_version }}"
|
||||||
|
android:versionName="{{ args.version }}"
|
||||||
|
android:installLocation="auto">
|
||||||
|
|
||||||
|
<supports-screens
|
||||||
|
android:smallScreens="true"
|
||||||
|
android:normalScreens="true"
|
||||||
|
android:largeScreens="true"
|
||||||
|
android:anyDensity="true"
|
||||||
|
{% if args.min_sdk_version >= 9 %}
|
||||||
|
android:xlargeScreens="true"
|
||||||
|
{% endif %}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<!-- Android 2.3.3 -->
|
||||||
|
<uses-sdk android:minSdkVersion="{{ args.min_sdk_version }}" android:targetSdkVersion="{{ android_api }}" />
|
||||||
|
|
||||||
|
<!-- OpenGL ES 2.0 -->
|
||||||
|
<uses-feature android:glEsVersion="0x00020000" />
|
||||||
|
<uses-feature android:name="android.hardware.usb.host" />
|
||||||
|
|
||||||
|
<!-- Allow writing to external storage -->
|
||||||
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
{% for perm in args.permissions %}
|
||||||
|
{% if '.' in perm %}
|
||||||
|
<uses-permission android:name="{{ perm }}" />
|
||||||
|
{% else %}
|
||||||
|
<uses-permission android:name="android.permission.{{ perm }}" />
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if args.wakelock %}
|
||||||
|
<uses-permission android:name="android.permission.WAKE_LOCK" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if args.billing_pubkey %}
|
||||||
|
<uses-permission android:name="com.android.vending.BILLING" />
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{{ args.extra_manifest_xml }}
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Create a Java class extending SDLActivity and place it in a
|
||||||
|
directory under src matching the package, e.g.
|
||||||
|
src/com/gamemaker/game/MyGame.java
|
||||||
|
|
||||||
|
then replace "SDLActivity" with the name of your class (e.g. "MyGame")
|
||||||
|
in the XML below.
|
||||||
|
|
||||||
|
An example Java class can be found in README-android.txt
|
||||||
|
-->
|
||||||
|
<application android:label="@string/app_name"
|
||||||
|
{% if debug %}android:debuggable="true"{% endif %}
|
||||||
|
android:icon="@mipmap/icon"
|
||||||
|
android:allowBackup="{{ args.allow_backup }}"
|
||||||
|
{% if args.backup_rules %}android:fullBackupContent="@xml/{{ args.backup_rules }}"{% endif %}
|
||||||
|
{{ args.extra_manifest_application_arguments }}
|
||||||
|
android:theme="{{args.android_apptheme}}{% if not args.window %}.Fullscreen{% endif %}"
|
||||||
|
android:hardwareAccelerated="true"
|
||||||
|
>
|
||||||
|
{% for l in args.android_used_libs %}
|
||||||
|
<uses-library android:name="{{ l }}" />
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% for m in args.meta_data %}
|
||||||
|
<meta-data android:name="{{ m.split('=', 1)[0] }}" android:value="{{ m.split('=', 1)[-1] }}"/>{% endfor %}
|
||||||
|
<meta-data android:name="wakelock" android:value="{% if args.wakelock %}1{% else %}0{% endif %}"/>
|
||||||
|
|
||||||
|
<activity android:name="{{args.android_entrypoint}}"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:configChanges="mcc|mnc|locale|touchscreen|keyboard|keyboardHidden|navigation|orientation|screenLayout|fontScale|uiMode{% if args.min_sdk_version >= 8 %}|uiMode{% endif %}{% if args.min_sdk_version >= 13 %}|screenSize|smallestScreenSize{% endif %}{% if args.min_sdk_version >= 17 %}|layoutDirection{% endif %}{% if args.min_sdk_version >= 24 %}|density{% endif %}"
|
||||||
|
android:screenOrientation="{{ args.orientation }}"
|
||||||
|
android:exported="true"
|
||||||
|
{% if args.activity_launch_mode %}
|
||||||
|
android:launchMode="{{ args.activity_launch_mode }}"
|
||||||
|
{% endif %}
|
||||||
|
>
|
||||||
|
|
||||||
|
{% if args.launcher %}
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="org.kivy.LAUNCH" />
|
||||||
|
<category android:name="android.intent.category.DEFAULT" />
|
||||||
|
<data android:scheme="{{ url_scheme }}" />
|
||||||
|
</intent-filter>
|
||||||
|
{% else %}
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{%- if args.intent_filters -%}
|
||||||
|
{{- args.intent_filters -}}
|
||||||
|
{%- endif -%}
|
||||||
|
</activity>
|
||||||
|
|
||||||
|
{% if args.launcher %}
|
||||||
|
<activity android:name="org.kivy.android.launcher.ProjectChooser"
|
||||||
|
android:icon="@mipmap/icon"
|
||||||
|
android:label="@string/app_name"
|
||||||
|
android:exported="true">
|
||||||
|
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
</activity>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
|
{% if service or args.launcher %}
|
||||||
|
<service android:name="{{ args.service_class_name }}"
|
||||||
|
android:process=":pythonservice" />
|
||||||
|
{% endif %}
|
||||||
|
{% for name in service_names %}
|
||||||
|
<service android:name="{{ args.package }}.Service{{ name|capitalize }}"
|
||||||
|
android:process=":service_{{ name }}" />
|
||||||
|
{% endfor %}
|
||||||
|
{% for name in native_services %}
|
||||||
|
<service android:name="{{ name }}" />
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% if args.billing_pubkey %}
|
||||||
|
<service android:name="org.kivy.android.billing.BillingReceiver"
|
||||||
|
android:process=":pythonbilling" />
|
||||||
|
<receiver android:name="org.kivy.android.billing.BillingReceiver"
|
||||||
|
android:process=":pythonbillingreceiver"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<action android:name="com.android.vending.billing.IN_APP_NOTIFY" />
|
||||||
|
<action android:name="com.android.vending.billing.RESPONSE_CODE" />
|
||||||
|
<action android:name="com.android.vending.billing.PURCHASE_STATE_CHANGED" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
|
{% endif %}
|
||||||
|
{% for a in args.add_activity %}
|
||||||
|
<activity android:name="{{ a }}"></activity>
|
||||||
|
{% endfor %}
|
||||||
|
</application>
|
||||||
|
|
||||||
|
</manifest>
|
314
sbapp/patches/HIDDeviceUSB.java
Normal file
314
sbapp/patches/HIDDeviceUSB.java
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
// Patched HID device handling in relation to:
|
||||||
|
// https://github.com/libsdl-org/SDL/issues/3850
|
||||||
|
|
||||||
|
package org.libsdl.app;
|
||||||
|
|
||||||
|
import android.hardware.usb.*;
|
||||||
|
import android.os.Build;
|
||||||
|
import android.util.Log;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
class HIDDeviceUSB implements HIDDevice {
|
||||||
|
|
||||||
|
private static final String TAG = "hidapi";
|
||||||
|
|
||||||
|
protected HIDDeviceManager mManager;
|
||||||
|
protected UsbDevice mDevice;
|
||||||
|
protected int mInterface;
|
||||||
|
protected int mDeviceId;
|
||||||
|
protected UsbDeviceConnection mConnection;
|
||||||
|
protected UsbEndpoint mInputEndpoint;
|
||||||
|
protected UsbEndpoint mOutputEndpoint;
|
||||||
|
protected InputThread mInputThread;
|
||||||
|
protected boolean mRunning;
|
||||||
|
protected boolean mFrozen;
|
||||||
|
|
||||||
|
public HIDDeviceUSB(HIDDeviceManager manager, UsbDevice usbDevice, int interface_number) {
|
||||||
|
mManager = manager;
|
||||||
|
mDevice = usbDevice;
|
||||||
|
mInterface = interface_number;
|
||||||
|
mDeviceId = manager.getDeviceIDForIdentifier(getIdentifier());
|
||||||
|
mRunning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdentifier() {
|
||||||
|
return String.format("%s/%x/%x", mDevice.getDeviceName(), mDevice.getVendorId(), mDevice.getProductId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getId() {
|
||||||
|
return mDeviceId;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVendorId() {
|
||||||
|
return mDevice.getVendorId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getProductId() {
|
||||||
|
return mDevice.getProductId();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getSerialNumber() {
|
||||||
|
String result = null;
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
try {
|
||||||
|
result = mDevice.getSerialNumber();
|
||||||
|
} catch (SecurityException e) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
result = "";
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getVersion() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getManufacturerName() {
|
||||||
|
String result = null;
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
result = mDevice.getManufacturerName();
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
result = String.format("%x", getVendorId());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getProductName() {
|
||||||
|
String result = null;
|
||||||
|
if (Build.VERSION.SDK_INT >= 21) {
|
||||||
|
result = mDevice.getProductName();
|
||||||
|
}
|
||||||
|
if (result == null) {
|
||||||
|
result = String.format("%x", getProductId());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UsbDevice getDevice() {
|
||||||
|
return mDevice;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDeviceName() {
|
||||||
|
return getManufacturerName() + " " + getProductName() + "(0x" + String.format("%x", getVendorId()) + "/0x" + String.format("%x", getProductId()) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean open() {
|
||||||
|
mConnection = mManager.getUSBManager().openDevice(mDevice);
|
||||||
|
if (mConnection == null) {
|
||||||
|
Log.w(TAG, "Unable to open USB device " + getDeviceName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force claim all interfaces
|
||||||
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||||
|
UsbInterface iface = mDevice.getInterface(i);
|
||||||
|
|
||||||
|
if (!mConnection.claimInterface(iface, true)) {
|
||||||
|
Log.w(TAG, "Failed to claim interfaces on USB device " + getDeviceName());
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the endpoints
|
||||||
|
UsbInterface iface = mDevice.getInterface(mInterface);
|
||||||
|
for (int j = 0; j < iface.getEndpointCount(); j++) {
|
||||||
|
UsbEndpoint endpt = iface.getEndpoint(j);
|
||||||
|
switch (endpt.getDirection()) {
|
||||||
|
case UsbConstants.USB_DIR_IN:
|
||||||
|
if (mInputEndpoint == null) {
|
||||||
|
mInputEndpoint = endpt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case UsbConstants.USB_DIR_OUT:
|
||||||
|
if (mOutputEndpoint == null) {
|
||||||
|
mOutputEndpoint = endpt;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure the required endpoints were present
|
||||||
|
if (mInputEndpoint == null || mOutputEndpoint == null) {
|
||||||
|
Log.w(TAG, "Missing required endpoint on USB device " + getDeviceName());
|
||||||
|
close();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start listening for input
|
||||||
|
mRunning = true;
|
||||||
|
mInputThread = new InputThread();
|
||||||
|
mInputThread.start();
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int sendFeatureReport(byte[] report) {
|
||||||
|
int res = -1;
|
||||||
|
int offset = 0;
|
||||||
|
int length = report.length;
|
||||||
|
boolean skipped_report_id = false;
|
||||||
|
byte report_number = report[0];
|
||||||
|
|
||||||
|
if (report_number == 0x0) {
|
||||||
|
++offset;
|
||||||
|
--length;
|
||||||
|
skipped_report_id = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mConnection.controlTransfer(
|
||||||
|
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_OUT,
|
||||||
|
0x09/*HID set_report*/,
|
||||||
|
(3/*HID feature*/ << 8) | report_number,
|
||||||
|
0,
|
||||||
|
report, offset, length,
|
||||||
|
1000/*timeout millis*/);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
Log.w(TAG, "sendFeatureReport() returned " + res + " on device " + getDeviceName());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipped_report_id) {
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int sendOutputReport(byte[] report) {
|
||||||
|
int r = mConnection.bulkTransfer(mOutputEndpoint, report, report.length, 1000);
|
||||||
|
if (r != report.length) {
|
||||||
|
Log.w(TAG, "sendOutputReport() returned " + r + " on device " + getDeviceName());
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean getFeatureReport(byte[] report) {
|
||||||
|
int res = -1;
|
||||||
|
int offset = 0;
|
||||||
|
int length = report.length;
|
||||||
|
boolean skipped_report_id = false;
|
||||||
|
byte report_number = report[0];
|
||||||
|
|
||||||
|
if (report_number == 0x0) {
|
||||||
|
/* Offset the return buffer by 1, so that the report ID
|
||||||
|
will remain in byte 0. */
|
||||||
|
++offset;
|
||||||
|
--length;
|
||||||
|
skipped_report_id = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = mConnection.controlTransfer(
|
||||||
|
UsbConstants.USB_TYPE_CLASS | 0x01 /*RECIPIENT_INTERFACE*/ | UsbConstants.USB_DIR_IN,
|
||||||
|
0x01/*HID get_report*/,
|
||||||
|
(3/*HID feature*/ << 8) | report_number,
|
||||||
|
0,
|
||||||
|
report, offset, length,
|
||||||
|
1000/*timeout millis*/);
|
||||||
|
|
||||||
|
if (res < 0) {
|
||||||
|
Log.w(TAG, "getFeatureReport() returned " + res + " on device " + getDeviceName());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipped_report_id) {
|
||||||
|
++res;
|
||||||
|
++length;
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data;
|
||||||
|
if (res == length) {
|
||||||
|
data = report;
|
||||||
|
} else {
|
||||||
|
data = Arrays.copyOfRange(report, 0, res);
|
||||||
|
}
|
||||||
|
mManager.HIDDeviceFeatureReport(mDeviceId, data);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() {
|
||||||
|
mRunning = false;
|
||||||
|
if (mInputThread != null) {
|
||||||
|
while (mInputThread.isAlive()) {
|
||||||
|
mInputThread.interrupt();
|
||||||
|
try {
|
||||||
|
mInputThread.join();
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// Keep trying until we're done
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mInputThread = null;
|
||||||
|
}
|
||||||
|
if (mConnection != null) {
|
||||||
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||||
|
UsbInterface iface = mDevice.getInterface(i);
|
||||||
|
mConnection.releaseInterface(iface);
|
||||||
|
}
|
||||||
|
mConnection.close();
|
||||||
|
mConnection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void shutdown() {
|
||||||
|
close();
|
||||||
|
mManager = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setFrozen(boolean frozen) {
|
||||||
|
mFrozen = frozen;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected class InputThread extends Thread {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
int packetSize = mInputEndpoint.getMaxPacketSize();
|
||||||
|
byte[] packet = new byte[packetSize];
|
||||||
|
while (mRunning) {
|
||||||
|
int r;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
r = mConnection.bulkTransfer(mInputEndpoint, packet, packetSize, 1000);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
Log.v(TAG, "Exception in UsbDeviceConnection bulktransfer: " + e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r < 0) {
|
||||||
|
// Could be a timeout or an I/O error
|
||||||
|
}
|
||||||
|
if (r > 0) {
|
||||||
|
byte[] data;
|
||||||
|
if (r == packetSize) {
|
||||||
|
data = packet;
|
||||||
|
} else {
|
||||||
|
data = Arrays.copyOfRange(packet, 0, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mFrozen) {
|
||||||
|
mManager.HIDDeviceInputReport(mDeviceId, data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
39
sbapp/patches/device_filter.xml
Normal file
39
sbapp/patches/device_filter.xml
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
|
||||||
|
<resources>
|
||||||
|
<!-- 0x0403 / 0x60??: FTDI -->
|
||||||
|
<usb-device vendor-id="1027" product-id="24577" /> <!-- 0x6001: FT232R -->
|
||||||
|
<usb-device vendor-id="1027" product-id="24592" /> <!-- 0x6010: FT2232H -->
|
||||||
|
<usb-device vendor-id="1027" product-id="24593" /> <!-- 0x6011: FT4232H -->
|
||||||
|
<usb-device vendor-id="1027" product-id="24596" /> <!-- 0x6014: FT232H -->
|
||||||
|
<usb-device vendor-id="1027" product-id="24597" /> <!-- 0x6015: FT230X, FT231X, FT234XD -->
|
||||||
|
|
||||||
|
<!-- 0x10C4 / 0xEA??: Silabs CP210x -->
|
||||||
|
<usb-device vendor-id="4292" product-id="60000" /> <!-- 0xea60: CP2102 and other CP210x single port devices -->
|
||||||
|
<usb-device vendor-id="4292" product-id="60016" /> <!-- 0xea70: CP2105 -->
|
||||||
|
<usb-device vendor-id="4292" product-id="60017" /> <!-- 0xea71: CP2108 -->
|
||||||
|
|
||||||
|
<!-- 0x067B / 0x23?3: Prolific PL2303x -->
|
||||||
|
<usb-device vendor-id="1659" product-id="8963" /> <!-- 0x2303: PL2303HX, HXD, TA, ... -->
|
||||||
|
<usb-device vendor-id="1659" product-id="9123" /> <!-- 0x23a3: PL2303GC -->
|
||||||
|
<usb-device vendor-id="1659" product-id="9139" /> <!-- 0x23b3: PL2303GB -->
|
||||||
|
<usb-device vendor-id="1659" product-id="9155" /> <!-- 0x23c3: PL2303GT -->
|
||||||
|
<usb-device vendor-id="1659" product-id="9171" /> <!-- 0x23d3: PL2303GL -->
|
||||||
|
<usb-device vendor-id="1659" product-id="9187" /> <!-- 0x23e3: PL2303GE -->
|
||||||
|
<usb-device vendor-id="1659" product-id="9203" /> <!-- 0x23f3: PL2303GS -->
|
||||||
|
|
||||||
|
<!-- 0x1a86 / 0x?523: Qinheng CH34x -->
|
||||||
|
<usb-device vendor-id="6790" product-id="21795" /> <!-- 0x5523: CH341A -->
|
||||||
|
<usb-device vendor-id="6790" product-id="29987" /> <!-- 0x7523: CH340 -->
|
||||||
|
|
||||||
|
<!-- CDC driver -->
|
||||||
|
<usb-device vendor-id="9025" /> <!-- 0x2341 / ......: Arduino -->
|
||||||
|
<usb-device vendor-id="5824" product-id="1155" /> <!-- 0x16C0 / 0x0483: Teensyduino -->
|
||||||
|
<usb-device vendor-id="1003" product-id="8260" /> <!-- 0x03EB / 0x2044: Atmel Lufa -->
|
||||||
|
<usb-device vendor-id="7855" product-id="4" /> <!-- 0x1eaf / 0x0004: Leaflabs Maple -->
|
||||||
|
<usb-device vendor-id="3368" product-id="516" /> <!-- 0x0d28 / 0x0204: ARM mbed -->
|
||||||
|
<usb-device vendor-id="1155" product-id="22336" /><!-- 0x0483 / 0x5740: ST CDC -->
|
||||||
|
<usb-device vendor-id="11914" product-id="5" /> <!-- 0x2E8A / 0x0005: Raspberry Pi Pico Micropython -->
|
||||||
|
<usb-device vendor-id="11914" product-id="10" /> <!-- 0x2E8A / 0x000A: Raspberry Pi Pico SDK -->
|
||||||
|
<usb-device vendor-id="6790" product-id="21972" /><!-- 0x1A86 / 0x55D4: Qinheng CH9102F -->
|
||||||
|
</resources>
|
6
sbapp/patches/intent-filter.xml
Normal file
6
sbapp/patches/intent-filter.xml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<intent-filter>
|
||||||
|
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
|
||||||
|
</intent-filter>
|
||||||
|
|
||||||
|
<meta-data android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||||
|
android:resource="@xml/device_filter" />
|
14
sbapp/services/sidebandservice.py
Normal file
14
sbapp/services/sidebandservice.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
class sidebandservice():
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
print("Sideband Service created")
|
||||||
|
self.run()
|
||||||
|
|
||||||
|
def run(self):
|
||||||
|
while True:
|
||||||
|
print("Service ping")
|
||||||
|
time.sleep(3)
|
||||||
|
|
||||||
|
sbs = sidebandservice()
|
Loading…
Reference in New Issue
Block a user