Сравнить коммиты
| Автор | SHA1 | Дата | |
|---|---|---|---|
|
|
5f059645a1 | ||
|
|
8b985526dd | ||
|
|
5e8ea134e0 | ||
|
|
ec85edd56f | ||
|
|
c5ab10919e | ||
|
|
3e8ba9a603 | ||
|
|
826d638ea3 | ||
|
|
1b687bd075 | ||
|
|
42d5584d8d | ||
|
|
ff88682e40 | ||
|
|
307e692459 | ||
|
|
b7ec644ecf | ||
|
|
842baa2aec | ||
|
|
26bc92cf8e | ||
|
|
6dadf5e7c3 | ||
|
|
39e9c171c4 | ||
|
|
bcb5985cef | ||
|
|
eb868056bf | ||
|
|
94e094e648 | ||
|
|
25c0434e4c | ||
|
|
3afcfa17d0 | ||
|
|
02263d5fd9 | ||
|
|
a884b2f3d7 | ||
|
|
6910790fa7 | ||
|
|
6cab1a0b36 | ||
|
|
edd4f670fe |
+26
-24
@@ -2,29 +2,23 @@ apply plugin: 'com.android.application'
|
|||||||
apply plugin: 'kotlin-android'
|
apply plugin: 'kotlin-android'
|
||||||
|
|
||||||
android {
|
android {
|
||||||
compileSdkVersion 30
|
compileSdkVersion 32
|
||||||
|
|
||||||
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 32
|
||||||
versionCode 69
|
versionCode 78
|
||||||
versionName '6.8'
|
versionName '6.17'
|
||||||
multiDexEnabled true
|
multiDexEnabled true
|
||||||
}
|
}
|
||||||
|
namespace 'org.traccar.client'
|
||||||
compileOptions {
|
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
|
||||||
targetCompatibility JavaVersion.VERSION_1_8
|
|
||||||
}
|
|
||||||
|
|
||||||
packagingOptions {
|
packagingOptions {
|
||||||
exclude 'META-INF/DEPENDENCIES'
|
resources {
|
||||||
}
|
excludes += ['META-INF/DEPENDENCIES']
|
||||||
|
}
|
||||||
lintOptions {
|
|
||||||
checkReleaseBuilds false
|
|
||||||
}
|
}
|
||||||
|
|
||||||
flavorDimensions 'default'
|
flavorDimensions 'default'
|
||||||
@@ -44,22 +38,30 @@ android {
|
|||||||
includeAndroidResources = true
|
includeAndroidResources = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
lint {
|
||||||
|
checkReleaseBuilds false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation 'com.google.android.material:material:1.5.0-alpha01'
|
implementation 'com.google.android.material:material:1.6.0'
|
||||||
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.2.0'
|
||||||
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:19.0.1'
|
||||||
|
googleImplementation 'com.google.android.play:core:1.10.3'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getGradle().getStartParameter().getTaskRequests().toString().contains('Google')) {
|
if (getGradle().getStartParameter().getTaskRequests().toString().contains('Google')) {
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest
|
<manifest
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
package="org.traccar.client">
|
|
||||||
|
|
||||||
<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 +13,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" />
|
||||||
|
|
||||||
@@ -23,7 +26,7 @@
|
|||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
android:name=".MainApplication"
|
android:name=".MainApplication"
|
||||||
tools:ignore="GoogleAppIndexingWarning">
|
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">
|
||||||
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="google_analytics_adid_collection_enabled"
|
android:name="google_analytics_adid_collection_enabled"
|
||||||
@@ -31,10 +34,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 +50,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 +66,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>
|
||||||
|
|||||||
@@ -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"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org)
|
* Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org)
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
@@ -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?) {
|
||||||
@@ -60,7 +62,7 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
|
|||||||
removeLauncherIcon()
|
removeLauncherIcon()
|
||||||
}
|
}
|
||||||
setHasOptionsMenu(true)
|
setHasOptionsMenu(true)
|
||||||
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context)
|
sharedPreferences = PreferenceManager.getDefaultSharedPreferences(requireContext())
|
||||||
setPreferencesFromResource(R.xml.preferences, rootKey)
|
setPreferencesFromResource(R.xml.preferences, rootKey)
|
||||||
initPreferences()
|
initPreferences()
|
||||||
|
|
||||||
@@ -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)
|
||||||
}
|
}
|
||||||
@@ -115,6 +126,7 @@ class MainFragment : PreferenceFragmentCompat(), OnSharedPreferenceChangeListene
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("DEPRECATION")
|
||||||
override fun onDisplayPreferenceDialog(preference: Preference) {
|
override fun onDisplayPreferenceDialog(preference: Preference) {
|
||||||
if (listOf(KEY_INTERVAL, KEY_DISTANCE, KEY_ANGLE).contains(preference.key)) {
|
if (listOf(KEY_INTERVAL, KEY_DISTANCE, KEY_ANGLE).contains(preference.key)) {
|
||||||
val f: EditTextPreferenceDialogFragmentCompat =
|
val f: EditTextPreferenceDialogFragmentCompat =
|
||||||
@@ -144,6 +156,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,12 +206,15 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initPreferences() {
|
private fun initPreferences() {
|
||||||
PreferenceManager.setDefaultValues(activity, R.xml.preferences, false)
|
PreferenceManager.setDefaultValues(requireActivity(), R.xml.preferences, false)
|
||||||
if (!sharedPreferences.contains(KEY_DEVICE)) {
|
if (!sharedPreferences.contains(KEY_DEVICE)) {
|
||||||
val id = (Random().nextInt(900000) + 100000).toString()
|
val id = (Random().nextInt(900000) + 100000).toString()
|
||||||
sharedPreferences.edit().putString(KEY_DEVICE, id).apply()
|
sharedPreferences.edit().putString(KEY_DEVICE, id).apply()
|
||||||
@@ -201,6 +223,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 +246,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 +254,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 +278,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 +324,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
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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.6.10'
|
||||||
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.2.1'
|
||||||
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.9.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' }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -2,4 +2,4 @@ distributionBase=GRADLE_USER_HOME
|
|||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user