kopia lustrzana https://github.com/ge0rg/aprsdroid
Porównaj commity
22 Commity
Autor | SHA1 | Data |
---|---|---|
Georg Lukas | d38a0dae39 | |
Georg Lukas | 7ede1c26fc | |
Georg Lukas | 73af9d1c5d | |
Georg Lukas | 4e2788e6b3 | |
Georg Lukas | 2ac1d3f1e6 | |
Georg Lukas | e3cb376195 | |
Georg Lukas | aee35ed3ed | |
Georg Lukas | b8ff35560e | |
Georg Lukas | 4c6a8a1b3f | |
Georg Lukas | 03e4a36d61 | |
Georg Lukas | 06fc910b9d | |
Georg Lukas | 70462b73d7 | |
Georg Lukas | 23833b55ef | |
Georg Lukas | 6751f24750 | |
Georg Lukas | 6607f3d027 | |
Georg Lukas | e669116795 | |
Georg Lukas | 08b4e7293e | |
Georg Lukas | 2ac0d739ae | |
Georg Lukas | 734498c6e0 | |
Georg Lukas | 5e7c8fc0e3 | |
Georg Lukas | 11d1e63299 | |
Georg Lukas | 106edf8b90 |
|
@ -11,13 +11,16 @@
|
|||
<uses-feature android:name="android.hardware.touchscreen" android:required="false" />
|
||||
<uses-feature android:name="android.hardware.usb.host" android:required="false" />
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
|
||||
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT" />
|
||||
<uses-permission android:name="android.permission.BROADCAST_STICKY" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
@ -27,6 +30,7 @@
|
|||
<application android:label="@string/app_name" android:icon="@drawable/icon"
|
||||
android:name=".APRSdroidApplication"
|
||||
android:usesCleartextTraffic="true"
|
||||
android:requestLegacyExternalStorage="true"
|
||||
android:allowBackup="true"
|
||||
android:theme="@style/DefaultTheme" >
|
||||
|
||||
|
@ -36,7 +40,8 @@
|
|||
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
|
||||
<activity android:name=".APRSdroid"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:label="@string/app_name">
|
||||
android:label="@string/app_name"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
@ -94,13 +99,16 @@
|
|||
android:launchMode="singleTop"
|
||||
android:parentActivityName=".HubActivity"
|
||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||
android:theme="@style/MapViewTheme" >
|
||||
android:theme="@style/MapViewTheme"
|
||||
android:exported="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".ProfileImportActivity" android:label="@string/profile_import_activity">
|
||||
<activity android:name=".ProfileImportActivity" android:label="@string/profile_import_activity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
@ -120,7 +128,8 @@
|
|||
android:pathPattern=".*\\.aprs" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity android:name=".KeyfileImportActivity" android:label="@string/ssl_import_activity">
|
||||
<activity android:name=".KeyfileImportActivity" android:label="@string/ssl_import_activity"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
@ -149,7 +158,9 @@
|
|||
</activity>
|
||||
<service android:name=".AprsService" android:label="@string/aprsservice"
|
||||
android:foregroundServiceType="location"
|
||||
tools:ignore="ExportedService" >
|
||||
tools:ignore="ExportedService"
|
||||
android:exported="true"
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="org.aprsdroid.app.SERVICE" />
|
||||
<action android:name="org.aprsdroid.app.ONCE" />
|
||||
|
@ -159,7 +170,7 @@
|
|||
</intent-filter>
|
||||
</service>
|
||||
<!-- start the service if applicable on boot -->
|
||||
<receiver android:name=".SystemEventReceiver">
|
||||
<receiver android:name=".SystemEventReceiver" android:exported="true">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
</intent-filter>
|
||||
|
|
|
@ -77,11 +77,11 @@ amazon {
|
|||
}
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
buildToolsVersion "29.0.3"
|
||||
compileSdkVersion 33
|
||||
buildToolsVersion "33.0.2"
|
||||
defaultConfig {
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 33
|
||||
versionName "$build_revision"
|
||||
versionCode versionCodeDate()
|
||||
resValue "string", "build_revision", "$build_revision"
|
||||
|
|
|
@ -35,7 +35,7 @@
|
|||
-keep public class com.jazzido.PacketDroid.AudioBufferProcessor {
|
||||
public void callback(byte[]);
|
||||
}
|
||||
-keepclassmembers class * extends com.jazzido.PacketDroid.PacketCallback {
|
||||
-keepclassmembers class * implements com.jazzido.PacketDroid.PacketCallback {
|
||||
public void received(...);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- UsbSerial/usbserial/src/main$ perl -lne '/new ConcreteDevice ?.(0x[0-9a-f]{4}), (0x[0-9a-f]{4})/i && printf "\t<usb-device vendor-id=\"%d\" product-id=\"%d\" />\n", hex($1), hex($2)' java/com/felhr/deviceids/*.java -->
|
||||
<!-- UsbSerial/usbserial/src/main$ perl -lne '/createDevice ?.(0x[0-9a-f]{4}), (0x[0-9a-f]{4})/i && printf "\t<usb-device vendor-id=\"%d\" product-id=\"%d\" />\n", hex($1), hex($2)' java/com/felhr/deviceids/*.java | sort -n -->
|
||||
<usb-device vendor-id="17224" product-id="21795" />
|
||||
<usb-device vendor-id="6790" product-id="29987" />
|
||||
<usb-device vendor-id="6790" product-id="21795" />
|
||||
|
@ -77,13 +77,17 @@
|
|||
<usb-device vendor-id="4292" product-id="34296" />
|
||||
<usb-device vendor-id="4292" product-id="34404" />
|
||||
<usb-device vendor-id="4292" product-id="34405" />
|
||||
<usb-device vendor-id="4292" product-id="34652" />
|
||||
<usb-device vendor-id="4292" product-id="34980" />
|
||||
<usb-device vendor-id="4292" product-id="34981" />
|
||||
<usb-device vendor-id="4292" product-id="60000" />
|
||||
<usb-device vendor-id="4292" product-id="60001" />
|
||||
<usb-device vendor-id="4292" product-id="60003" />
|
||||
<usb-device vendor-id="4292" product-id="60016" />
|
||||
<usb-device vendor-id="4292" product-id="60032" />
|
||||
<usb-device vendor-id="4292" product-id="60017" />
|
||||
<usb-device vendor-id="4292" product-id="60026" />
|
||||
<usb-device vendor-id="4292" product-id="60027" />
|
||||
<usb-device vendor-id="4292" product-id="60032" />
|
||||
<usb-device vendor-id="4292" product-id="61441" />
|
||||
<usb-device vendor-id="4292" product-id="61442" />
|
||||
<usb-device vendor-id="4292" product-id="61443" />
|
||||
|
@ -136,6 +140,7 @@
|
|||
<usb-device vendor-id="12693" product-id="62080" />
|
||||
<usb-device vendor-id="12693" product-id="62081" />
|
||||
<usb-device vendor-id="16700" product-id="38144" />
|
||||
<usb-device vendor-id="6408" product-id="8977" />
|
||||
<usb-device vendor-id="4292" product-id="34720" />
|
||||
<usb-device vendor-id="1027" product-id="24577" />
|
||||
<usb-device vendor-id="1027" product-id="24582" />
|
||||
|
@ -373,7 +378,6 @@
|
|||
<usb-device vendor-id="1003" product-id="8457" />
|
||||
<usb-device vendor-id="1110" product-id="61440" />
|
||||
<usb-device vendor-id="1110" product-id="61441" />
|
||||
<usb-device vendor-id="1240" product-id="10" />
|
||||
<usb-device vendor-id="1412" product-id="45088" />
|
||||
<usb-device vendor-id="1607" product-id="256" />
|
||||
<usb-device vendor-id="1742" product-id="33553" />
|
||||
|
@ -734,6 +738,8 @@
|
|||
<usb-device vendor-id="2915" product-id="25904" />
|
||||
<usb-device vendor-id="2956" product-id="8963" />
|
||||
<usb-device vendor-id="4362" product-id="4432" />
|
||||
<usb-device vendor-id="1367" product-id="8200" />
|
||||
<usb-device vendor-id="9805" product-id="562" />
|
||||
<usb-device vendor-id="9805" product-id="288" />
|
||||
<usb-device vendor-id="1155" product-id="22336" />
|
||||
</resources>
|
||||
|
|
|
@ -12,6 +12,9 @@ import android.widget.Toast
|
|||
class BackendPrefs extends PreferenceActivity
|
||||
with OnSharedPreferenceChangeListener
|
||||
with PermissionHelper {
|
||||
|
||||
val BACKEND_PERMISSION = 1000
|
||||
|
||||
def loadXml() {
|
||||
val prefs = new PrefsWrapper(this)
|
||||
addPreferencesFromResource(R.xml.backend)
|
||||
|
@ -22,6 +25,10 @@ class BackendPrefs extends PreferenceActivity
|
|||
hookPasscode()
|
||||
hookGpsPermission()
|
||||
}
|
||||
val perms = AprsBackend.defaultBackendPermissions(prefs)
|
||||
if (perms.nonEmpty) {
|
||||
checkPermissions(perms.toArray, BACKEND_PERMISSION)
|
||||
}
|
||||
}
|
||||
|
||||
def hookPasscode(): Unit = {
|
||||
|
@ -42,7 +49,7 @@ class BackendPrefs extends PreferenceActivity
|
|||
def onPreferenceClick(preference: Preference) = {
|
||||
if (preference.asInstanceOf[CheckBoxPreference].isChecked) {
|
||||
preference.asInstanceOf[CheckBoxPreference].setChecked(false)
|
||||
checkPermissions(Array(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_GPS)
|
||||
checkPermissions(Array(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), REQUEST_GPS)
|
||||
}
|
||||
true
|
||||
}
|
||||
|
@ -71,6 +78,13 @@ class BackendPrefs extends PreferenceActivity
|
|||
override def getActionName(action: Int): Int = R.string.p_conn_kwd_gps
|
||||
|
||||
override def onAllPermissionsGranted(action: Int): Unit = {
|
||||
findPreference("kenwood.gps").asInstanceOf[CheckBoxPreference].setChecked(true)
|
||||
action match {
|
||||
case REQUEST_GPS =>
|
||||
findPreference("kenwood.gps").asInstanceOf[CheckBoxPreference].setChecked(true)
|
||||
case _ =>
|
||||
}
|
||||
}
|
||||
override def onPermissionsFailedCancel(action: Int): Unit = {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ class LocationPrefs extends PreferenceActivity with OnSharedPreferenceChangeList
|
|||
if (i != null && i.getDataString() != null) {
|
||||
i.getDataString() match {
|
||||
case "gps2manual" =>
|
||||
checkPermissions(Array(Manifest.permission.ACCESS_FINE_LOCATION), REQUEST_GPS)
|
||||
checkPermissions(Array(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION), REQUEST_GPS)
|
||||
case "chooseOnMap" =>
|
||||
val mapmode = MapModes.defaultMapMode(this, prefs)
|
||||
startActivityForResult(new Intent(this, mapmode.viewClass).putExtra("info", R.string.p_source_from_map_save), REQUEST_MAP)
|
||||
|
@ -72,4 +72,7 @@ class LocationPrefs extends PreferenceActivity with OnSharedPreferenceChangeList
|
|||
pe.commit()
|
||||
} else Toast.makeText(this, getString(R.string.map_track_unknown, prefs.getCallsign()), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
override def onPermissionsFailedCancel(action: Int): Unit = {
|
||||
// nop
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,8 +19,10 @@ import _root_.org.mapsforge.v3.android.maps.overlay.{ItemizedOverlay, OverlayIte
|
|||
import _root_.scala.collection.mutable.ArrayBuffer
|
||||
import _root_.java.io.File
|
||||
import _root_.java.util.ArrayList
|
||||
import java.lang.UnsupportedOperationException
|
||||
|
||||
import org.mapsforge.v3.android.maps.mapgenerator.{MapGeneratorFactory, MapGeneratorInternal}
|
||||
import org.mapsforge.v3.map.reader.header.FileOpenResult
|
||||
|
||||
// to make scala-style iterating over arraylist possible
|
||||
import scala.collection.JavaConversions._
|
||||
|
@ -35,7 +37,7 @@ class MapAct extends MapActivity with MapMenuHelper {
|
|||
lazy val db = StorageDatabase.open(this)
|
||||
lazy val staoverlay = new StationOverlay(allicons, this, db)
|
||||
lazy val loading = findViewById(R.id.loading).asInstanceOf[View]
|
||||
lazy val locReceiver = new LocationReceiver2[ArrayList[Station]](staoverlay.load_stations,
|
||||
lazy val locReceiver = new LocationReceiver2[ArrayList[OSMStation]](staoverlay.load_stations,
|
||||
staoverlay.replace_stations, staoverlay.cancel_stations)
|
||||
|
||||
override def onCreate(savedInstanceState: Bundle) {
|
||||
|
@ -51,13 +53,16 @@ class MapAct extends MapActivity with MapMenuHelper {
|
|||
override def onResume() {
|
||||
super.onResume()
|
||||
// only make it default if not tracking
|
||||
if (targetcall == "")
|
||||
if (isCoordinateChooser)
|
||||
setTitle(R.string.p_source_from_map)
|
||||
else if (targetcall == "")
|
||||
makeLaunchActivity("map")
|
||||
else
|
||||
setLongTitle(R.string.app_map, targetcall)
|
||||
setKeepScreenOn()
|
||||
setVolumeControls()
|
||||
checkPermissions(Array(Manifest.permission.WRITE_EXTERNAL_STORAGE), RELOAD_MAP)
|
||||
//checkPermissions(Array(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE), RELOAD_MAP)
|
||||
reloadMapAndTheme()
|
||||
mapview.requestFocus()
|
||||
}
|
||||
|
||||
|
@ -105,26 +110,39 @@ class MapAct extends MapActivity with MapMenuHelper {
|
|||
}
|
||||
}
|
||||
|
||||
override def onPermissionsFailed(action: Int, permissions: Set[String]): Unit = {
|
||||
if (action == RELOAD_MAP) {
|
||||
if (targetcall == "")
|
||||
startActivity(new Intent(this, classOf[HubActivity]).addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP))
|
||||
finish()
|
||||
}
|
||||
super.onPermissionsFailed(action, permissions)
|
||||
}
|
||||
override def onPermissionsFailed(action : Int, permissions : Set[String]): Unit = {
|
||||
// fail to online OSM map
|
||||
}
|
||||
|
||||
override def onPermissionsFailedCancel(action: Int): Unit = {
|
||||
// should never be called
|
||||
}
|
||||
|
||||
def reloadMapAndTheme() {
|
||||
val mapfile = new File(prefs.getString("mapfile", android.os.Environment.getExternalStorageDirectory() + "/aprsdroid.map"))
|
||||
if (mapfile.exists() && mapfile.canRead())
|
||||
mapview.setMapFile(mapfile)
|
||||
else {
|
||||
if (prefs.getString("mapfile", null) != null)
|
||||
Toast.makeText(this, getString(R.string.mapfile_error, mapfile), Toast.LENGTH_SHORT).show()
|
||||
val map_source = MapGeneratorInternal.MAPNIK
|
||||
val map_gen = new OsmTileDownloader()
|
||||
map_gen.setUserAgent(getString(R.string.build_version))
|
||||
mapview.setMapGenerator(map_gen)
|
||||
var error = if (mapfile.exists() && mapfile.canRead()) {
|
||||
val result = mapview.setMapFile(mapfile)
|
||||
// output map loader's error if loading failed
|
||||
if (result.isSuccess) null else result.getErrorMessage
|
||||
} else if (prefs.getString("mapfile", null) != null) {
|
||||
// output generic error if file was configured but is not loadable
|
||||
getString(R.string.mapfile_error, mapfile)
|
||||
} else {
|
||||
// do not output error if no map file was configured, silently load online osm
|
||||
null
|
||||
}
|
||||
if (error != null)
|
||||
Toast.makeText(this, error, Toast.LENGTH_SHORT).show()
|
||||
// all map file attempts failed, fall back to online
|
||||
try {
|
||||
if (mapview.getMapFile == null) {
|
||||
val map_source = MapGeneratorInternal.MAPNIK
|
||||
val map_gen = new OsmTileDownloader()
|
||||
map_gen.setUserAgent(getString(R.string.build_version))
|
||||
mapview.setMapGenerator(map_gen)
|
||||
}
|
||||
} catch {
|
||||
case _ : UnsupportedOperationException => /* ignore, this is thrown by online map generator */
|
||||
}
|
||||
val themefile = new File(prefs.getString("themefile", android.os.Environment.getExternalStorageDirectory() + "/aprsdroid.xml"))
|
||||
if (themefile.exists())
|
||||
|
@ -153,6 +171,7 @@ class MapAct extends MapActivity with MapMenuHelper {
|
|||
KeyEvent.KEYCODE_ENTER =>
|
||||
// TODO: return coordinates
|
||||
if (isCoordinateChooser) {
|
||||
setResult(android.app.Activity.RESULT_OK, resultIntent)
|
||||
finish()
|
||||
}
|
||||
true
|
||||
|
@ -201,7 +220,7 @@ class MapAct extends MapActivity with MapMenuHelper {
|
|||
}
|
||||
}
|
||||
|
||||
class Station(val movelog : ArrayBuffer[GeoPoint], val pt : GeoPoint,
|
||||
class OSMStation(val movelog : ArrayBuffer[GeoPoint], val pt : GeoPoint,
|
||||
val call : String, val origin : String, val symbol : String)
|
||||
extends OverlayItem(pt, call, origin) {
|
||||
|
||||
|
@ -215,11 +234,11 @@ class Station(val movelog : ArrayBuffer[GeoPoint], val pt : GeoPoint,
|
|||
}
|
||||
}
|
||||
|
||||
class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) extends ItemizedOverlay[Station](icons) {
|
||||
class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) extends ItemizedOverlay[OSMStation](icons) {
|
||||
val TAG = "APRSdroid.StaOverlay"
|
||||
|
||||
//lazy val calls = new scala.collection.mutable.HashMap[String, Boolean]()
|
||||
var stations = new java.util.ArrayList[Station]()
|
||||
var stations = new java.util.ArrayList[OSMStation]()
|
||||
|
||||
// prevent android bug #11666
|
||||
populate()
|
||||
|
@ -231,7 +250,7 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
icons.setBounds(0, 0, symbolSize, symbolSize)
|
||||
|
||||
override def size() = stations.size()
|
||||
override def createItem(idx : Int) : Station = stations.get(idx)
|
||||
override def createItem(idx : Int) : OSMStation = stations.get(idx)
|
||||
|
||||
def symbol2rect(index : Int, page : Int) : Rect = {
|
||||
// check for overflow
|
||||
|
@ -250,7 +269,7 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
(symbol(0) != '/' && symbol(0) != '\\')
|
||||
}
|
||||
|
||||
def drawTrace(c : Canvas, proj : Projection, s : Station) : Unit = {
|
||||
def drawTrace(c : Canvas, proj : Projection, s : OSMStation) : Unit = {
|
||||
//Log.d(TAG, "drawing trace of %s".format(call))
|
||||
|
||||
val tracePaint = new Paint()
|
||||
|
@ -339,7 +358,7 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
context.handler.post { context.updateCoordinateInfo() }
|
||||
}
|
||||
|
||||
def addStation(sta : Station) {
|
||||
def addStation(sta : OSMStation) {
|
||||
//if (calls.contains(sta.getTitle()))
|
||||
// return
|
||||
//calls.add(sta.getTitle(), true)
|
||||
|
@ -407,10 +426,10 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
m
|
||||
}
|
||||
|
||||
def load_stations(i : Intent) : ArrayList[Station] = {
|
||||
def load_stations(i : Intent) : ArrayList[OSMStation] = {
|
||||
import StorageDatabase.Station._
|
||||
|
||||
val s = new ArrayList[Station]()
|
||||
val s = new ArrayList[OSMStation]()
|
||||
val age_ts = (System.currentTimeMillis - context.prefs.getShowAge()).toString
|
||||
val filter = if (context.showObjects) "TS > ? OR CALL=?" else "(ORIGIN IS NULL AND TS > ?) OR CALL=?"
|
||||
val c = db.getStations(filter, Array(age_ts, context.targetcall), null)
|
||||
|
@ -425,7 +444,7 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
val origin = c.getString(COLUMN_MAP_ORIGIN)
|
||||
val p = new GeoPoint(lat, lon)
|
||||
val m = fetchStaPositions(call, pos_c)
|
||||
s.add(new Station(m, p, call, origin, symbol))
|
||||
s.add(new OSMStation(m, p, call, origin, symbol))
|
||||
c.moveToNext()
|
||||
}
|
||||
c.close()
|
||||
|
@ -434,12 +453,12 @@ class StationOverlay(icons : Drawable, context : MapAct, db : StorageDatabase) e
|
|||
s
|
||||
}
|
||||
|
||||
def replace_stations(s : ArrayList[Station]) {
|
||||
def replace_stations(s : ArrayList[OSMStation]) {
|
||||
stations = s
|
||||
Benchmark("populate") { populate() }
|
||||
context.onPostLoad()
|
||||
}
|
||||
def cancel_stations(s : ArrayList[Station]) {
|
||||
def cancel_stations(s : ArrayList[OSMStation]) {
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -24,7 +24,14 @@ trait MapLoaderBase extends MapMenuHelper {
|
|||
super.onDestroy()
|
||||
}
|
||||
|
||||
def onStationUpdate(sl : ArrayList[Station])
|
||||
def newStation(call : String, origin : String, symbol : String,
|
||||
lat : Double, lon : Double,
|
||||
qrg : String, comment : String, speed : Int, course : Int,
|
||||
movelog : ArrayBuffer[Point]) : Station = {
|
||||
new Station(call, origin, symbol, lat, lon, qrg, comment, speed, course, movelog)
|
||||
}
|
||||
|
||||
def onStationUpdate(sl : ArrayList[Station])
|
||||
|
||||
def startLoading() {
|
||||
locReceiver.startTask(null)
|
||||
|
@ -52,7 +59,7 @@ trait MapLoaderBase extends MapMenuHelper {
|
|||
val cse = c.getInt(COLUMN_MAP_CSE)
|
||||
|
||||
if (call != null && !call.isEmpty)
|
||||
s.add(new Station(call, origin, symbol, lat/1000000.0d, lon/1000000.0d,
|
||||
s.add(newStation(call, origin, symbol, lat/1000000.0d, lon/1000000.0d,
|
||||
qrg, comment, speed, cse,
|
||||
null))
|
||||
c.moveToNext()
|
||||
|
|
|
@ -46,7 +46,7 @@ trait MapMenuHelper extends UIHelper with OnClickListener {
|
|||
infoText.setVisibility(View.INVISIBLE)
|
||||
accept.setVisibility(View.INVISIBLE)
|
||||
}
|
||||
keyboardNavDialog()
|
||||
keyboardNavDialog(isCoordinateChooser)
|
||||
}
|
||||
|
||||
abstract override def onCreateOptionsMenu(menu : Menu) : Boolean = {
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.provider.Settings
|
|||
trait PermissionHelper extends Activity {
|
||||
def getActionName(action : Int): Int
|
||||
def onAllPermissionsGranted(action : Int): Unit
|
||||
def onPermissionsFailedCancel(action : Int): Unit
|
||||
|
||||
def checkPermissions(permissions : Array[String], action : Int): Boolean = {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
|
||||
|
@ -71,7 +72,11 @@ trait PermissionHelper extends Activity {
|
|||
startActivity(intent)
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener {
|
||||
override def onClick(dialogInterface: DialogInterface, i: Int): Unit = {
|
||||
onPermissionsFailedCancel(action)
|
||||
}
|
||||
})
|
||||
.create().show()
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ class PrefsAct extends PreferenceActivity {
|
|||
def fileChooserPreference(pref_name : String, reqCode : Int, titleId : Int) {
|
||||
findPreference(pref_name).setOnPreferenceClickListener(new OnPreferenceClickListener() {
|
||||
def onPreferenceClick(preference : Preference) = {
|
||||
val get_file = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*")
|
||||
val get_file = new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*")
|
||||
startActivityForResult(Intent.createChooser(get_file,
|
||||
getString(titleId)), reqCode)
|
||||
true
|
||||
|
@ -110,7 +110,13 @@ class PrefsAct extends PreferenceActivity {
|
|||
override def onActivityResult(reqCode : Int, resultCode : Int, data : Intent) {
|
||||
android.util.Log.d("PrefsAct", "onActResult: request=" + reqCode + " result=" + resultCode + " " + data)
|
||||
if (resultCode == android.app.Activity.RESULT_OK && reqCode == 123456) {
|
||||
parseFilePickerResult(data, "mapfile", R.string.mapfile_error)
|
||||
//parseFilePickerResult(data, "mapfile", R.string.mapfile_error)
|
||||
val takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
|
||||
getContentResolver.takePersistableUriPermission(data.getData(), takeFlags)
|
||||
PreferenceManager.getDefaultSharedPreferences(this)
|
||||
.edit().putString("mapfile", data.getDataString()).commit()
|
||||
finish()
|
||||
startActivity(getIntent())
|
||||
} else
|
||||
if (resultCode == android.app.Activity.RESULT_OK && reqCode == 123457) {
|
||||
parseFilePickerResult(data, "themefile", R.string.themefile_error)
|
||||
|
@ -129,7 +135,7 @@ class PrefsAct extends PreferenceActivity {
|
|||
override def onOptionsItemSelected(mi : MenuItem) : Boolean = {
|
||||
mi.getItemId match {
|
||||
case R.id.profile_load =>
|
||||
val get_file = new Intent(Intent.ACTION_GET_CONTENT).setType("*/*")
|
||||
val get_file = new Intent(Intent.ACTION_OPEN_DOCUMENT).setType("*/*")
|
||||
// TODO: use MaterialFilePicker().withFilter() for *.aprs
|
||||
startActivityForResult(Intent.createChooser(get_file,
|
||||
getString(R.string.profile_import_activity)), 123458)
|
||||
|
|
|
@ -41,7 +41,7 @@ class ServiceNotifier {
|
|||
val nb = newNotificationBuilder(ctx, "status")
|
||||
.setContentTitle(appname)
|
||||
.setContentText(status)
|
||||
.setContentIntent(PendingIntent.getActivity(ctx, 0, i, 0))
|
||||
.setContentIntent(PendingIntent.getActivity(ctx, 0, i, PendingIntent.FLAG_IMMUTABLE))
|
||||
.setSmallIcon(R.drawable.ic_status)
|
||||
.setWhen(System.currentTimeMillis)
|
||||
.setOngoing(true)
|
||||
|
@ -68,7 +68,7 @@ class ServiceNotifier {
|
|||
newNotificationBuilder(ctx, "msg")
|
||||
.setContentTitle(call)
|
||||
.setContentText(message)
|
||||
.setContentIntent(PendingIntent.getActivity(ctx, 0, i, PendingIntent.FLAG_UPDATE_CURRENT))
|
||||
.setContentIntent(PendingIntent.getActivity(ctx, 0, i, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE))
|
||||
.setSmallIcon(R.drawable.icon)
|
||||
.setTicker(call + ": " + message)
|
||||
.setWhen(System.currentTimeMillis)
|
||||
|
|
|
@ -108,6 +108,9 @@ trait UIHelper extends Activity
|
|||
case START_SERVICE_ONCE => startService(AprsService.intent(this, AprsService.SERVICE_ONCE))
|
||||
}
|
||||
}
|
||||
override def onPermissionsFailedCancel(action: Int): Unit = {
|
||||
// nop
|
||||
}
|
||||
def startAprsService(action : Int): Unit = {
|
||||
checkPermissions(currentListOfPermissions(), action)
|
||||
}
|
||||
|
@ -137,20 +140,22 @@ trait UIHelper extends Activity
|
|||
passcodeDialog.show()
|
||||
}
|
||||
|
||||
def keyboardNavDialog() {
|
||||
def keyboardNavDialog(force : Boolean = false) {
|
||||
if (getPackageManager().hasSystemFeature("android.hardware.touchscreen"))
|
||||
return
|
||||
if (prefs.getBoolean("kbdnav_shown", false))
|
||||
if (!force && prefs.getBoolean("kbdnav_shown", false))
|
||||
return
|
||||
prefs.prefs.edit().putBoolean("kbdnav_shown", true).commit()
|
||||
|
||||
val keys = Array("⬅➡⬆⬇", "⏪⏩", "⏯️", "⏎🆗")
|
||||
val keys = Array("←→↑↓", "⏪⏩", "⏯️", "⏎🆗")
|
||||
val titles = getResources().getStringArray(R.array.kbdnav_lines)
|
||||
val text = keys zip titles map { case (k, v) => "%s\t%s".format(k, v) } mkString("\n")
|
||||
val text = keys zip titles map { case (k, v) => "%s\t%s".format(k, v) } mkString("\n\n")
|
||||
new AlertDialog.Builder(this).setTitle(R.string.kbdnav_title)
|
||||
.setMessage(text)
|
||||
.setIcon(android.R.drawable.ic_dialog_info)
|
||||
.setPositiveButton(android.R.string.ok, null)
|
||||
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener {
|
||||
override def onClick(dialog: DialogInterface, which: Int) = {
|
||||
prefs.prefs.edit().putBoolean("kbdnav_shown", true).commit()
|
||||
}})
|
||||
.create.show
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package org.aprsdroid.app
|
||||
|
||||
import android.Manifest
|
||||
import android.os.Build
|
||||
import _root_.net.ab0oo.aprs.parser.APRSPacket
|
||||
import _root_.java.io.{InputStream, OutputStream}
|
||||
|
||||
|
@ -32,6 +33,12 @@ object AprsBackend {
|
|||
val need_passcode : Int
|
||||
) {}
|
||||
|
||||
val BLUETOOTH_PERMISSION = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
Manifest.permission.BLUETOOTH_CONNECT
|
||||
} else {
|
||||
Manifest.permission.BLUETOOTH_ADMIN
|
||||
}
|
||||
|
||||
// map from old "backend" to new proto-link-aprsis (defaults are bluetooth and tcp)
|
||||
val backend_upgrade = Map(
|
||||
"tcp" -> "aprsis-tcpip-tcp",
|
||||
|
@ -61,7 +68,7 @@ object AprsBackend {
|
|||
"afsk" -> new BackendInfo(
|
||||
(s, p) => new AfskUploader(s, p),
|
||||
0,
|
||||
Set(Manifest.permission.RECORD_AUDIO),
|
||||
Set(Manifest.permission.RECORD_AUDIO),
|
||||
CAN_DUPLEX,
|
||||
PASSCODE_NONE),
|
||||
"tcp" -> new BackendInfo(
|
||||
|
@ -73,7 +80,7 @@ object AprsBackend {
|
|||
"bluetooth" -> new BackendInfo(
|
||||
(s, p) => new BluetoothTnc(s, p),
|
||||
R.xml.backend_bluetooth,
|
||||
Set(Manifest.permission.BLUETOOTH_ADMIN),
|
||||
Set(BLUETOOTH_PERMISSION),
|
||||
CAN_DUPLEX,
|
||||
PASSCODE_NONE),
|
||||
"tcpip" -> new BackendInfo(
|
||||
|
@ -134,7 +141,10 @@ object AprsBackend {
|
|||
val perms = scala.collection.mutable.Set[String]()
|
||||
perms ++= AprsBackend.defaultBackendInfo(prefs).permissions
|
||||
if (prefs.getProto() == "kenwood" && prefs.getBoolean("kenwood.gps", false))
|
||||
perms.add(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
perms += (Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
perms += (Manifest.permission.POST_NOTIFICATIONS)
|
||||
}
|
||||
perms.toSet
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ class UsbTnc(service : AprsService, prefs : PrefsWrapper) extends AprsBackend(pr
|
|||
var alreadyRunning = false
|
||||
|
||||
val intent = new Intent(USB_PERM_ACTION)
|
||||
val pendingIntent = PendingIntent.getBroadcast(service, 0, intent, 0)
|
||||
val pendingIntent = PendingIntent.getBroadcast(service, 0, intent, PendingIntent.FLAG_MUTABLE)
|
||||
|
||||
val receiver = new BroadcastReceiver() {
|
||||
override def onReceive(ctx : Context, i : Intent) {
|
||||
|
@ -59,6 +59,11 @@ class UsbTnc(service : AprsService, prefs : PrefsWrapper) extends AprsBackend(pr
|
|||
ctx.stopService(AprsService.intent(ctx, AprsService.SERVICE))
|
||||
return
|
||||
}
|
||||
if (i.getExtras() == null) {
|
||||
/* this shouldn't ever happen, don't need i18n */
|
||||
service.postAbort("USB permission bug")
|
||||
return
|
||||
}
|
||||
val granted = i.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED)
|
||||
if (!granted) {
|
||||
service.postAbort(service.getString(R.string.p_serial_noperm))
|
||||
|
|
|
@ -16,7 +16,7 @@ class FixedPosition(service : AprsService, prefs : PrefsWrapper) extends Locatio
|
|||
|
||||
val intent = new Intent(ALARM_ACTION)
|
||||
val pendingIntent = PendingIntent.getBroadcast(service, 0, intent,
|
||||
PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE)
|
||||
|
||||
// get called on alarm
|
||||
val receiver = new BroadcastReceiver() {
|
||||
|
|
|
@ -22,8 +22,8 @@ object LocationSource {
|
|||
}
|
||||
def getPermissions(prefs : PrefsWrapper) = {
|
||||
prefs.getString("loc_source", DEFAULT_CONNTYPE) match {
|
||||
case "smartbeaconing" => Set(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
case "periodic" => Set(Manifest.permission.ACCESS_FINE_LOCATION)
|
||||
case "smartbeaconing" => Set(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||
case "periodic" => Set(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION)
|
||||
case "manual" => Set()
|
||||
}
|
||||
}
|
||||
|
|
Ładowanie…
Reference in New Issue