Merge branch 'master' into mapsforge
|
@ -13,6 +13,7 @@
|
|||
<uses-feature android:name="android.hardware.location.gps" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.microphone" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
|
||||
<uses-library android:name="android.test.runner" android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
|
@ -35,6 +36,12 @@
|
|||
<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>
|
||||
<activity android:name=".LogActivity" android:label="@string/app_name"
|
||||
android:launchMode="singleTop"
|
||||
|
|
117
build.xml
|
@ -4,7 +4,7 @@
|
|||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<loadproperties srcFile="local.properties" />
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
|
@ -28,6 +28,15 @@
|
|||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
|
@ -41,49 +50,23 @@
|
|||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project'"
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
|
||||
<!-- extension targets. Uncomment the ones where you want to do custom work
|
||||
in between standard targets -->
|
||||
<property name="mapviewxml" value="res/layout/mapview.xml" />
|
||||
<target name="-pre-build">
|
||||
<fail unless="mapsApiKey">You need to add mapsApiKey=... to local.properties</fail>
|
||||
<copy file="mapview.xml.tpl" tofile="${mapviewxml}" overwrite="true">
|
||||
<filterchain>
|
||||
<replacetokens>
|
||||
<token key="apiKey" value="${mapsApiKey}"/>
|
||||
</replacetokens>
|
||||
</filterchain>
|
||||
|
||||
</copy>
|
||||
<tstamp>
|
||||
<format property="build.date" pattern="yyyy-MM-dd" />
|
||||
</tstamp>
|
||||
<exec executable="git" outputproperty="git.revision">
|
||||
<arg line="describe --tags --dirty=+"/>
|
||||
</exec>
|
||||
<copy file="version.xml.tpl" tofile="${resource.absolute.dir}/values/version.xml" overwrite="true">
|
||||
<filterchain>
|
||||
<replacetokens>
|
||||
<token key="build_version" value="${ant.project.name} ${git.revision} ${build.date}"/>
|
||||
</replacetokens>
|
||||
</filterchain>
|
||||
|
||||
</copy>
|
||||
</target>
|
||||
<!--
|
||||
<target name="-pre-compile">
|
||||
</target>
|
||||
|
||||
/* This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir} */
|
||||
-->
|
||||
<target name="-post-compile" depends="scalac, proguard">
|
||||
</target>
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
|
@ -103,57 +86,7 @@
|
|||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: custom -->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
<target name="check-scalalib">
|
||||
<available file="tools/scala-library.jar" property="have.scalalib"/>
|
||||
<fail unless="have.scalalib">You have to place scala-compiler.jar and scala-library.jar to tools/</fail>
|
||||
</target>
|
||||
<target name="check-scalac">
|
||||
<available file="tools/scala-compiler.jar" property="have.scalac"/>
|
||||
<fail unless="have.scalac">You have to place scala-compiler.jar and scala-library.jar to tools/</fail>
|
||||
</target>
|
||||
|
||||
<target name="scalac" depends="-compile, check-scalalib, check-scalac">
|
||||
<taskdef resource="scala/tools/ant/antlib.xml"
|
||||
classpath="tools/scala-compiler.jar:tools/scala-library.jar:tools/scala-reflect.jar" />
|
||||
<scalac force="changed" deprecation="on"
|
||||
srcdir="${source.absolute.dir}" includes="**/*.scala"
|
||||
bootclasspathref="project.target.class.path"
|
||||
destdir="${out.classes.absolute.dir}">
|
||||
<classpath>
|
||||
<pathelement location="${out.classes.absolute.dir}"/>
|
||||
<fileset dir="tools" includes="*.jar"/>
|
||||
<fileset dir="${jar.libs.dir}" includes="*.jar"/>
|
||||
</classpath>
|
||||
</scalac>
|
||||
</target>
|
||||
|
||||
<target name="check-proguard">
|
||||
<available file="tools/proguard.jar" property="have.proguard"/>
|
||||
<fail unless="have.proguard">ProGuard is required to build! Copy proguard.jar to tools/</fail>
|
||||
</target>
|
||||
|
||||
<property name="optimized.dir" value="${out.absolute.dir}/optimized" />
|
||||
<target name="proguard" depends="scalac, check-proguard">
|
||||
<taskdef resource="proguard/ant/task.properties"
|
||||
classpath="tools/proguard.jar" />
|
||||
<mkdir dir="${optimized.dir}" />
|
||||
<proguard configuration="proguard.cfg">
|
||||
-injars ${out.classes.absolute.dir}:${jar.libs.dir}:tools/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)
|
||||
-outjars ${out.absolute.dir}/classes.min.jar
|
||||
-libraryjars ${toString:project.target.class.path}
|
||||
-printusage ${optimized.dir}/proguard.usage
|
||||
</proguard>
|
||||
</target>
|
||||
|
||||
<target name="-dex" depends="-post-compile">
|
||||
<echo>Converting compiled files and external libraries into ${intermediate.dex.file}...</echo>
|
||||
<apply executable="${dx}" failonerror="true" parallel="true">
|
||||
<arg value="--dex" />
|
||||
<arg value="--output=${intermediate.dex.file}" />
|
||||
<fileset dir="${out.absolute.dir}" includes="*.min.jar"/>
|
||||
</apply>
|
||||
</target>
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project>
|
||||
|
||||
<property name="mapviewxml" value="res/layout/mapview.xml" />
|
||||
|
||||
<target name="-pre-build">
|
||||
<fail unless="mapsApiKey">You need to add mapsApiKey=... to local.properties</fail>
|
||||
<copy file="mapview.xml.tpl" tofile="${mapviewxml}" overwrite="true">
|
||||
<filterchain>
|
||||
<replacetokens>
|
||||
<token key="apiKey" value="${mapsApiKey}"/>
|
||||
</replacetokens>
|
||||
</filterchain>
|
||||
|
||||
</copy>
|
||||
<tstamp>
|
||||
<format property="build.date" pattern="yyyy-MM-dd" />
|
||||
</tstamp>
|
||||
<exec executable="git" outputproperty="git.revision">
|
||||
<arg line="describe --tags --dirty=+"/>
|
||||
</exec>
|
||||
<copy file="version.xml.tpl" tofile="${resource.absolute.dir}/values/version.xml" overwrite="true">
|
||||
<filterchain>
|
||||
<replacetokens>
|
||||
<token key="build_version" value="${ant.project.name} ${git.revision} ${build.date}"/>
|
||||
</replacetokens>
|
||||
</filterchain>
|
||||
|
||||
</copy>
|
||||
</target>
|
||||
|
||||
<target name="check-scalalib">
|
||||
<available file="tools/scala-library.jar" property="have.scalalib"/>
|
||||
<fail unless="have.scalalib">You have to place scala-compiler.jar and scala-library.jar to tools/</fail>
|
||||
</target>
|
||||
<target name="check-scalac">
|
||||
<available file="tools/scala-compiler.jar" property="have.scalac"/>
|
||||
<fail unless="have.scalac">You have to place scala-compiler.jar and scala-library.jar to tools/</fail>
|
||||
</target>
|
||||
|
||||
<target name="scalac" depends="-compile, check-scalalib, check-scalac">
|
||||
<taskdef resource="scala/tools/ant/antlib.xml"
|
||||
classpath="tools/scala-compiler.jar:tools/scala-library.jar:tools/scala-reflect.jar" />
|
||||
<scalac force="changed" deprecation="on"
|
||||
srcdir="${source.absolute.dir}" includes="**/*.scala"
|
||||
bootclasspathref="project.target.class.path"
|
||||
destdir="${out.classes.absolute.dir}">
|
||||
<classpath>
|
||||
<pathelement location="${out.classes.absolute.dir}"/>
|
||||
<fileset dir="tools" includes="*.jar"/>
|
||||
<fileset dir="${jar.libs.dir}" includes="*.jar"/>
|
||||
</classpath>
|
||||
</scalac>
|
||||
</target>
|
||||
|
||||
<!-- proguard is always enabled in APRSdroid -->
|
||||
<target name="-post-compile" depends="scalac, proguard" />
|
||||
|
||||
<target name="proguard" depends="scalac">
|
||||
<property name="proguard.jar" location="${android.tools.dir}/proguard/lib/proguard.jar" />
|
||||
<taskdef name="proguard" classname="proguard.ant.ProGuardTask" classpath="${proguard.jar}" />
|
||||
|
||||
<property name="obfuscate.absolute.dir" location="${out.absolute.dir}/proguard" />
|
||||
<property name="obfuscated.jar.file" value="${obfuscate.absolute.dir}/obfuscated.jar" />
|
||||
<property name="out.dex.input.absolute.dir" value="${obfuscated.jar.file}" />
|
||||
<mkdir dir="${obfuscate.absolute.dir}" />
|
||||
<proguard configuration="proguard.cfg">
|
||||
-injars ${out.classes.absolute.dir}:${jar.libs.dir}:tools/scala-library.jar(!META-INF/MANIFEST.MF,!library.properties)
|
||||
-outjars ${obfuscated.jar.file}
|
||||
-libraryjars ${toString:project.target.class.path}
|
||||
-dump "${obfuscate.absolute.dir}/dump.txt"
|
||||
-printseeds "${obfuscate.absolute.dir}/seeds.txt"
|
||||
-printusage "${obfuscate.absolute.dir}/usage.txt"
|
||||
-printmapping "${obfuscate.absolute.dir}/mapping.txt"
|
||||
</proguard>
|
||||
<path id="out.dex.jar.input.ref" />
|
||||
</target>
|
||||
<target name="-obfuscate" depends="proguard" />
|
||||
|
||||
</project>
|
|
@ -167,7 +167,7 @@ Start the APRSdroid tracking service for an indeterminate runtime
|
|||
(`SERVICE`) or for one position transmission (`ONCE`).
|
||||
|
||||
// launch APRSdroid tracker
|
||||
Intent i = new Intent("org.aprsdroid.app.SERVICE");
|
||||
Intent i = new Intent("org.aprsdroid.app.SERVICE").setPackage("org.aprsdroid.app");
|
||||
startService(i);
|
||||
|
||||
### SERVICE_STOP
|
||||
|
@ -175,7 +175,7 @@ Start the APRSdroid tracking service for an indeterminate runtime
|
|||
Stop the tracking service.
|
||||
|
||||
// stop APRSdroid tracker
|
||||
Intent i = new Intent("org.aprsdroid.app.SERVICE_STOP");
|
||||
Intent i = new Intent("org.aprsdroid.app.SERVICE_STOP").setPackage("org.aprsdroid.app");
|
||||
startService(i);
|
||||
|
||||
### SEND_PACKET
|
||||
|
@ -192,7 +192,7 @@ Intent extras:
|
|||
Example for sending a raw status packet:
|
||||
|
||||
// send raw status packet
|
||||
Intent i = new Intent("org.aprsdroid.app.SEND_PACKET");
|
||||
Intent i = new Intent("org.aprsdroid.app.SEND_PACKET").setPackage("org.aprsdroid.app");
|
||||
i.putExtra("data", ">third-party APRS status app");
|
||||
startService(i);
|
||||
|
||||
|
|
Po Szerokość: | Wysokość: | Rozmiar: 81 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 175 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 2.0 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 180 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 19 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 2.7 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 260 KiB |
Po Szerokość: | Wysokość: | Rozmiar: 30 KiB |
Przed Szerokość: | Wysokość: | Rozmiar: 9.7 KiB Po Szerokość: | Wysokość: | Rozmiar: 74 KiB |
|
@ -8,6 +8,7 @@
|
|||
<item>@string/p_conn_bt</item>
|
||||
<item>@string/p_conn_kwd</item>
|
||||
<item>@string/p_conn_tcptnc</item>
|
||||
<item>@string/p_conn_usb</item>
|
||||
</string-array>
|
||||
<string-array name="p_conntype_ev">
|
||||
<item>tcp</item>
|
||||
|
@ -17,6 +18,7 @@
|
|||
<item>bluetooth</item>
|
||||
<item>kenwood</item>
|
||||
<item>tcptnc</item>
|
||||
<item>usb</item>
|
||||
</string-array>
|
||||
<string-array name="p_afsk_out_ev">
|
||||
<item>0</item>
|
||||
|
@ -83,4 +85,12 @@
|
|||
<item>1440</item>
|
||||
<item>2880</item>
|
||||
</string-array>
|
||||
<string-array name="p_serial_baudrates">
|
||||
<item>4800</item>
|
||||
<item>9600</item>
|
||||
<item>19200</item>
|
||||
<item>38400</item>
|
||||
<item>57600</item>
|
||||
<item>115200</item>
|
||||
</string-array>
|
||||
</resources>
|
||||
|
|
|
@ -181,6 +181,7 @@
|
|||
<string name="p_conn_bt">Bluetooth TNC</string>
|
||||
<string name="p_conn_kwd">Kenwood GPS Port</string>
|
||||
<string name="p_conn_tcptnc">TCP/IP TNC</string>
|
||||
<string name="p_conn_usb">USB Serial</string>
|
||||
<!-- array of location sources -->
|
||||
<string name="p_source_manual">Manual Position</string>
|
||||
<string name="p_source_periodic">Periodic GPS/Network Position</string>
|
||||
|
@ -369,4 +370,8 @@
|
|||
<string name="ssl_import_error">Error importing certificate: %s!</string>
|
||||
<string name="ssl_expired">Your certificate has expired!</string>
|
||||
<string name="ssl_expire_in">Your certificate will expire in %d days!</string>
|
||||
|
||||
<!-- (USB) Serial TNC settings -->
|
||||
<string name="p_serial_baudrate">Baud Rate</string>
|
||||
<string name="p_serial_baudrate_summary">Data rate of the serial port</string>
|
||||
</resources>
|
||||
|
|
|
@ -32,8 +32,8 @@
|
|||
<de.duenndns.EditTextPreferenceWithValue
|
||||
android:key="afsk.prefix"
|
||||
android:inputType="number"
|
||||
android:defaultValue="1000"
|
||||
android:hint="1000"
|
||||
android:defaultValue="200"
|
||||
android:hint="200"
|
||||
android:title="@string/p_afsk_prefix"
|
||||
android:summary="@string/p_afsk_prefix_summary"
|
||||
android:dialogTitle="@string/p_afsk_prefix_entry" />
|
||||
|
|
|
@ -16,6 +16,13 @@ class APRSdroid extends Activity {
|
|||
override def onCreate(savedInstanceState : Bundle) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
|
||||
|
||||
// if this is a USB device, auto-launch the service
|
||||
if (getIntent.getParcelableExtra("device") != null) {
|
||||
prefs.edit().putString("backend", "usb").commit();
|
||||
startService(AprsService.intent(this, AprsService.SERVICE))
|
||||
}
|
||||
|
||||
prefs.getString("activity", "log") match {
|
||||
case "hub" => replaceAct(classOf[HubActivity])
|
||||
case "map" => replaceAct(classOf[MapAct])
|
||||
|
|
|
@ -202,12 +202,12 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
|
||||
def symbol2rect(symbol : String) : Rect = {
|
||||
val alt_offset = if (symbol(0) == '/') 0 else symbolSize*6
|
||||
val index = symbol(1) - 32
|
||||
val index = symbol(1) - 33
|
||||
// check for overflow
|
||||
if (index < 0 || index >= 6*16)
|
||||
return new Rect(0, 0, symbolSize, symbolSize)
|
||||
val x = (index / 16) * symbolSize + alt_offset
|
||||
val y = (index % 16) * symbolSize
|
||||
val y = (index / 16) * symbolSize + alt_offset
|
||||
val x = (index % 16) * symbolSize
|
||||
new Rect(x, y, x+symbolSize, y+symbolSize)
|
||||
}
|
||||
|
||||
|
@ -291,8 +291,8 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
c.drawBitmap(iconbitmap, srcRect, destRect, null)
|
||||
// and finally the bitmap overlay, if any
|
||||
if (zoom >= 6 && symbolIsOverlayed(s.symbol)) {
|
||||
c.drawText(s.symbol(0).toString(), p.x, p.y+ss/2, symbStrPaint)
|
||||
c.drawText(s.symbol(0).toString(), p.x, p.y+ss/2, symbPaint)
|
||||
c.drawText(s.symbol(0).toString(), p.x+1, p.y+ss/2+1, symbStrPaint)
|
||||
c.drawText(s.symbol(0).toString(), p.x+1, p.y+ss/2+1, symbPaint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
package org.aprsdroid.app
|
||||
|
||||
import _root_.android.content.{BroadcastReceiver, Context, Intent, IntentFilter}
|
||||
import _root_.android.graphics.drawable.{Drawable, BitmapDrawable}
|
||||
import _root_.android.graphics.{Canvas, Paint, Path, Point, Rect, Typeface}
|
||||
import _root_.android.graphics.drawable.Drawable
|
||||
import _root_.android.graphics.{Bitmap, BitmapFactory, Canvas, Matrix, Paint, Path, Point, Rect, Typeface}
|
||||
import _root_.android.util.AttributeSet
|
||||
import _root_.android.widget.ImageView
|
||||
|
||||
class SymbolView(context : Context, attrs : AttributeSet) extends ImageView(context, attrs) {
|
||||
|
||||
var symbol : String = "/$"
|
||||
val iconbitmap = UnscaledBitmapLoader.loadFromResource(context.getResources(),
|
||||
R.drawable.allicons, null)
|
||||
val symbolSize = 16
|
||||
lazy val iconbitmap = BitmapFactory.decodeResource(context.getResources(), R.drawable.allicons)
|
||||
lazy val symbolSize = (context.getResources().getDisplayMetrics().density * 16).toInt
|
||||
|
||||
|
||||
def setSymbol(new_sym : String) {
|
||||
symbol = new_sym
|
||||
|
@ -20,9 +20,9 @@ class SymbolView(context : Context, attrs : AttributeSet) extends ImageView(cont
|
|||
|
||||
def symbol2rect(symbol : String) : Rect = {
|
||||
val alt_offset = if (symbol(0) == '/') 0 else symbolSize*6
|
||||
val index = symbol(1) - 32
|
||||
val x = (index / 16) * symbolSize + alt_offset
|
||||
val y = (index % 16) * symbolSize
|
||||
val index = symbol(1) - 33
|
||||
val y = (index / 16) * symbolSize + alt_offset
|
||||
val x = (index % 16) * symbolSize
|
||||
new Rect(x, y, x+symbolSize, y+symbolSize)
|
||||
}
|
||||
|
||||
|
@ -57,8 +57,8 @@ class SymbolView(context : Context, attrs : AttributeSet) extends ImageView(cont
|
|||
if (symbolIsOverlayed(symbol)) {
|
||||
val x = getWidth()/2
|
||||
val y = getHeight()*3/4
|
||||
canvas.drawText(symbol(0).toString(), x, y, strokePaint)
|
||||
canvas.drawText(symbol(0).toString(), x, y, symbPaint)
|
||||
canvas.drawText(symbol(0).toString(), x+1, y+1, strokePaint)
|
||||
canvas.drawText(symbol(0).toString(), x+1, y+1, symbPaint)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,7 +14,7 @@ class AfskUploader(service : AprsService, prefs : PrefsWrapper) extends AprsBack
|
|||
with PacketHandler with PacketCallback {
|
||||
val TAG = "APRSdroid.Afsk"
|
||||
// frame prefix: bytes = milliseconds * baudrate / 8 / 1000
|
||||
var FrameLength = prefs.getStringInt("afsk.prefix", 1000)*1200/8/1000
|
||||
var FrameLength = prefs.getStringInt("afsk.prefix", 200)*1200/8/1000
|
||||
var Digis = prefs.getString("digi_path", "WIDE1-1")
|
||||
val use_hq = prefs.getAfskHQ()
|
||||
val use_bt = prefs.getAfskBluetooth()
|
||||
|
|
|
@ -57,6 +57,11 @@ object AprsBackend {
|
|||
(s, p) => new TcpTnc(s, p),
|
||||
R.xml.backend_tcptnc,
|
||||
CAN_DUPLEX,
|
||||
PASSCODE_NONE),
|
||||
"usb" -> new BackendInfo(
|
||||
(s, p) => new UsbTnc(s, p),
|
||||
R.xml.backend_usb,
|
||||
CAN_DUPLEX,
|
||||
PASSCODE_NONE)
|
||||
)
|
||||
|
||||
|
|
|
@ -106,6 +106,8 @@ class TcpUploader(service : AprsService, prefs : PrefsWrapper) extends AprsBacke
|
|||
service.getString(R.string.post_connecting, host, port.asInstanceOf[AnyRef]))
|
||||
|
||||
val socket = sc.getSocketFactory().createSocket(host, port).asInstanceOf[SSLSocket]
|
||||
// enable all available cipher suites, including NULL; fixes #71
|
||||
socket.setEnabledCipherSuites(sc.getSocketFactory().getDefaultCipherSuites())
|
||||
socket
|
||||
} catch {
|
||||
case e : java.io.FileNotFoundException =>
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
package org.aprsdroid.app
|
||||
|
||||
import android.app.PendingIntent
|
||||
import android.app.Service
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.IntentFilter
|
||||
import android.hardware.usb.UsbManager
|
||||
import android.hardware.usb.UsbDevice
|
||||
import android.hardware.usb.UsbDeviceConnection
|
||||
import android.util.Log
|
||||
import java.io.{InputStream, OutputStream}
|
||||
|
||||
import net.ab0oo.aprs.parser._
|
||||
|
||||
import com.felhr.usbserial._
|
||||
|
||||
class UsbTnc(service : AprsService, prefs : PrefsWrapper) extends AprsBackend(prefs) {
|
||||
val TAG = "APRSdroid.Usb"
|
||||
|
||||
val USB_PERM_ACTION = "org.aprsdroid.app.UsbTnc.PERM"
|
||||
val ACTION_USB_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED"
|
||||
val ACTION_USB_DETACHED = "android.hardware.usb.action.USB_DEVICE_DETACHED"
|
||||
|
||||
var digipath = prefs.getString("digi_path", "WIDE1-1")
|
||||
|
||||
val usbManager = service.getSystemService(Context.USB_SERVICE).asInstanceOf[UsbManager];
|
||||
var thread : UsbThread = null
|
||||
var dev : UsbDevice = null
|
||||
var con : UsbDeviceConnection = null
|
||||
var ser : UsbSerialInterface = null
|
||||
var alreadyRunning = false
|
||||
|
||||
val intent = new Intent(USB_PERM_ACTION)
|
||||
val pendingIntent = PendingIntent.getBroadcast(service, 0, intent, 0)
|
||||
|
||||
val receiver = new BroadcastReceiver() {
|
||||
override def onReceive(ctx : Context, i : Intent) {
|
||||
Log.d(TAG, "onReceive: " + i)
|
||||
if (i.getAction() == ACTION_USB_DETACHED) {
|
||||
log("USB device detached.")
|
||||
ctx.stopService(AprsService.intent(ctx, AprsService.SERVICE))
|
||||
return
|
||||
}
|
||||
val granted = i.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED)
|
||||
if (!granted) {
|
||||
service.postAbort("No permission for USB device!")
|
||||
return
|
||||
}
|
||||
log("Obtained USB permissions.")
|
||||
thread = new UsbThread()
|
||||
thread.start()
|
||||
}
|
||||
}
|
||||
|
||||
var proto : TncProto = null
|
||||
|
||||
def start() = {
|
||||
val filter = new IntentFilter(USB_PERM_ACTION)
|
||||
filter.addAction(ACTION_USB_DETACHED)
|
||||
service.registerReceiver(receiver, filter)
|
||||
alreadyRunning = true
|
||||
if (ser == null)
|
||||
requestPermissions()
|
||||
false
|
||||
}
|
||||
|
||||
def log(s : String) {
|
||||
Log.i(TAG, s)
|
||||
service.postAddPost(StorageDatabase.Post.TYPE_INFO, R.string.post_info, s)
|
||||
}
|
||||
|
||||
def requestPermissions() {
|
||||
Log.d(TAG, "UsbTnc.requestPermissions");
|
||||
val dl = usbManager.getDeviceList();
|
||||
var requested = false
|
||||
import scala.collection.JavaConversions._
|
||||
for ((name, dev) <- dl) {
|
||||
val deviceVID = dev.getVendorId()
|
||||
val devicePID = dev.getProductId()
|
||||
if (deviceVID != 0x1d6b || (devicePID != 0x0001 || devicePID != 0x0002 || devicePID != 0x0003)) {
|
||||
// this is not a USB Hub
|
||||
log("Found USB device %04x:%04x, requesting permissions.".format(deviceVID, devicePID))
|
||||
this.dev = dev
|
||||
usbManager.requestPermission(dev, pendingIntent)
|
||||
return
|
||||
}
|
||||
}
|
||||
service.postAbort("No USB device found!")
|
||||
}
|
||||
|
||||
def update(packet : APRSPacket) : String = {
|
||||
// the digipeater setting here is a duplicate just for log purpose
|
||||
packet.setDigipeaters(Digipeater.parseList(digipath, true))
|
||||
Log.d(TAG, "UsbTnc.update: " + packet)
|
||||
//TODO
|
||||
proto.writePacket(packet)
|
||||
"USB OK"
|
||||
}
|
||||
|
||||
def stop() {
|
||||
if (alreadyRunning)
|
||||
service.unregisterReceiver(receiver)
|
||||
alreadyRunning = false
|
||||
if (ser != null)
|
||||
ser.close()
|
||||
if (con != null)
|
||||
con.close()
|
||||
if (thread == null)
|
||||
return
|
||||
thread.synchronized {
|
||||
thread.running = false
|
||||
}
|
||||
//thread.shutdown()
|
||||
thread.interrupt()
|
||||
thread.join(50)
|
||||
}
|
||||
|
||||
class UsbThread()
|
||||
extends Thread("APRSdroid USB connection") {
|
||||
val TAG = "UsbThread"
|
||||
var running = true
|
||||
|
||||
def log(s : String) {
|
||||
Log.i(TAG, s)
|
||||
service.postAddPost(StorageDatabase.Post.TYPE_INFO, R.string.post_info, s)
|
||||
}
|
||||
|
||||
override def run() {
|
||||
val con = usbManager.openDevice(dev)
|
||||
val ser = UsbSerialDevice.createUsbSerialDevice(dev, con)
|
||||
if (ser == null || !ser.open()) {
|
||||
con.close()
|
||||
service.postAbort("Unsupported serial port")
|
||||
return
|
||||
}
|
||||
val baudrate = prefs.getStringInt("baudrate", 115200)
|
||||
ser.setBaudRate(baudrate)
|
||||
ser.setDataBits(UsbSerialInterface.DATA_BITS_8)
|
||||
ser.setStopBits(UsbSerialInterface.STOP_BITS_1)
|
||||
ser.setParity(UsbSerialInterface.PARITY_NONE)
|
||||
ser.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF)
|
||||
|
||||
log("Opened " + ser.getClass().getSimpleName() + " at " + baudrate + "bd")
|
||||
val os = new SerialOutputStream(ser)
|
||||
val initstring = prefs.getString("usb.init", null)
|
||||
val initdelay = prefs.getStringInt("usb.delay", 300)
|
||||
if (initstring != null && initstring != "") {
|
||||
log("Sending init: " + initstring)
|
||||
for (line <- initstring.split("\n")) {
|
||||
os.write(line.getBytes())
|
||||
os.write('\r')
|
||||
os.write('\n')
|
||||
Thread.sleep(initdelay)
|
||||
}
|
||||
}
|
||||
proto = new KissProto(new SerialInputStream(ser), os, digipath)
|
||||
service.postPosterStarted()
|
||||
while (running) {
|
||||
val line = proto.readPacket()
|
||||
Log.d(TAG, "recv: " + line)
|
||||
service.postSubmit(line)
|
||||
}
|
||||
Log.d(TAG, "terminate()")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|