Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">

<!-- Permissions -->
<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_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_LOCATION" />
<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.gps" />

<application
android:allowBackup="true"
android:networkSecurityConfig="@xml/network_security_config"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
android:name=".MainApplication"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute">

<meta-data
android:name="google_analytics_adid_collection_enabled"
android:value="false" />

<!-- MainActivity: legg til intent-filter her -->
<activity
android:name=".MainActivity"
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="traccar" android:host="config" />
</intent-filter>
</activity>

<activity-alias
android:name=".Launcher"
android:exported="true"
android:targetActivity=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.shortcuts"
android:resource="@xml/shortcuts" />
</activity-alias>

<activity
android:name=".StatusActivity"
android:exported="false" />

<activity
android:name=".ShortcutActivity"
android:exported="true"
android:label="@string/menu_shortcuts">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.CREATE_SHORTCUT" />
</intent-filter>
</activity>

<service
android:name=".TrackingService"
android:exported="false"
android:foregroundServiceType="location" />

<receiver
android:name=".AutostartReceiver"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>

<receiver
android:name=".StatusWidget"
android:label="@string/widget_label"
android:exported="true">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="org.traccar.action.SERVICE_STARTED" />
<action android:name="org.traccar.action.SERVICE_STOPPED" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/status_widget_info" />
</receiver>
<receiver android:name=".TrackingSchedulerReceiver" />
</application>
</manifest>
122 changes: 122 additions & 0 deletions MainActivity.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
/*
* Copyright 2017 - 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.util.Log
import android.content.Intent
import android.os.Bundle
import android.preference.PreferenceManager
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import android.app.AlarmManager
import android.app.PendingIntent
import java.util.Calendar
import android.content.Context
import android.content.SharedPreferences


class MainActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
handleDeepLink(intent)
setContentView(R.layout.main)
}

override fun onNewIntent(intent: Intent) {
super.onNewIntent(intent)
handleDeepLink(intent)
}

private fun handleDeepLink(intent: Intent) {
val uri = intent.data ?: return
if (uri.scheme == "traccar" && uri.host == "config") {
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
prefs.edit().apply {
uri.getQueryParameter("deviceId")?.let { putString("id", it) }
uri.getQueryParameter("serverUrl")?.let { putString("url", it) }
uri.getQueryParameter("accuracy")?.let { putString("accuracy", it) }
uri.getQueryParameter("interval")?.let { putString("interval", it) }
uri.getQueryParameter("distance")?.let { putString("distance", it) }
uri.getQueryParameter("angle")?.let { putString("angle", it) }
uri.getQueryParameter("startTime")?.let { putString("startTime", it) }
uri.getQueryParameter("stopTime")?.let { putString("stopTime", it) }
apply()
}
scheduleTrackingFromPreferences()
val serviceOn = uri.getQueryParameter("service") == "true"
if (serviceOn) {
ContextCompat.startForegroundService(this, Intent(this, TrackingService::class.java))
} else {
stopService(Intent(this, TrackingService::class.java))
}

prefs.edit().putBoolean("status", serviceOn).apply()
val fragment = supportFragmentManager.findFragmentById(R.id.fragment)
if (fragment is MainFragment) {
fragment.updateStatusSwitch(serviceOn)
}
Toast.makeText(this, "Traccar konfigurert via QR", Toast.LENGTH_SHORT).show()
}
}
private fun scheduleTrackingFromPreferences() {
val prefs = PreferenceManager.getDefaultSharedPreferences(this)
val startTimeStr = prefs.getString("startTime", null)
val stopTimeStr = prefs.getString("stopTime", null)

val alarmManager = getSystemService(Context.ALARM_SERVICE) as android.app.AlarmManager

fun schedule(timeStr: String?, action: String) {
if (timeStr == null) return
val parts = timeStr.split(":")
if (parts.size != 2) return
val hour = parts[0].toIntOrNull() ?: return
val minute = parts[1].toIntOrNull() ?: return

val time = java.util.Calendar.getInstance().apply {
set(java.util.Calendar.HOUR_OF_DAY, hour)
set(java.util.Calendar.MINUTE, minute)
set(java.util.Calendar.SECOND, 0)
set(java.util.Calendar.MILLISECOND, 0)
if (before(java.util.Calendar.getInstance())) add(java.util.Calendar.DATE, 1)
}

val intent = Intent(this, TrackingSchedulerReceiver::class.java).apply {
this.action = action
}

val flags = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
} else {
PendingIntent.FLAG_UPDATE_CURRENT
}

val pendingIntent = PendingIntent.getBroadcast(this, action.hashCode(), intent, flags)

alarmManager.set(
android.app.AlarmManager.RTC_WAKEUP,
time.timeInMillis,
/*android.app.AlarmManager.INTERVAL_DAY,*/
pendingIntent
)
Log.i("TrackingScheduler", "Scheduled $action at $hour:$minute (${time.time})")
}

schedule(startTimeStr, "START_TRACKING")
schedule(stopTimeStr, "STOP_TRACKING")
}
}
22 changes: 22 additions & 0 deletions TrackingSchedulerReceiver.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package org.traccar.client

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import androidx.core.content.ContextCompat

class TrackingSchedulerReceiver : BroadcastReceiver() {

override fun onReceive(context: Context, intent: Intent) {
Log.i("TrackingScheduler", ">>> Received intent with action: ${intent.action}")
when (intent.action) {
"START_TRACKING" -> {
ContextCompat.startForegroundService(context, Intent(context, TrackingService::class.java))
}
"STOP_TRACKING" -> {
context.stopService(Intent(context, TrackingService::class.java))
}
}
}
}
66 changes: 66 additions & 0 deletions preferences.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

<SwitchPreferenceCompat
android:defaultValue="false"
android:key="status"
android:summaryOff="@string/settings_status_off_summary"
android:summaryOn="@string/settings_status_on_summary"
android:switchTextOff="@string/settings_status_off"
android:switchTextOn="@string/settings_status_on"
android:title="@string/settings_status_title" />

<EditTextPreference
android:key="id"
android:title="@string/settings_id_title" />

<EditTextPreference
android:defaultValue="@string/settings_url_default_value"
android:key="url"
android:summary="@string/settings_url_summary"
android:title="@string/settings_url_title" />

<ListPreference
android:defaultValue="medium"
android:entries="@array/settings_accuracy_names"
android:entryValues="@array/settings_accuracy_values"
android:key="accuracy"
android:summary="@string/settings_accuracy_summary"
android:title="@string/settings_accuracy_title" />

<EditTextPreference
android:defaultValue="300"
android:key="interval"
android:inputType="number"
android:summary="@string/settings_interval_summary"
android:title="@string/settings_interval_title" />

<EditTextPreference
android:defaultValue="0"
android:key="distance"
android:inputType="number"
android:summary="@string/settings_distance_summary"
android:title="@string/settings_distance_title" />

<EditTextPreference
android:defaultValue="0"
android:key="angle"
android:inputType="number"
android:summary="@string/settings_angle_summary"
android:title="@string/settings_angle_title" />

<CheckBoxPreference
android:defaultValue="true"
android:key="buffer"
android:summaryOff="@string/settings_buffer_off_summary"
android:summaryOn="@string/settings_buffer_on_summary"
android:title="@string/settings_buffer" />

<CheckBoxPreference
android:defaultValue="true"
android:key="wakelock"
android:summaryOff="@string/settings_wakelock_off_summary"
android:summaryOn="@string/settings_wakelock_on_summary"
android:title="@string/settings_wakelock" />

</PreferenceScreen>