SDRPlusPlus/android/app/src/main/java/MainActivity.kt

193 wiersze
6.6 KiB
Kotlin

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;
}
}