Сравнить коммиты

...
25 Коммитов
Автор SHA1 Сообщение Дата
Anton Tananaev 8b985526dd Update version number 2022-01-30 10:18:36 -08:00
Anton Tananaev 5e8ea134e0 Attempt at fixing crashes 2022-01-30 10:18:09 -08:00
Anton Tananaev ec85edd56f Update version number 2021-11-04 19:21:19 -07:00
Anton Tananaev c5ab10919e Update dependencies 2021-11-04 19:20:08 -07:00
Anton Tananaev 3e8ba9a603 Fix Android 11 location permissions 2021-11-04 19:18:09 -07:00
Anton Tananaev 826d638ea3 Update version number 2021-10-11 23:26:51 -07:00
Anton Tananaev 1b687bd075 Handle security exception 2021-10-11 23:26:28 -07:00
Anton Tananaev 42d5584d8d Fix hidden app 2021-10-09 17:59:58 -07:00
Anton Tananaev ff88682e40 Update app version 2021-10-09 17:41:18 -07:00
Anton Tananaev 307e692459 Integrate DKMA info 2021-10-09 17:40:27 -07:00
Anton Tananaev b7ec644ecf Improve app autostart 2021-10-09 17:40:27 -07:00
Anton Tananaev 842baa2aec Merge pull request #427 from scfarley/master
Accept user CA's for connections via HTTPS proxy
2021-09-12 18:25:32 -07:00
Sean Farley 26bc92cf8e Accept user CA's for connections via HTTPS proxy
Permit Traccar client to communicate with the Traccar server via an
HTTPS proxy that uses a certificate generated from a user (non-system)
CA.
2021-09-12 21:02:20 -04:00
Anton Tananaev 6dadf5e7c3 Update project files 2021-08-29 22:13:52 -07:00
Anton Tananaev 39e9c171c4 Handle battery optimization exception 2021-08-29 18:17:31 -07:00
Anton Tananaev bcb5985cef Alarm foreground priority 2021-08-29 15:55:52 -07:00
Anton Tananaev eb868056bf Change alarm flag 2021-07-31 07:37:47 -10:00
Anton Tananaev 94e094e648 Update app version 2021-07-24 11:24:26 -07:00
Anton Tananaev 25c0434e4c Fix database management 2021-07-24 11:23:58 -07:00
Anton Tananaev 3afcfa17d0 Update version number 2021-07-20 23:12:26 -07:00
Anton Tananaev 02263d5fd9 Fix crash 2021-07-20 23:12:04 -07:00
Anton Tananaev a884b2f3d7 Reorder dependencies 2021-07-19 20:26:42 -07:00
Anton Tananaev 6910790fa7 Specify location services version 2021-07-19 20:17:53 -07:00
Anton Tananaev 6cab1a0b36 Update Firebase 2021-07-19 20:14:15 -07:00
Anton Tananaev edd4f670fe Remove unused 2021-07-19 20:03:06 -07:00
14 изменённых файлов: 237 добавлений и 54 удалений
+18 -13
Просмотреть файл
@@ -2,15 +2,15 @@ apply plugin: 'com.android.application'
apply plugin: 'kotlin-android' apply plugin: 'kotlin-android'
android { android {
compileSdkVersion 30 compileSdkVersion 31
defaultConfig { defaultConfig {
applicationId 'org.traccar.client' applicationId 'org.traccar.client'
buildConfigField 'boolean', 'HIDDEN_APP', 'false' buildConfigField 'boolean', 'HIDDEN_APP', 'false'
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 30 targetSdkVersion 31
versionCode 69 versionCode 77
versionName '6.8' versionName '6.16'
multiDexEnabled true multiDexEnabled true
} }
@@ -47,19 +47,24 @@ android {
} }
dependencies { dependencies {
implementation 'com.google.android.material:material:1.5.0-alpha01' implementation 'com.google.android.material:material:1.5.0-alpha05'
implementation 'androidx.multidex:multidex:2.0.1' implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.preference:preference-ktx:1.1.1'
implementation 'androidx.test:core-ktx:1.4.0' implementation 'androidx.test:core-ktx:1.4.0'
testImplementation 'junit:junit:4.13.2' implementation 'androidx.core:core-ktx:1.7.0'
testImplementation 'org.robolectric:robolectric:4.1'
googleImplementation 'com.google.firebase:firebase-core:19.0.0'
googleImplementation 'com.google.firebase:firebase-crashlytics-gradle:2.7.1'
googleImplementation 'com.google.firebase:firebase-analytics:19.0.0'
googleImplementation 'com.google.android.gms:play-services-location:18.0.0'
googleImplementation 'com.google.android.play:core:1.10.0'
implementation "androidx.core:core-ktx:1.6.0"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.github.judemanutd:autostarter:1.1.0'
implementation('dev.doubledot.doki:library:0.0.1@aar') {
transitive = true
}
testImplementation 'junit:junit:4.13.2'
testImplementation 'org.robolectric:robolectric:4.6.1'
googleImplementation platform('com.google.firebase:firebase-bom:28.2.1')
googleImplementation 'com.google.firebase:firebase-core'
googleImplementation 'com.google.firebase:firebase-analytics'
googleImplementation 'com.google.firebase:firebase-crashlytics'
googleImplementation 'com.google.android.gms:play-services-location:18.0.0'
googleImplementation 'com.google.android.play:core:1.10.2'
} }
if (getGradle().getStartParameter().getTaskRequests().toString().contains('Google')) { if (getGradle().getStartParameter().getTaskRequests().toString().contains('Google')) {
+5 -2
Просмотреть файл
@@ -9,7 +9,8 @@
tools:replace="android:label"> tools:replace="android:label">
<activity <activity
android:name="org.traccar.client.MainActivity"> android:name="org.traccar.client.MainActivity"
android:exported="true">
<intent-filter android:label="@string/app_name"> <intent-filter android:label="@string/app_name">
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT" />
@@ -18,7 +19,9 @@
</intent-filter> </intent-filter>
</activity> </activity>
<receiver android:name="org.traccar.client.DialLaunchReceiver" > <receiver
android:name="org.traccar.client.DialLaunchReceiver"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" /> <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter> </intent-filter>
+16 -3
Просмотреть файл
@@ -6,6 +6,7 @@
<uses-permission android:name="android.permission.ACCESS_COARSE_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.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
@@ -13,6 +14,9 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> <uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" /> <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
<uses-permission android:name="oppo.permission.OPPO_COMPONENT_SAFE" />
<uses-permission android:name="com.huawei.permission.external_app_settings.USE_COMPONENT" />
<uses-feature android:name="android.hardware.location.network" /> <uses-feature android:name="android.hardware.location.network" />
<uses-feature android:name="android.hardware.location.gps" /> <uses-feature android:name="android.hardware.location.gps" />
@@ -31,10 +35,12 @@
<activity <activity
android:name=".MainActivity" android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask" /> android:launchMode="singleTask" />
<activity-alias <activity-alias
android:name=".Launcher" android:name=".Launcher"
android:exported="true"
android:targetActivity=".MainActivity"> android:targetActivity=".MainActivity">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@@ -45,10 +51,13 @@
android:resource="@xml/shortcuts" /> android:resource="@xml/shortcuts" />
</activity-alias> </activity-alias>
<activity android:name=".StatusActivity"/> <activity
android:name=".StatusActivity"
android:exported="false" />
<activity <activity
android:name=".ShortcutActivity" android:name=".ShortcutActivity"
android:exported="true"
android:label="@string/menu_shortcuts"> android:label="@string/menu_shortcuts">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
@@ -58,12 +67,16 @@
<service <service
android:name=".TrackingService" android:name=".TrackingService"
android:exported="false"
android:foregroundServiceType="location" /> android:foregroundServiceType="location" />
<service <service
android:name=".TrackingService$HideNotificationService" /> android:name=".TrackingService$HideNotificationService"
android:exported="false" />
<receiver android:name=".AutostartReceiver"> <receiver
android:name=".AutostartReceiver"
android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
+102
Просмотреть файл
@@ -0,0 +1,102 @@
/*
* Copyright 2021 Anton Tananaev (anton@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.traccar.client
import android.content.ActivityNotFoundException
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build
import android.os.PowerManager
import android.provider.Settings
import androidx.appcompat.app.AlertDialog
import androidx.preference.PreferenceManager
import com.judemanutd.autostarter.AutoStartPermissionHelper
class BatteryOptimizationHelper {
private fun showDialog(context: Context, onSuccess: () -> Unit) {
val builder = AlertDialog.Builder(context)
builder.setMessage(context.getString(R.string.request_exception))
builder.setPositiveButton(android.R.string.ok) { _, _ -> onSuccess() }
builder.setNegativeButton(android.R.string.cancel, null)
builder.show()
}
private fun requestVendorException(context: Context) {
val vendorIntentList = listOf(
Intent().setComponent(ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")),
Intent().setComponent(ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
Intent().setComponent(ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.startupmgr.ui.StartupNormalAppListActivity")),
Intent().setComponent(ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")),
Intent().setComponent(ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.appcontrol.activity.StartupAppControlActivity")),
Intent().setComponent(ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
Intent().setComponent(ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
Intent().setComponent(ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
Intent().setComponent(ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
Intent().setComponent(ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
Intent().setComponent(ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
Intent().setComponent(ComponentName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")),
Intent().setComponent(ComponentName("com.htc.pitroad", "com.htc.pitroad.landingpage.activity.LandingPageActivity")),
Intent().setComponent(ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.MainActivity")),
)
for (vendorIntent in vendorIntentList) {
if (context.packageManager.resolveActivity(vendorIntent, PackageManager.MATCH_DEFAULT_ONLY) != null) {
try {
context.startActivity(vendorIntent)
return
} catch (e: Exception) {
continue
}
}
}
}
fun requestException(context: Context): Boolean {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
if (!sharedPreferences.getBoolean(KEY_EXCEPTION_REQUESTED, false)) {
sharedPreferences.edit().putBoolean(KEY_EXCEPTION_REQUESTED, true).apply()
val powerManager = context.getSystemService(PowerManager::class.java)
if (!powerManager.isIgnoringBatteryOptimizations(context.packageName)) {
showDialog(context) {
try {
context.startActivity(Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS))
} catch (e: ActivityNotFoundException) {
requestVendorException(context)
}
}
return true
}
} else if (!sharedPreferences.getBoolean(KEY_AUTOSTART_REQUESTED, false)) {
sharedPreferences.edit().putBoolean(KEY_AUTOSTART_REQUESTED, true).apply()
try {
if (AutoStartPermissionHelper.getInstance().getAutoStartPermission(context)) {
return true
}
} catch (e: SecurityException) {
}
}
}
return false
}
companion object {
private const val KEY_EXCEPTION_REQUESTED = "exceptionRequested"
private const val KEY_AUTOSTART_REQUESTED = "autostartRequested"
}
}
+4 -4
Просмотреть файл
@@ -30,7 +30,7 @@ class DatabaseHelper(context: Context?) : SQLiteOpenHelper(context, DATABASE_NAM
fun onComplete(success: Boolean, result: T) fun onComplete(success: Boolean, result: T)
} }
private abstract class DatabaseAsyncTask<T>(val handler: DatabaseHandler<T>) : AsyncTask<Unit, Unit, T?>() { private abstract class DatabaseAsyncTask<T>(val handler: DatabaseHandler<T?>) : AsyncTask<Unit, Unit, T?>() {
private var error: RuntimeException? = null private var error: RuntimeException? = null
@@ -46,7 +46,7 @@ class DatabaseHelper(context: Context?) : SQLiteOpenHelper(context, DATABASE_NAM
protected abstract fun executeMethod(): T protected abstract fun executeMethod(): T
override fun onPostExecute(result: T?) { override fun onPostExecute(result: T?) {
result?.let { handler.onComplete(error == null, result) } handler.onComplete(error == null, result)
} }
} }
@@ -94,7 +94,7 @@ class DatabaseHelper(context: Context?) : SQLiteOpenHelper(context, DATABASE_NAM
db.insertOrThrow("position", null, values) db.insertOrThrow("position", null, values)
} }
fun insertPositionAsync(position: Position, handler: DatabaseHandler<Unit>) { fun insertPositionAsync(position: Position, handler: DatabaseHandler<Unit?>) {
object : DatabaseAsyncTask<Unit>(handler) { object : DatabaseAsyncTask<Unit>(handler) {
override fun executeMethod() { override fun executeMethod() {
insertPosition(position) insertPosition(position)
@@ -138,7 +138,7 @@ class DatabaseHelper(context: Context?) : SQLiteOpenHelper(context, DATABASE_NAM
} }
} }
fun deletePositionAsync(id: Long, handler: DatabaseHandler<Unit>) { fun deletePositionAsync(id: Long, handler: DatabaseHandler<Unit?>) {
object : DatabaseAsyncTask<Unit>(handler) { object : DatabaseAsyncTask<Unit>(handler) {
override fun executeMethod() { override fun executeMethod() {
deletePosition(id) deletePosition(id)
-5
Просмотреть файл
@@ -24,11 +24,6 @@ import android.graphics.Color
import android.os.Build import android.os.Build
import android.app.Activity import android.app.Activity
import androidx.annotation.NonNull
open class MainApplication : MultiDexApplication() { open class MainApplication : MultiDexApplication() {
override fun onCreate() { override fun onCreate() {
+56 -10
Просмотреть файл
@@ -45,6 +45,7 @@ import androidx.preference.Preference
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import androidx.preference.TwoStatePreference import androidx.preference.TwoStatePreference
import dev.doubledot.doki.ui.DokiActivity
import java.util.* import java.util.*
import kotlin.collections.HashSet import kotlin.collections.HashSet
@@ -53,6 +54,7 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
private lateinit var sharedPreferences: SharedPreferences private lateinit var sharedPreferences: SharedPreferences
private lateinit var alarmManager: AlarmManager private lateinit var alarmManager: AlarmManager
private lateinit var alarmIntent: PendingIntent private lateinit var alarmIntent: PendingIntent
private var requestingPermissions: Boolean = false
@SuppressLint("UnspecifiedImmutableFlag") @SuppressLint("UnspecifiedImmutableFlag")
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
@@ -90,7 +92,16 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
findPreference<Preference>(KEY_ANGLE)?.onPreferenceChangeListener = numberValidationListener findPreference<Preference>(KEY_ANGLE)?.onPreferenceChangeListener = numberValidationListener
alarmManager = requireActivity().getSystemService(Context.ALARM_SERVICE) as AlarmManager alarmManager = requireActivity().getSystemService(Context.ALARM_SERVICE) as AlarmManager
alarmIntent = PendingIntent.getBroadcast(activity, 0, Intent(activity, AutostartReceiver::class.java), 0) val originalIntent = Intent(activity, AutostartReceiver::class.java)
originalIntent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
alarmIntent = PendingIntent.getBroadcast(activity, 0, originalIntent, flags)
if (sharedPreferences.getBoolean(KEY_STATUS, false)) { if (sharedPreferences.getBoolean(KEY_STATUS, false)) {
startTrackingService(checkPermission = true, initialPermission = false) startTrackingService(checkPermission = true, initialPermission = false)
} }
@@ -144,6 +155,13 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
} }
} }
override fun onStart() {
super.onStart()
if (requestingPermissions) {
requestingPermissions = BatteryOptimizationHelper().requestException(requireContext())
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
sharedPreferences.registerOnSharedPreferenceChangeListener(this) sharedPreferences.registerOnSharedPreferenceChangeListener(this)
@@ -187,6 +205,9 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
if (item.itemId == R.id.status) { if (item.itemId == R.id.status) {
startActivity(Intent(activity, StatusActivity::class.java)) startActivity(Intent(activity, StatusActivity::class.java))
return true return true
} else if (item.itemId == R.id.info) {
DokiActivity.start(requireContext())
return true
} }
return super.onOptionsItemSelected(item) return super.onOptionsItemSelected(item)
} }
@@ -201,6 +222,19 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
findPreference<Preference>(KEY_DEVICE)?.summary = sharedPreferences.getString(KEY_DEVICE, null) findPreference<Preference>(KEY_DEVICE)?.summary = sharedPreferences.getString(KEY_DEVICE, null)
} }
private fun showBackgroundLocationDialog(context: Context, onSuccess: () -> Unit) {
val builder = AlertDialog.Builder(context)
val option = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
context.packageManager.backgroundPermissionOptionLabel
} else {
context.getString(R.string.request_background_option)
}
builder.setMessage(context.getString(R.string.request_background, option))
builder.setPositiveButton(android.R.string.ok) { _, _ -> onSuccess() }
builder.setNegativeButton(android.R.string.cancel, null)
builder.show()
}
private fun startTrackingService(checkPermission: Boolean, initialPermission: Boolean) { private fun startTrackingService(checkPermission: Boolean, initialPermission: Boolean) {
var permission = initialPermission var permission = initialPermission
if (checkPermission) { if (checkPermission) {
@@ -211,10 +245,7 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
permission = requiredPermissions.isEmpty() permission = requiredPermissions.isEmpty()
if (!permission) { if (!permission) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
requestPermissions( requestPermissions(requiredPermissions.toTypedArray(), PERMISSIONS_REQUEST_LOCATION)
requiredPermissions.toTypedArray(),
PERMISSIONS_REQUEST_LOCATION
)
} }
return return
} }
@@ -222,10 +253,22 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
if (permission) { if (permission) {
setPreferencesEnabled(false) setPreferencesEnabled(false)
ContextCompat.startForegroundService(requireContext(), Intent(activity, TrackingService::class.java)) ContextCompat.startForegroundService(requireContext(), Intent(activity, TrackingService::class.java))
alarmManager.setInexactRepeating( if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
AlarmManager.ELAPSED_REALTIME_WAKEUP, alarmManager.setInexactRepeating(
ALARM_MANAGER_INTERVAL.toLong(), ALARM_MANAGER_INTERVAL.toLong(), alarmIntent AlarmManager.ELAPSED_REALTIME_WAKEUP,
) ALARM_MANAGER_INTERVAL.toLong(), ALARM_MANAGER_INTERVAL.toLong(), alarmIntent
)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q
&& ContextCompat.checkSelfPermission(requireContext(), Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
requestingPermissions = true
showBackgroundLocationDialog(requireContext()) {
requestPermissions(arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION), PERMISSIONS_REQUEST_BACKGROUND_LOCATION)
}
} else {
requestingPermissions = BatteryOptimizationHelper().requestException(requireContext())
}
} else { } else {
sharedPreferences.edit().putBoolean(KEY_STATUS, false).apply() sharedPreferences.edit().putBoolean(KEY_STATUS, false).apply()
val preference = findPreference<TwoStatePreference>(KEY_STATUS) val preference = findPreference<TwoStatePreference>(KEY_STATUS)
@@ -234,7 +277,9 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
} }
private fun stopTrackingService() { private fun stopTrackingService() {
alarmManager.cancel(alarmIntent) if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
alarmManager.cancel(alarmIntent)
}
requireActivity().stopService(Intent(activity, TrackingService::class.java)) requireActivity().stopService(Intent(activity, TrackingService::class.java))
setPreferencesEnabled(true) setPreferencesEnabled(true)
} }
@@ -278,6 +323,7 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
const val KEY_BUFFER = "buffer" const val KEY_BUFFER = "buffer"
const val KEY_WAKELOCK = "wakelock" const val KEY_WAKELOCK = "wakelock"
private const val PERMISSIONS_REQUEST_LOCATION = 2 private const val PERMISSIONS_REQUEST_LOCATION = 2
private const val PERMISSIONS_REQUEST_BACKGROUND_LOCATION = 3
} }
} }
+4 -4
Просмотреть файл
@@ -104,8 +104,8 @@ class TrackingController(private val context: Context) : PositionListener, Netwo
private fun write(position: Position) { private fun write(position: Position) {
log("write", position) log("write", position)
databaseHelper.insertPositionAsync(position, object : DatabaseHandler<Unit> { databaseHelper.insertPositionAsync(position, object : DatabaseHandler<Unit?> {
override fun onComplete(success: Boolean, result: Unit) { override fun onComplete(success: Boolean, result: Unit?) {
if (success) { if (success) {
if (isOnline && isWaiting) { if (isOnline && isWaiting) {
read() read()
@@ -139,8 +139,8 @@ class TrackingController(private val context: Context) : PositionListener, Netwo
private fun delete(position: Position) { private fun delete(position: Position) {
log("delete", position) log("delete", position)
databaseHelper.deletePositionAsync(position.id, object : DatabaseHandler<Unit> { databaseHelper.deletePositionAsync(position.id, object : DatabaseHandler<Unit?> {
override fun onComplete(success: Boolean, result: Unit) { override fun onComplete(success: Boolean, result: Unit?) {
if (success) { if (success) {
read() read()
} else { } else {
+10 -6
Просмотреть файл
@@ -49,7 +49,7 @@ class TrackingService : Service() {
stopForeground(true) stopForeground(true)
} }
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
stopSelfResult(startId) stopSelfResult(startId)
return START_NOT_STICKY return START_NOT_STICKY
} }
@@ -57,11 +57,10 @@ class TrackingService : Service() {
@SuppressLint("WakelockTimeout") @SuppressLint("WakelockTimeout")
override fun onCreate() { override fun onCreate() {
startForeground(NOTIFICATION_ID, createNotification(this))
Log.i(TAG, "service create") Log.i(TAG, "service create")
sendBroadcast(Intent(ACTION_STARTED)) sendBroadcast(Intent(ACTION_STARTED))
StatusActivity.addMessage(getString(R.string.status_service_create)) StatusActivity.addMessage(getString(R.string.status_service_create))
startForeground(NOTIFICATION_ID, createNotification(this))
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) { if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(MainFragment.KEY_WAKELOCK, true)) { if (PreferenceManager.getDefaultSharedPreferences(this).getBoolean(MainFragment.KEY_WAKELOCK, true)) {
@@ -83,16 +82,16 @@ class TrackingService : Service() {
} }
@TargetApi(Build.VERSION_CODES.ECLAIR) @TargetApi(Build.VERSION_CODES.ECLAIR)
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int { override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
WakefulBroadcastReceiver.completeWakefulIntent(intent) WakefulBroadcastReceiver.completeWakefulIntent(intent)
return START_STICKY return START_STICKY
} }
override fun onDestroy() { override fun onDestroy() {
stopForeground(true)
Log.i(TAG, "service destroy") Log.i(TAG, "service destroy")
sendBroadcast(Intent(ACTION_STOPPED)) sendBroadcast(Intent(ACTION_STOPPED))
StatusActivity.addMessage(getString(R.string.status_service_destroy)) StatusActivity.addMessage(getString(R.string.status_service_destroy))
stopForeground(true)
if (wakeLock?.isHeld == true) { if (wakeLock?.isHeld == true) {
wakeLock?.release() wakeLock?.release()
} }
@@ -122,7 +121,12 @@ class TrackingService : Service() {
} else { } else {
intent = Intent(Settings.ACTION_SETTINGS) intent = Intent(Settings.ACTION_SETTINGS)
} }
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, 0)) val flags = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}
builder.setContentIntent(PendingIntent.getActivity(context, 0, intent, flags))
return builder.build() return builder.build()
} }
} }
+2 -2
Просмотреть файл
@@ -51,8 +51,8 @@ abstract class WakefulBroadcastReceiver : BroadcastReceiver() {
} }
} }
fun completeWakefulIntent(intent: Intent): Boolean { fun completeWakefulIntent(intent: Intent?): Boolean {
val id = intent.getIntExtra(EXTRA_WAKE_LOCK_ID, 0) val id = intent?.getIntExtra(EXTRA_WAKE_LOCK_ID, 0) ?: 0
if (id == 0) { if (id == 0) {
return false return false
} }
+5
Просмотреть файл
@@ -8,4 +8,9 @@
android:title="@string/menu_status" android:title="@string/menu_status"
app:showAsAction="ifRoom" /> app:showAsAction="ifRoom" />
<item
android:id="@+id/info"
android:title="@string/menu_info"
app:showAsAction="ifRoom" />
</menu> </menu>
+4
Просмотреть файл
@@ -34,6 +34,7 @@
<string name="settings_foreground_title">Foreground service</string> <string name="settings_foreground_title">Foreground service</string>
<string name="settings_foreground_summary">Increase service priority</string> <string name="settings_foreground_summary">Increase service priority</string>
<string name="menu_status">Status</string> <string name="menu_status">Status</string>
<string name="menu_info">Info</string>
<string name="menu_shortcuts">Add shortcuts</string> <string name="menu_shortcuts">Add shortcuts</string>
<string name="menu_clear">Clear</string> <string name="menu_clear">Clear</string>
<string name="status_service_create">Service started</string> <string name="status_service_create">Service started</string>
@@ -46,4 +47,7 @@
<string name="hidden_app_name">Device Settings</string> <string name="hidden_app_name">Device Settings</string>
<string name="hidden_alert">The app has been hidden. To open it again please dial 8722227 (TRACCAR).</string> <string name="hidden_alert">The app has been hidden. To open it again please dial 8722227 (TRACCAR).</string>
<string name="error_msg_invalid_url">Please enter a valid http:// or https:// URL</string> <string name="error_msg_invalid_url">Please enter a valid http:// or https:// URL</string>
<string name="request_exception">To continuously collect location data please turn off battery optimization for the app.</string>
<string name="request_background">To continuously collect location data please enable \"%s\" permission.</string>
<string name="request_background_option">Allow all the time</string>
</resources> </resources>
+6 -1
Просмотреть файл
@@ -1,4 +1,9 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<network-security-config> <network-security-config>
<base-config cleartextTrafficPermitted="true" /> <base-config cleartextTrafficPermitted="true">
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config> </network-security-config>
+5 -4
Просмотреть файл
@@ -1,13 +1,13 @@
buildscript { buildscript {
ext.kotlin_version = '1.5.21' ext.kotlin_version = '1.5.31'
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.0.0-beta05' classpath 'com.android.tools.build:gradle:7.0.3'
classpath 'com.google.gms:google-services:4.3.8' classpath 'com.google.gms:google-services:4.3.10'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.7.1' classpath 'com.google.firebase:firebase-crashlytics-gradle:2.8.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
} }
} }
@@ -16,5 +16,6 @@ allprojects {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
maven { url 'https://jitpack.io' }
} }
} }