Backend abstraction + added android support + partial high DPI scaling + added missing files

This commit is contained in:
AlexandreRouma
2022-02-13 17:25:43 +01:00
parent e5f3d1672c
commit e9cb7fda42
17 changed files with 1367 additions and 0 deletions

64
android/app/build.gradle Normal file
View File

@ -0,0 +1,64 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
android {
compileSdkVersion 28
buildToolsVersion "30.0.3"
ndkVersion "23.0.7599858"
defaultConfig {
applicationId "org.sdrpp.sdrpp"
minSdkVersion 28
targetSdkVersion 28
versionCode 1
versionName "1.1.0"
externalNativeBuild {
cmake {
arguments "-DOPT_BACKEND_GLFW=OFF", "-DOPT_BACKEND_ANDROID=ON", "-DOPT_BUILD_SOAPY_SOURCE=OFF", "-DOPT_BUILD_ANDROID_AUDIO_SINK=ON", "-DOPT_BUILD_AUDIO_SINK=OFF", "-DOPT_BUILD_DISCORD_PRESENCE=OFF", "-DUSE_INTERNAL_LIBCORRECT=OFF"
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt')
}
}
externalNativeBuild {
cmake {
version "3.18.1"
path "../../CMakeLists.txt"
}
}
sourceSets {
main {
assets.srcDirs += ['assets']
}
}
}
task deleteTempAssets (type: Delete) {
delete 'assets'
}
task copyResources(type: Copy) {
description = 'Copy resources...'
from '../../root/'
into 'assets/'
include('**/*')
}
repositories {
mavenCentral()
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.0.2'
}
copyResources.dependsOn deleteTempAssets
preBuild.dependsOn copyResources

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.sdrpp.sdrpp">
<application
android:label="SDR++"
android:allowBackup="false"
android:fullBackupContent="false"
android:hasCode="true">
<activity
android:name="org.sdrpp.sdrpp.MainActivity"
android:icon="@mipmap/ic_launcher"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:configChanges="orientation|keyboardHidden|screenSize">
<meta-data android:name="android.app.lib_name" android:value="sdrpp_core" />
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<!-- <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" /> -->
</activity>
</application>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View File

@ -0,0 +1,32 @@
package org.sdrpp.sdrpp;
import android.app.NativeActivity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.hardware.usb.*;
import android.Manifest;
import android.os.Bundle;
import android.view.View;
import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager;
import android.util.Log;
import android.content.res.AssetManager;
import androidx.core.app.ActivityCompat;
import androidx.core.content.PermissionChecker;
import java.util.concurrent.LinkedBlockingQueue;
import java.io.*;
class DeviceManager {
public fun init() {
}
}

View File

@ -0,0 +1,192 @@
package org.sdrpp.sdrpp;
import android.app.NativeActivity;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.pm.PackageManager;
import android.hardware.usb.*;
import android.Manifest;
import android.os.Bundle;
import android.view.View;
import android.view.KeyEvent;
import android.view.inputmethod.InputMethodManager;
import android.util.Log;
import android.content.res.AssetManager;
import androidx.core.app.ActivityCompat;
import androidx.core.content.PermissionChecker;
import java.util.concurrent.LinkedBlockingQueue;
import java.io.*;
private const val ACTION_USB_PERMISSION = "org.sdrpp.sdrpp.USB_PERMISSION";
private val usbReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (ACTION_USB_PERMISSION == intent.action) {
synchronized(this) {
var _this = context as MainActivity;
_this.SDR_device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE)
if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
_this.SDR_conn = _this.usbManager!!.openDevice(_this.SDR_device);
// Save SDR info
_this.SDR_VID = _this.SDR_device!!.getVendorId();
_this.SDR_PID = _this.SDR_device!!.getProductId()
_this.SDR_FD = _this.SDR_conn!!.getFileDescriptor();
}
// Whatever the hell this does
context.unregisterReceiver(this);
// Hide again the system bars
_this.hideSystemBars();
}
}
}
}
class MainActivity : NativeActivity() {
private val TAG : String = "SDR++";
public var usbManager : UsbManager? = null;
public var SDR_device : UsbDevice? = null;
public var SDR_conn : UsbDeviceConnection? = null;
public var SDR_VID : Int = -1;
public var SDR_PID : Int = -1;
public var SDR_FD : Int = -1;
fun checkAndAsk(permission: String) {
if (PermissionChecker.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, arrayOf(permission), 1);
}
}
public fun hideSystemBars() {
val decorView = getWindow().getDecorView();
val uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
decorView.setSystemUiVisibility(uiOptions);
}
public override fun onCreate(savedInstanceState: Bundle?) {
// Hide bars
hideSystemBars();
// Ask for required permissions, without these the app cannot run.
checkAndAsk(Manifest.permission.WRITE_EXTERNAL_STORAGE);
checkAndAsk(Manifest.permission.READ_EXTERNAL_STORAGE);
// TODO: Have the main code wait until these two permissions are available
// Register events
usbManager = getSystemService(Context.USB_SERVICE) as UsbManager;
val permissionIntent = PendingIntent.getBroadcast(this, 0, Intent(ACTION_USB_PERMISSION), 0)
val filter = IntentFilter(ACTION_USB_PERMISSION)
registerReceiver(usbReceiver, filter)
// Get permission for all USB devices
val devList = usbManager!!.getDeviceList();
for ((name, dev) in devList) {
usbManager!!.requestPermission(dev, permissionIntent);
}
// Ask for internet permission
checkAndAsk(Manifest.permission.INTERNET);
super.onCreate(savedInstanceState)
}
public override fun onResume() {
// Hide bars again
hideSystemBars();
super.onResume();
}
fun showSoftInput() {
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
inputMethodManager.showSoftInput(window.decorView, 0);
}
fun hideSoftInput() {
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager;
inputMethodManager.hideSoftInputFromWindow(window.decorView.windowToken, 0);
hideSystemBars();
}
// Queue for the Unicode characters to be polled from native code (via pollUnicodeChar())
private var unicodeCharacterQueue: LinkedBlockingQueue<Int> = LinkedBlockingQueue()
// We assume dispatchKeyEvent() of the NativeActivity is actually called for every
// KeyEvent and not consumed by any View before it reaches here
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
if (event.action == KeyEvent.ACTION_DOWN) {
unicodeCharacterQueue.offer(event.getUnicodeChar(event.metaState))
}
return super.dispatchKeyEvent(event)
}
fun pollUnicodeChar(): Int {
return unicodeCharacterQueue.poll() ?: 0
}
public fun createIfDoesntExist(path: String) {
// This is a directory, create it in the filesystem
var folder = File(path);
var success = true;
if (!folder.exists()) {
success = folder.mkdirs();
}
if (!success) {
Log.e(TAG, "Could not create folder with path " + path);
}
}
public fun extractDir(aman: AssetManager, local: String, rsrc: String): Int {
val flist = aman.list(rsrc);
var ecount = 0;
for (fp in flist) {
val lpath = local + "/" + fp;
val rpath = rsrc + "/" + fp;
Log.w(TAG, "Extracting '" + rpath + "' to '" + lpath + "'");
// Create local path if non-existent
createIfDoesntExist(local);
// Create if directory
val ext = extractDir(aman, lpath, rpath);
// Extract if file
if (ext == 0) {
// This is a file, extract it
val _os = FileOutputStream(lpath);
val _is = aman.open(rpath);
val ilen = _is.available();
var fbuf = ByteArray(ilen);
_is.read(fbuf, 0, ilen);
_os.write(fbuf);
_os.close();
_is.close();
}
ecount++;
}
return ecount;
}
public fun getAppDir(): String {
val fdir = getFilesDir().getAbsolutePath();
// Extract all resources to the app directory
val aman = getAssets();
extractDir(aman, fdir + "/res", "res");
createIfDoesntExist(fdir + "/modules");
return fdir;
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@ -0,0 +1,53 @@
<resources>
<!-- RTL-SDR -->
<usb-device vendor-id="0x0bda" product-id="0x2832" />
<usb-device vendor-id="0x0bda" product-id="0x2838" />
<usb-device vendor-id="0x0413" product-id="0x6680" />
<usb-device vendor-id="0x0413" product-id="0x6f0f" />
<usb-device vendor-id="0x0458" product-id="0x707f" />
<usb-device vendor-id="0x0ccd" product-id="0x00a9" />
<usb-device vendor-id="0x0ccd" product-id="0x00b3" />
<usb-device vendor-id="0x0ccd" product-id="0x00b4" />
<usb-device vendor-id="0x0ccd" product-id="0x00b5" />
<usb-device vendor-id="0x0ccd" product-id="0x00b7" />
<usb-device vendor-id="0x0ccd" product-id="0x00b8" />
<usb-device vendor-id="0x0ccd" product-id="0x00b9" />
<usb-device vendor-id="0x0ccd" product-id="0x00c0" />
<usb-device vendor-id="0x0ccd" product-id="0x00c6" />
<usb-device vendor-id="0x0ccd" product-id="0x00d3" />
<usb-device vendor-id="0x0ccd" product-id="0x00d7" />
<usb-device vendor-id="0x0ccd" product-id="0x00e0" />
<usb-device vendor-id="0x1554" product-id="0x5020" />
<usb-device vendor-id="0x15f4" product-id="0x0131" />
<usb-device vendor-id="0x15f4" product-id="0x0133" />
<usb-device vendor-id="0x185b" product-id="0x0620" />
<usb-device vendor-id="0x185b" product-id="0x0650" />
<usb-device vendor-id="0x185b" product-id="0x0680" />
<usb-device vendor-id="0x1b80" product-id="0xd393" />
<usb-device vendor-id="0x1b80" product-id="0xd394" />
<usb-device vendor-id="0x1b80" product-id="0xd395" />
<usb-device vendor-id="0x1b80" product-id="0xd397" />
<usb-device vendor-id="0x1b80" product-id="0xd398" />
<usb-device vendor-id="0x1b80" product-id="0xd39d" />
<usb-device vendor-id="0x1b80" product-id="0xd3a4" />
<usb-device vendor-id="0x1b80" product-id="0xd3a8" />
<usb-device vendor-id="0x1b80" product-id="0xd3af" />
<usb-device vendor-id="0x1b80" product-id="0xd3b0" />
<usb-device vendor-id="0x1d19" product-id="0x1101" />
<usb-device vendor-id="0x1d19" product-id="0x1102" />
<usb-device vendor-id="0x1d19" product-id="0x1103" />
<usb-device vendor-id="0x1d19" product-id="0x1104" />
<usb-device vendor-id="0x1f4d" product-id="0xa803" />
<usb-device vendor-id="0x1f4d" product-id="0xb803" />
<usb-device vendor-id="0x1f4d" product-id="0xc803" />
<usb-device vendor-id="0x1f4d" product-id="0xd286" />
<usb-device vendor-id="0x1f4d" product-id="0xd803" />
<!-- Airspy One -->
<usb-device vendor-id="0x1d50" product-id="0x60a1" />
<!-- Airspy HF+ -->
<usb-device vendor-id="0x03EB" product-id="0x800C" />
</resources>