mirror of
https://github.com/AlexandreRouma/SDRPlusPlus.git
synced 2025-06-25 12:07:49 +02:00
Backend abstraction + added android support + partial high DPI scaling + added missing files
This commit is contained in:
64
android/app/build.gradle
Normal file
64
android/app/build.gradle
Normal 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
|
34
android/app/src/main/AndroidManifest.xml
Normal file
34
android/app/src/main/AndroidManifest.xml
Normal 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>
|
32
android/app/src/main/java/DeviceManager.kt
Normal file
32
android/app/src/main/java/DeviceManager.kt
Normal 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() {
|
||||
|
||||
}
|
||||
}
|
192
android/app/src/main/java/MainActivity.kt
Normal file
192
android/app/src/main/java/MainActivity.kt
Normal 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;
|
||||
}
|
||||
}
|
BIN
android/app/src/main/res/mipmap/ic_launcher.png
Normal file
BIN
android/app/src/main/res/mipmap/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
53
android/app/src/main/res/xml/device_filter.xml
Normal file
53
android/app/src/main/res/xml/device_filter.xml
Normal 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>
|
Reference in New Issue
Block a user