diff --git a/android/app/build.gradle b/android/app/build.gradle
index 6215bc3..c30904e 100644
--- a/android/app/build.gradle
+++ b/android/app/build.gradle
@@ -81,6 +81,7 @@ dependencies {
implementation 'com.google.firebase:firebase-analytics:17.2.2'
implementation 'com.google.firebase:firebase-messaging:20.2.0'
implementation 'androidx.work:work-runtime:2.3.4'
+ implementation "androidx.concurrent:concurrent-futures:1.0.0"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 68d0b46..fb61996 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -72,7 +72,7 @@
-
+
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/Autostart.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/Autostart.java
deleted file mode 100644
index 739af96..0000000
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/Autostart.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package com.keyboardcrumbs.hassclient;
-
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.ServiceConnection;
-import android.os.Build;
-import android.os.IBinder;
-
-public class Autostart extends BroadcastReceiver {
-
- public void onReceive(Context context, Intent intent) {
- if (Utils.requestingLocationUpdates(context) && Intent.ACTION_BOOT_COMPLETED.equalsIgnoreCase(intent.getAction())) {
- Intent serviceIntent = new Intent(context, LocationUpdatesService.class);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- context.startForegroundService(serviceIntent);
- } else {
- context.startService(serviceIntent);
- }
- }
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesAfterReboot.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesAfterReboot.java
new file mode 100644
index 0000000..68029c1
--- /dev/null
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesAfterReboot.java
@@ -0,0 +1,14 @@
+package com.keyboardcrumbs.hassclient;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class LocationUpdatesAfterReboot extends BroadcastReceiver {
+
+ public void onReceive(Context context, Intent intent) {
+ if (LocationUtils.getLocationUpdatesState(context) == LocationUtils.LOCATION_UPDATES_SERVICE && Intent.ACTION_BOOT_COMPLETED.equalsIgnoreCase(intent.getAction())) {
+ LocationUtils.startServiceFromBroadcast(context);
+ }
+ }
+}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java
index 5c1a13b..728f436 100644
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java
@@ -7,7 +7,6 @@ import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
-import android.os.Binder;
import android.os.Build;
import android.os.Handler;
import android.os.HandlerThread;
@@ -78,9 +77,6 @@ public class LocationUpdatesService extends Service {
};
mLocationRequest = new LocationRequest();
- mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
-
- getLastLocation();
HandlerThread handlerThread = new HandlerThread(TAG);
handlerThread.start();
@@ -130,8 +126,10 @@ public class LocationUpdatesService extends Service {
}
private void requestLocationUpdates() {
- long requestInterval = Utils.getLocationUpdateIntervals(getApplicationContext());
- Log.i(TAG, "Requesting location updates. Interval is " + requestInterval);
+ long requestInterval = LocationUtils.getLocationUpdateIntervals(getApplicationContext());
+ int priority = LocationUtils.getLocationUpdatesPriority(getApplicationContext());
+ Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority);
+ mLocationRequest.setPriority(priority);
mLocationRequest.setInterval(requestInterval);
mLocationRequest.setFastestInterval(requestInterval);
startForeground(NOTIFICATION_ID, getNotification());
@@ -146,7 +144,7 @@ public class LocationUpdatesService extends Service {
private Notification getNotification() {
Intent intent = new Intent(this, LocationUpdatesService.class);
- CharSequence text = Utils.getLocationText(mLocation);
+ CharSequence text = LocationUtils.getLocationText(mLocation);
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
@@ -157,13 +155,13 @@ public class LocationUpdatesService extends Service {
new Intent(this, MainActivity.class), 0);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
- .addAction(R.drawable.blank_icon, "Open HA Client",
+ .addAction(R.drawable.blank_icon, "Open app",
activityPendingIntent)
- .addAction(R.drawable.blank_icon, "Stop",
+ .addAction(R.drawable.blank_icon, "Stop tracking",
servicePendingIntent)
.setContentText(text)
.setPriority(-1)
- .setContentTitle(Utils.getLocationTitle(mLocation))
+ .setContentTitle(LocationUtils.getLocationTitle(mLocation))
.setOngoing(true)
.setSmallIcon(R.drawable.mini_icon)
.setWhen(System.currentTimeMillis());
@@ -171,21 +169,6 @@ public class LocationUpdatesService extends Service {
return builder.build();
}
- private void getLastLocation() {
- try {
- mFusedLocationClient.getLastLocation()
- .addOnCompleteListener(task -> {
- if (task.isSuccessful() && task.getResult() != null) {
- mLocation = task.getResult();
- } else {
- Log.w(TAG, "Failed to get location.");
- }
- });
- } catch (SecurityException unlikely) {
- Log.e(TAG, "Lost location permission." + unlikely);
- }
- }
-
private void onNewLocation(Location location) {
Log.i(TAG, "New location: " + location);
@@ -198,6 +181,7 @@ public class LocationUpdatesService extends Service {
.build();
Data locationData = new Data.Builder()
+ .putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_LOCATION)
.putDouble("Lat", mLocation.getLatitude())
.putDouble("Long", mLocation.getLongitude())
.putFloat("Acc", mLocation.getAccuracy())
@@ -205,7 +189,7 @@ public class LocationUpdatesService extends Service {
OneTimeWorkRequest uploadWorkRequest =
- new OneTimeWorkRequest.Builder(SendLocationWorker.class)
+ new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
10,
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java
new file mode 100644
index 0000000..5de1fdd
--- /dev/null
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java
@@ -0,0 +1,100 @@
+package com.keyboardcrumbs.hassclient;
+
+import android.content.Context;
+import android.location.Location;
+import android.os.Looper;
+
+import androidx.annotation.NonNull;
+import androidx.concurrent.futures.CallbackToFutureAdapter;
+import androidx.work.BackoffPolicy;
+import androidx.work.Constraints;
+import androidx.work.Data;
+import androidx.work.ExistingWorkPolicy;
+import androidx.work.ListenableWorker;
+import androidx.work.NetworkType;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
+import androidx.work.WorkerParameters;
+
+import com.google.android.gms.location.FusedLocationProviderClient;
+import com.google.android.gms.location.LocationCallback;
+import com.google.android.gms.location.LocationRequest;
+import com.google.android.gms.location.LocationResult;
+import com.google.android.gms.location.LocationServices;
+import com.google.common.util.concurrent.ListenableFuture;
+
+import java.util.concurrent.TimeUnit;
+
+public class LocationUpdatesWorker extends ListenableWorker {
+
+ private Context currentContext;
+ private LocationCallback callback;
+ private FusedLocationProviderClient fusedLocationClient;
+
+ public LocationUpdatesWorker(Context context, WorkerParameters params) {
+ super(context, params);
+ currentContext = context;
+ }
+
+ private void finish() {
+ fusedLocationClient.removeLocationUpdates(callback);
+ }
+
+
+
+ @NonNull
+ @Override
+ public ListenableFuture startWork() {
+ return CallbackToFutureAdapter.getFuture(completer -> {
+ fusedLocationClient = LocationServices.getFusedLocationProviderClient(currentContext);
+
+ callback = new LocationCallback() {
+ @Override
+ public void onLocationResult(LocationResult locationResult) {
+ super.onLocationResult(locationResult);
+ Location location = locationResult.getLastLocation();
+ Constraints constraints = new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build();
+
+ Data locationData = new Data.Builder()
+ .putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_LOCATION)
+ .putDouble("Lat", location.getLatitude())
+ .putDouble("Long", location.getLongitude())
+ .putFloat("Acc", location.getAccuracy())
+ .build();
+
+
+ OneTimeWorkRequest uploadWorkRequest =
+ new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
+ .setBackoffCriteria(
+ BackoffPolicy.EXPONENTIAL,
+ 10,
+ TimeUnit.SECONDS)
+ .setConstraints(constraints)
+ .setInputData(locationData)
+ .build();
+
+ WorkManager
+ .getInstance(getApplicationContext())
+ .enqueueUniqueWork("SendLocationUpdate", ExistingWorkPolicy.REPLACE, uploadWorkRequest);
+ finish();
+ completer.set(Result.success());
+ }
+ };
+
+ LocationRequest locationRequest = new LocationRequest();
+ int accuracy = LocationUtils.getLocationUpdatesPriority(getApplicationContext());
+ locationRequest.setPriority(accuracy);
+ locationRequest.setInterval(5000);
+ locationRequest.setFastestInterval(1000);
+ try {
+ fusedLocationClient.requestLocationUpdates(locationRequest,
+ callback, Looper.myLooper());
+ } catch (SecurityException e) {
+ completer.setException(e);
+ }
+ return callback;
+ });
+ }
+}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java
new file mode 100644
index 0000000..af028a8
--- /dev/null
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java
@@ -0,0 +1,78 @@
+package com.keyboardcrumbs.hassclient;
+
+import android.content.Context;
+import android.content.Intent;
+import android.location.Location;
+import android.os.Build;
+
+import androidx.work.ExistingPeriodicWorkPolicy;
+import androidx.work.PeriodicWorkRequest;
+import androidx.work.WorkManager;
+
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.concurrent.TimeUnit;
+
+class LocationUtils {
+
+ static final String KEY_REQUESTING_LOCATION_UPDATES = "flutter.location-updates-state";
+ static final String KEY_LOCATION_UPDATE_INTERVAL = "flutter.location-updates-interval";
+ static final String KEY_LOCATION_UPDATE_PRIORITY = "flutter.location-updates-priority";
+
+ static final String LOCATION_WORK_NAME = "HALocationWorker";
+
+ static final int LOCATION_UPDATES_DISABLED = 0;
+ static final int LOCATION_UPDATES_SERVICE = 1;
+ static final int LOCATION_UPDATES_WORKER = 2;
+
+ static final int DEFAULT_LOCATION_UPDATE_INTERVAL_S = 900; //15 minutes
+ static final long MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS = 900000; //15 minutes
+
+ static int getLocationUpdatesState(Context context) {
+ return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_REQUESTING_LOCATION_UPDATES, LOCATION_UPDATES_DISABLED);
+ }
+
+ static long getLocationUpdateIntervals(Context context) {
+ return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_LOCATION_UPDATE_INTERVAL, DEFAULT_LOCATION_UPDATE_INTERVAL_S) * 1000;
+ }
+
+ static int getLocationUpdatesPriority(Context context) {
+ return (int) context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_LOCATION_UPDATE_PRIORITY, 102);
+ }
+
+ static void setLocationUpdatesState(Context context, int locationUpdatesState) {
+ context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
+ .edit()
+ .putInt(KEY_REQUESTING_LOCATION_UPDATES, locationUpdatesState)
+ .apply();
+ }
+
+ static String getLocationText(Location location) {
+ return location == null ? "Accuracy: unknown" :
+ "Accuracy: " + location.getAccuracy();
+ }
+
+ static String getLocationTitle(Location location) {
+ return location == null ? "Requesting location..." : "Location updated at " + DateFormat.getDateTimeInstance().format(new Date(location.getTime()));
+ }
+
+ static void startService(Context context) {
+ Intent myService = new Intent(context, LocationUpdatesService.class);
+ context.startService(myService);
+ }
+
+ static void startServiceFromBroadcast(Context context) {
+ Intent serviceIntent = new Intent(context, LocationUpdatesService.class);
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ context.startForegroundService(serviceIntent);
+ } else {
+ context.startService(serviceIntent);
+ }
+ }
+
+ static void startWorker(Context context, long interval) {
+ PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(LocationUpdatesWorker.class, interval, TimeUnit.MILLISECONDS)
+ .build();
+ WorkManager.getInstance(context).enqueueUniquePeriodicWork(LocationUtils.LOCATION_WORK_NAME, ExistingPeriodicWorkPolicy.REPLACE, periodicWork);
+ }
+}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java
index 2a3edfe..e106f7c 100644
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java
@@ -2,24 +2,19 @@ package com.keyboardcrumbs.hassclient;
import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
-import androidx.localbroadcastmanager.content.LocalBroadcastManager;
+import androidx.work.WorkManager;
import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;
import android.Manifest;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.ServiceConnection;
+import android.content.SharedPreferences;
import android.content.pm.PackageManager;
-import android.location.Location;
import android.os.Bundle;
-import android.os.IBinder;
import io.flutter.plugin.common.MethodChannel;
@@ -33,6 +28,9 @@ public class MainActivity extends FlutterActivity {
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
+ private int locationUpdatesType = LocationUtils.LOCATION_UPDATES_DISABLED;
+ private long locationUpdatesInterval = LocationUtils.DEFAULT_LOCATION_UPDATE_INTERVAL_S * 1000;
+
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
@@ -46,8 +44,7 @@ public class MainActivity extends FlutterActivity {
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
String token = task.getResult().getToken();
- UpdateTokenTask updateTokenTask = new UpdateTokenTask(context);
- updateTokenTask.execute(token);
+ context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).edit().putString("flutter.npush-token", token).apply();
result.success(token);
} else {
Exception ex = task.getException();
@@ -64,17 +61,25 @@ public class MainActivity extends FlutterActivity {
}
break;
case "startLocationService":
- Utils.setRequestingLocationUpdates(this, true);
- if (isNoLocationPermissions()) {
- requestLocationPermissions();
- } else {
- startLocationService();
+ try {
+ locationUpdatesInterval = LocationUtils.getLocationUpdateIntervals(this);
+ if (locationUpdatesInterval >= LocationUtils.MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS) {
+ locationUpdatesType = LocationUtils.LOCATION_UPDATES_WORKER;
+ } else {
+ locationUpdatesType = LocationUtils.LOCATION_UPDATES_SERVICE;
+ }
+ if (isNoLocationPermissions()) {
+ requestLocationPermissions();
+ } else {
+ startLocationUpdates();
+ }
+ result.success("");
+ } catch (Exception e) {
+ result.error("location_error", e.getMessage(), null);
}
- result.success("");
break;
case "stopLocationService":
- Utils.setRequestingLocationUpdates(this, false);
- stopLocationService();
+ stopLocationUpdates();
result.success("");
break;
}
@@ -86,24 +91,28 @@ public class MainActivity extends FlutterActivity {
return (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS);
}
- private void startLocationService() {
- Intent myService = new Intent(MainActivity.this, LocationUpdatesService.class);
- startService(myService);
+ private void startLocationUpdates() {
+ if (locationUpdatesType == LocationUtils.LOCATION_UPDATES_SERVICE) {
+ LocationUtils.startService(this);
+ LocationUtils.setLocationUpdatesState(this, locationUpdatesType);
+ } else if (locationUpdatesType == LocationUtils.LOCATION_UPDATES_WORKER) {
+ LocationUtils.startWorker(this, locationUpdatesInterval);
+ LocationUtils.setLocationUpdatesState(this, locationUpdatesType);
+ } else {
+ stopLocationUpdates();
+ }
}
- private void stopLocationService() {
+ private void stopLocationUpdates() {
Intent myService = new Intent(MainActivity.this, LocationUpdatesService.class);
stopService(myService);
+ WorkManager.getInstance(this).cancelUniqueWork(LocationUtils.LOCATION_WORK_NAME);
+ LocationUtils.setLocationUpdatesState(this, LocationUtils.LOCATION_UPDATES_DISABLED);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- /*if (Utils.requestingLocationUpdates(this)) {
- if (isNoLocationPermissions()) {
- requestLocationPermissions();
- }
- }*/
}
@Override
@@ -142,7 +151,9 @@ public class MainActivity extends FlutterActivity {
@NonNull int[] grantResults) {
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
- startLocationService();
+ startLocationUpdates();
+ } else {
+ stopLocationUpdates();
}
}
}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java
index b4376bb..525588d 100644
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java
@@ -3,7 +3,6 @@ package com.keyboardcrumbs.hassclient;
import java.util.Map;
import java.net.URL;
import java.net.URLConnection;
-import java.io.IOException;
import java.io.InputStream;
import android.app.NotificationChannel;
@@ -14,6 +13,8 @@ import android.content.Intent;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.Build;
+
+import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import com.google.firebase.messaging.FirebaseMessagingService;
@@ -26,7 +27,7 @@ import android.webkit.URLUtil;
public class MessagingService extends FirebaseMessagingService {
- private static final String TAG = "MessagingService";
+ public static final String NOTIFICATION_ACTION_BROADCAST = "com.keyboardcrumbs.hassclient.haNotificationAction";
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
@@ -39,19 +40,19 @@ public class MessagingService extends FirebaseMessagingService {
}
@Override
- public void onNewToken(String token) {
- UpdateTokenTask updateTokenTask = new UpdateTokenTask(this);
- updateTokenTask.execute(token);
+ public void onNewToken(@NonNull String token) {
+ getApplicationContext().getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).edit().putString("flutter.npush-token", token).apply();
}
private void sendNotification(Map data) {
String channelId, messageBody, messageTitle, imageUrl, nTag, channelDescription;
boolean autoCancel;
- if (!data.containsKey("channelId")) {
+ String customChannelId = data.get("channelId");
+ if (customChannelId == null) {
channelId = "ha_notify";
channelDescription = "Default notification channel";
} else {
- channelId = data.get("channelId");
+ channelId = customChannelId;
channelDescription = channelId;
}
if (!data.containsKey("body")) {
@@ -114,7 +115,7 @@ public class MessagingService extends FirebaseMessagingService {
}
for (int i = 1; i <= 3; i++) {
if (data.containsKey("action" + i)) {
- Intent broadcastIntent = new Intent(this, NotificationActionReceiver.class);
+ Intent broadcastIntent = new Intent(this, NotificationActionReceiver.class).setAction(NOTIFICATION_ACTION_BROADCAST);
if (autoCancel) {
broadcastIntent.putExtra("tag", nTag);
}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/NextAlarmBroadcastReceiver.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/NextAlarmBroadcastReceiver.java
index 36b4729..1deef0a 100644
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/NextAlarmBroadcastReceiver.java
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/NextAlarmBroadcastReceiver.java
@@ -7,19 +7,17 @@ import android.content.Intent;
import androidx.work.BackoffPolicy;
import androidx.work.Constraints;
+import androidx.work.Data;
import androidx.work.ExistingWorkPolicy;
import androidx.work.NetworkType;
import androidx.work.OneTimeWorkRequest;
import androidx.work.WorkManager;
-import androidx.work.WorkRequest;
import java.util.concurrent.TimeUnit;
public class NextAlarmBroadcastReceiver extends BroadcastReceiver {
- private static final String TAG = "NextAlarmReceiver";
-
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
@@ -35,12 +33,17 @@ public class NextAlarmBroadcastReceiver extends BroadcastReceiver {
.setRequiredNetworkType(NetworkType.CONNECTED)
.build();
+ Data workerData = new Data.Builder()
+ .putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_NEXT_ALARM)
+ .build();
+
OneTimeWorkRequest uploadWorkRequest =
- new OneTimeWorkRequest.Builder(UpdateNextAlarmWorker.class)
+ new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
.setBackoffCriteria(
BackoffPolicy.EXPONENTIAL,
10,
TimeUnit.SECONDS)
+ .setInputData(workerData)
.setConstraints(constraints)
.build();
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/NotificationActionReceiver.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/NotificationActionReceiver.java
index 8c2e266..294e614 100644
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/NotificationActionReceiver.java
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/NotificationActionReceiver.java
@@ -1,73 +1,58 @@
package com.keyboardcrumbs.hassclient;
-import android.app.AlarmManager;
import android.content.Context;
-import android.util.Log;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.app.NotificationManager;
-import android.webkit.URLUtil;
+import androidx.work.BackoffPolicy;
+import androidx.work.Constraints;
+import androidx.work.Data;
+import androidx.work.ExistingWorkPolicy;
+import androidx.work.NetworkType;
+import androidx.work.OneTimeWorkRequest;
+import androidx.work.WorkManager;
-import org.json.JSONObject;
-import android.content.SharedPreferences;
+import java.util.concurrent.TimeUnit;
public class NotificationActionReceiver extends BroadcastReceiver {
- private static final String TAG = "NotificationAction";
-
@Override
public void onReceive(Context context, Intent intent) {
if (intent == null) {
return;
}
-
+ String intentAction = intent.getAction();
+ if (intentAction == null || !intentAction.equalsIgnoreCase(MessagingService.NOTIFICATION_ACTION_BROADCAST)) {
+ return;
+ }
String rawActionData = intent.getStringExtra("actionData");
if (intent.hasExtra("tag")) {
String notificationTag = intent.getStringExtra("tag");
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(notificationTag, 0);
}
- SharedPreferences prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
- String webhookId = prefs.getString("flutter.app-webhook-id", null);
- if (webhookId != null) {
- try {
- String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
- "://" +
- prefs.getString("flutter.hassio-domain", "") +
- ":" +
- prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
- JSONObject actionData = new JSONObject(rawActionData);
- if (URLUtil.isValidUrl(requestUrl)) {
- JSONObject dataToSend = new JSONObject();
- JSONObject requestData = new JSONObject();
- if (actionData.getString("action").equals("call-service")) {
- dataToSend.put("type", "call_service");
- requestData.put("domain", actionData.getString("service").split("\\.")[0]);
- requestData.put("service", actionData.getString("service").split("\\.")[1]);
- if (actionData.has("service_data")) {
- requestData.put("service_data", actionData.get("service_data"));
- }
- } else {
- dataToSend.put("type", "fire_event");
- requestData.put("event_type", "ha_client_event");
- JSONObject eventData = new JSONObject();
- eventData.put("action", actionData.getString("action"));
- requestData.put("event_data", eventData);
- }
- dataToSend.put("data", requestData);
- String stringRequest = dataToSend.toString();
- SendTask sendTask = new SendTask();
- sendTask.execute(requestUrl, stringRequest);
- } else {
- Log.w(TAG, "Invalid HA url");
- }
- } catch (Exception e) {
- Log.e(TAG, "Error handling notification action", e);
- }
- } else {
- Log.w(TAG, "Webhook id not found");
- }
+ Constraints constraints = new Constraints.Builder()
+ .setRequiredNetworkType(NetworkType.CONNECTED)
+ .build();
+ Data workerData = new Data.Builder()
+ .putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_NOTIFICATION_ACTION)
+ .putString("rawActionData", rawActionData)
+ .build();
+
+ OneTimeWorkRequest uploadWorkRequest =
+ new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
+ .setBackoffCriteria(
+ BackoffPolicy.EXPONENTIAL,
+ 10,
+ TimeUnit.SECONDS)
+ .setInputData(workerData)
+ .setConstraints(constraints)
+ .build();
+
+ WorkManager
+ .getInstance(context)
+ .enqueueUniqueWork("NotificationAction", ExistingWorkPolicy.APPEND, uploadWorkRequest);
}
}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendDataHomeWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendDataHomeWorker.java
new file mode 100644
index 0000000..e9a5b1d
--- /dev/null
+++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendDataHomeWorker.java
@@ -0,0 +1,218 @@
+package com.keyboardcrumbs.hassclient;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.os.BatteryManager;
+import android.util.Log;
+import android.webkit.URLUtil;
+
+import androidx.annotation.NonNull;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+
+import org.json.JSONArray;
+import org.json.JSONObject;
+
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Locale;
+
+public class SendDataHomeWorker extends Worker {
+ public static final String DATA_TYPE_KEY = "dataType";
+
+ public static final int DATA_TYPE_LOCATION = 1;
+ public static final int DATA_TYPE_NEXT_ALARM = 2;
+ public static final int DATA_TYPE_NOTIFICATION_ACTION = 3;
+
+ private Context currentContext;
+ private static final String TAG = "SendDataHomeWorker";
+
+ public static final String KEY_LAT_ARG = "Lat";
+ public static final String KEY_LONG_ARG = "Long";
+ public static final String KEY_ACC_ARG = "Acc";
+
+ private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:00", Locale.ENGLISH);
+ private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
+ private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:00", Locale.ENGLISH);
+
+ public SendDataHomeWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
+ super(context, workerParams);
+ currentContext = context;
+ }
+
+ @NonNull
+ @Override
+ public Result doWork() {
+ Log.d(TAG, "Start sending data home");
+ SharedPreferences prefs = currentContext.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
+ String webhookId = prefs.getString("flutter.app-webhook-id", null);
+ if (webhookId != null) {
+ try {
+ String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
+ "://" +
+ prefs.getString("flutter.hassio-domain", "") +
+ ":" +
+ prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
+ if (URLUtil.isValidUrl(requestUrl)) {
+ int dataType = getInputData().getInt(DATA_TYPE_KEY, 0);
+ String stringRequest;
+ if (dataType == DATA_TYPE_LOCATION) {
+ Log.d(TAG, "Location data");
+ stringRequest = getLocationDataToSend();
+ } else if (dataType == DATA_TYPE_NEXT_ALARM) {
+ Log.d(TAG, "Next alarm data");
+ stringRequest = getNextAlarmDataToSend();
+ } else if (dataType == DATA_TYPE_NOTIFICATION_ACTION) {
+ Log.d(TAG, "Notification action data");
+ stringRequest = getNotificationActionData();
+ } else {
+ Log.e(TAG, "doWork() unknown data type: " + dataType);
+ return Result.failure();
+ }
+ try {
+ URL url = new URL(requestUrl);
+ HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
+ urlConnection.setRequestMethod("POST");
+ urlConnection.setRequestProperty("Content-Type", "application/json");
+ urlConnection.setDoOutput(true);
+ assert stringRequest != null;
+ byte[] outputBytes = stringRequest.getBytes(StandardCharsets.UTF_8);
+ OutputStream os = urlConnection.getOutputStream();
+ os.write(outputBytes);
+
+ int responseCode = urlConnection.getResponseCode();
+ urlConnection.disconnect();
+ if (responseCode >= 300) {
+ return Result.retry();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error sending data", e);
+ return Result.retry();
+ }
+ } else {
+ Log.w(TAG, "Invalid HA url");
+ return Result.failure();
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Error =(", e);
+ return Result.failure();
+ }
+ } else {
+ Log.w(TAG, "Webhook id not found");
+ return Result.failure();
+ }
+ return Result.success();
+ }
+
+ private String getLocationDataToSend() {
+ try {
+ JSONObject dataToSend = new JSONObject();
+ dataToSend.put("type", "update_location");
+ JSONObject dataObject = new JSONObject();
+
+ JSONArray gps = new JSONArray();
+ gps.put(0, getInputData().getDouble(KEY_LAT_ARG, 0));
+ gps.put(1, getInputData().getDouble(KEY_LONG_ARG, 0));
+
+ dataObject.put("gps", gps);
+ dataObject.put("gps_accuracy", getInputData().getFloat(KEY_ACC_ARG, 0));
+
+ BatteryManager bm;
+ if (android.os.Build.VERSION.SDK_INT >= 23) {
+ bm = currentContext.getSystemService(BatteryManager.class);
+ } else {
+ bm = (BatteryManager)currentContext.getSystemService(Context.BATTERY_SERVICE);
+ }
+ int batLevel = bm.getIntProperty(BatteryManager.BATTERY_PROPERTY_CAPACITY);
+
+ dataObject.put("battery", batLevel);
+
+ dataToSend.put("data", dataObject);
+ return dataToSend.toString();
+ } catch (Exception e) {
+ Log.e(TAG,"getLocationDataToSend", e);
+ return null;
+ }
+ }
+
+ private String getNotificationActionData() {
+ try {
+ String rawActionData = getInputData().getString("rawActionData");
+ if (rawActionData == null || rawActionData.length() == 0) {
+ Log.e(TAG,"getNotificationActionData rawAction data is empty");
+ return null;
+ }
+ JSONObject actionData = new JSONObject(rawActionData);
+ JSONObject dataToSend = new JSONObject();
+ JSONObject requestData = new JSONObject();
+ if (actionData.getString("action").equals("call-service")) {
+ dataToSend.put("type", "call_service");
+ requestData.put("domain", actionData.getString("service").split("\\.")[0]);
+ requestData.put("service", actionData.getString("service").split("\\.")[1]);
+ if (actionData.has("service_data")) {
+ requestData.put("service_data", actionData.get("service_data"));
+ }
+ } else {
+ dataToSend.put("type", "fire_event");
+ requestData.put("event_type", "ha_client_event");
+ JSONObject eventData = new JSONObject();
+ eventData.put("action", actionData.getString("action"));
+ requestData.put("event_data", eventData);
+ }
+ dataToSend.put("data", requestData);
+ return dataToSend.toString();
+ } catch (Exception e) {
+ Log.e(TAG,"getNotificationActionData", e);
+ return null;
+ }
+ }
+
+ private String getNextAlarmDataToSend() {
+ try {
+ final AlarmManager alarmManager;
+ if (android.os.Build.VERSION.SDK_INT >= 23) {
+ alarmManager = currentContext.getSystemService(AlarmManager.class);
+ } else {
+ alarmManager = (AlarmManager)currentContext.getSystemService(Context.ALARM_SERVICE);
+ }
+
+ final AlarmManager.AlarmClockInfo alarmClockInfo = alarmManager.getNextAlarmClock();
+
+ JSONObject dataToSend = new JSONObject();
+ dataToSend.put("type", "update_sensor_states");
+ JSONArray dataArray = new JSONArray();
+ JSONObject sensorData = new JSONObject();
+ JSONObject sensorAttrs = new JSONObject();
+ sensorData.put("unique_id", "next_alarm");
+ sensorData.put("type", "sensor");
+ final long triggerTimestamp;
+ if (alarmClockInfo != null) {
+ triggerTimestamp = alarmClockInfo.getTriggerTime();
+ final Calendar calendar = Calendar.getInstance();
+ calendar.setTimeInMillis(triggerTimestamp);
+ sensorData.put("state", DATE_TIME_FORMAT.format(calendar.getTime()));
+ sensorAttrs.put("date", DATE_FORMAT.format(calendar.getTime()));
+ sensorAttrs.put("time", TIME_FORMAT.format(calendar.getTime()));
+ sensorAttrs.put("timestamp", triggerTimestamp);
+ } else {
+ sensorData.put("state", "");
+ sensorAttrs.put("date", "");
+ sensorAttrs.put("time", "");
+ sensorAttrs.put("timestamp", 0);
+ }
+ sensorData.put("icon", "mdi:alarm");
+ sensorData.put("attributes", sensorAttrs);
+ dataArray.put(0, sensorData);
+ dataToSend.put("data", dataArray);
+ return dataToSend.toString();
+ } catch (Exception e) {
+ Log.e(TAG,"getNextAlarmDataToSend", e);
+ return null;
+ }
+ }
+}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendLocationWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendLocationWorker.java
deleted file mode 100644
index 2cc79f1..0000000
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendLocationWorker.java
+++ /dev/null
@@ -1,98 +0,0 @@
-package com.keyboardcrumbs.hassclient;
-
-import android.app.AlarmManager;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-import android.webkit.URLUtil;
-
-import androidx.annotation.NonNull;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Locale;
-
-public class SendLocationWorker extends Worker {
-
- private Context currentContext;
- private static final String TAG = "SendLocationWorker";
-
- public static final String KEY_LAT_ARG = "Lat";
- public static final String KEY_LONG_ARG = "Long";
- public static final String KEY_ACC_ARG = "Acc";
-
- public SendLocationWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
- super(context, workerParams);
- currentContext = context;
- }
-
- @NonNull
- @Override
- public Result doWork() {
- SharedPreferences prefs = currentContext.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
- String webhookId = prefs.getString("flutter.app-webhook-id", null);
- if (webhookId != null) {
- try {
- String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
- "://" +
- prefs.getString("flutter.hassio-domain", "") +
- ":" +
- prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
- JSONObject dataToSend = new JSONObject();
- if (URLUtil.isValidUrl(requestUrl)) {
- dataToSend.put("type", "update_location");
- JSONObject dataObject = new JSONObject();
-
- JSONArray gps = new JSONArray();
- gps.put(0, getInputData().getDouble(KEY_LAT_ARG, 0));
- gps.put(1, getInputData().getDouble(KEY_LONG_ARG, 0));
-
- dataObject.put("gps", gps);
- dataObject.put("gps_accuracy", getInputData().getFloat(KEY_ACC_ARG, 0));
- dataObject.put("battery", 41);
-
- dataToSend.put("data", dataObject);
-
- String stringRequest = dataToSend.toString();
- try {
- URL url = new URL(requestUrl);
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- urlConnection.setRequestMethod("POST");
- urlConnection.setRequestProperty("Content-Type", "application/json");
- urlConnection.setDoOutput(true);
- byte[] outputBytes = stringRequest.getBytes("UTF-8");
- OutputStream os = urlConnection.getOutputStream();
- os.write(outputBytes);
-
- int responseCode = urlConnection.getResponseCode();
- urlConnection.disconnect();
- if (responseCode >= 300) {
- return Result.retry();
- }
- } catch (Exception e) {
- Log.e(TAG, "Error sending data", e);
- return Result.retry();
- }
- } else {
- Log.w(TAG, "Invalid HA url");
- return Result.failure();
- }
- } catch (Exception e) {
- Log.e(TAG, "Error =(", e);
- return Result.failure();
- }
- } else {
- Log.w(TAG, "Webhook id not found");
- return Result.failure();
- }
- return Result.success();
- }
-}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendTask.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendTask.java
deleted file mode 100644
index 76571cd..0000000
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/SendTask.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.keyboardcrumbs.hassclient;
-
-import android.util.Log;
-import android.os.AsyncTask;
-
-import java.net.URL;
-import java.net.HttpURLConnection;
-import java.io.OutputStream;
-
-public class SendTask extends AsyncTask {
-
- private static final String TAG = "SendTask";
-
- public SendTask(){
- //set context variables if required
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
-
- @Override
- protected String doInBackground(String... params) {
- String urlString = params[0];
- String data = params[1];
-
- try {
- URL url = new URL(urlString);
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- urlConnection.setRequestMethod("POST");
- urlConnection.setRequestProperty("Content-Type", "application/json");
- urlConnection.setDoOutput(true);
- byte[] outputBytes = data.getBytes("UTF-8");
- OutputStream os = urlConnection.getOutputStream();
- os.write(outputBytes);
-
- int responseCode = urlConnection.getResponseCode();
-
- urlConnection.disconnect();
- } catch (Exception e) {
- Log.e(TAG, "Error sending data", e);
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/UpdateNextAlarmWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/UpdateNextAlarmWorker.java
deleted file mode 100644
index a6d69a6..0000000
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/UpdateNextAlarmWorker.java
+++ /dev/null
@@ -1,119 +0,0 @@
-package com.keyboardcrumbs.hassclient;
-
-import android.app.AlarmManager;
-import android.content.Context;
-import android.content.SharedPreferences;
-import android.util.Log;
-import android.webkit.URLUtil;
-
-import androidx.annotation.NonNull;
-import androidx.work.Worker;
-import androidx.work.WorkerParameters;
-
-import org.json.JSONArray;
-import org.json.JSONObject;
-
-import java.io.OutputStream;
-import java.net.HttpURLConnection;
-import java.net.URL;
-import java.text.SimpleDateFormat;
-import java.util.Calendar;
-import java.util.Locale;
-
-public class UpdateNextAlarmWorker extends Worker {
-
- private Context currentContext;
- private static final String TAG = "NextAlarmWorker";
- private static final SimpleDateFormat DATE_TIME_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:00", Locale.ENGLISH);
- private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.ENGLISH);
- private static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:00", Locale.ENGLISH);
-
- public UpdateNextAlarmWorker(@NonNull Context context, @NonNull WorkerParameters workerParams) {
- super(context, workerParams);
- currentContext = context;
- }
-
- @NonNull
- @Override
- public Result doWork() {
- final AlarmManager alarmManager;
- if (android.os.Build.VERSION.SDK_INT >= 23) {
- alarmManager = currentContext.getSystemService(AlarmManager.class);
- } else {
- alarmManager = (AlarmManager)currentContext.getSystemService(Context.ALARM_SERVICE);
- }
-
- final AlarmManager.AlarmClockInfo alarmClockInfo = alarmManager.getNextAlarmClock();
-
- SharedPreferences prefs = currentContext.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
- String webhookId = prefs.getString("flutter.app-webhook-id", null);
- if (webhookId != null) {
- try {
- String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
- "://" +
- prefs.getString("flutter.hassio-domain", "") +
- ":" +
- prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
- JSONObject dataToSend = new JSONObject();
- if (URLUtil.isValidUrl(requestUrl)) {
- dataToSend.put("type", "update_sensor_states");
- JSONArray dataArray = new JSONArray();
- JSONObject sensorData = new JSONObject();
- JSONObject sensorAttrs = new JSONObject();
- sensorData.put("unique_id", "next_alarm");
- sensorData.put("type", "sensor");
- final long triggerTimestamp;
- if (alarmClockInfo != null) {
- triggerTimestamp = alarmClockInfo.getTriggerTime();
- final Calendar calendar = Calendar.getInstance();
- calendar.setTimeInMillis(triggerTimestamp);
- sensorData.put("state", DATE_TIME_FORMAT.format(calendar.getTime()));
- sensorAttrs.put("date", DATE_FORMAT.format(calendar.getTime()));
- sensorAttrs.put("time", TIME_FORMAT.format(calendar.getTime()));
- sensorAttrs.put("timestamp", triggerTimestamp);
- } else {
- sensorData.put("state", "");
- sensorAttrs.put("date", "");
- sensorAttrs.put("time", "");
- sensorAttrs.put("timestamp", 0);
- }
- sensorData.put("icon", "mdi:alarm");
- sensorData.put("attributes", sensorAttrs);
- dataArray.put(0, sensorData);
- dataToSend.put("data", dataArray);
-
- String stringRequest = dataToSend.toString();
- try {
- URL url = new URL(requestUrl);
- HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
- urlConnection.setRequestMethod("POST");
- urlConnection.setRequestProperty("Content-Type", "application/json");
- urlConnection.setDoOutput(true);
- byte[] outputBytes = stringRequest.getBytes("UTF-8");
- OutputStream os = urlConnection.getOutputStream();
- os.write(outputBytes);
-
- int responseCode = urlConnection.getResponseCode();
- urlConnection.disconnect();
- if (responseCode >= 300) {
- return Result.retry();
- }
- } catch (Exception e) {
- Log.e(TAG, "Error sending data", e);
- return Result.retry();
- }
- } else {
- Log.w(TAG, "Invalid HA url");
- return Result.failure();
- }
- } catch (Exception e) {
- Log.e(TAG, "Error setting next alarm", e);
- return Result.failure();
- }
- } else {
- Log.w(TAG, "Webhook id not found");
- return Result.failure();
- }
- return Result.success();
- }
-}
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/UpdateTokenTask.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/UpdateTokenTask.java
deleted file mode 100644
index 91455c0..0000000
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/UpdateTokenTask.java
+++ /dev/null
@@ -1,46 +0,0 @@
-package com.keyboardcrumbs.hassclient;
-
-import android.util.Log;
-import android.os.AsyncTask;
-
-import java.net.URL;
-import java.net.HttpURLConnection;
-import java.io.OutputStream;
-
-import android.webkit.URLUtil;
-
-import org.json.JSONObject;
-import android.content.SharedPreferences;
-import android.content.Context;
-import java.lang.ref.WeakReference;
-
-
-public class UpdateTokenTask extends AsyncTask {
-
- private static final String TAG = "UpdateTokenTask";
-
- private WeakReference contextRef;
-
- public UpdateTokenTask(Context context){
- contextRef = new WeakReference<>(context);
- }
-
- @Override
- protected void onPreExecute() {
- super.onPreExecute();
- }
-
- @Override
- protected String doInBackground(String... params) {
- Log.d(TAG, "Updating push token");
- Context context = contextRef.get();
- if (context != null) {
- String token = params[0];
- SharedPreferences prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
- SharedPreferences.Editor editor = prefs.edit();
- editor.putString("flutter.npush-token", token);
- editor.commit();
- }
- return null;
- }
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/Utils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/Utils.java
deleted file mode 100644
index 36de592..0000000
--- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/Utils.java
+++ /dev/null
@@ -1,38 +0,0 @@
-package com.keyboardcrumbs.hassclient;
-
-import android.content.Context;
-import android.location.Location;
-import android.preference.PreferenceManager;
-
-import java.text.DateFormat;
-import java.util.Date;
-
-class Utils {
-
- static final String KEY_REQUESTING_LOCATION_UPDATES = "flutter.foreground-location-service";
- static final String KEY_LOCATION_UPDATE_INTERVAL = "flutter.active-location-interval";
-
- static boolean requestingLocationUpdates(Context context) {
- return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getBoolean(KEY_REQUESTING_LOCATION_UPDATES, false);
- }
-
- static long getLocationUpdateIntervals(Context context) {
- return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_LOCATION_UPDATE_INTERVAL, 90) * 1000;
- }
-
- static void setRequestingLocationUpdates(Context context, boolean requestingLocationUpdates) {
- context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE)
- .edit()
- .putBoolean(KEY_REQUESTING_LOCATION_UPDATES, requestingLocationUpdates)
- .apply();
- }
-
- static String getLocationText(Location location) {
- return location == null ? "Accuracy: unknown" :
- "Accuracy: " + location.getAccuracy();
- }
-
- static String getLocationTitle(Location location) {
- return location == null ? "Requesting location..." : "Location updated at " + DateFormat.getDateTimeInstance().format(new Date(location.getTime()));
- }
-}
diff --git a/lib/managers/app_settings.dart b/lib/managers/app_settings.dart
index 009a03a..60ed778 100644
--- a/lib/managers/app_settings.dart
+++ b/lib/managers/app_settings.dart
@@ -32,7 +32,7 @@ class AppSettings {
DisplayMode displayMode;
AppTheme appTheme;
final int defaultLocationUpdateIntervalMinutes = 20;
- final int defaultActiveLocationUpdateIntervalSeconds = 90;
+ final int defaultActiveLocationUpdateIntervalSeconds = 900;
Duration locationUpdateInterval;
bool locationTrackingEnabled = false;
diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart
index 52fc15e..f1e4b32 100644
--- a/lib/pages/settings/integration_settings.part.dart
+++ b/lib/pages/settings/integration_settings.part.dart
@@ -12,6 +12,12 @@ class IntegrationSettingsPage extends StatefulWidget {
class _IntegrationSettingsPageState extends State {
static const platform = const MethodChannel('com.keyboardcrumbs.hassclient/native');
+ static final locationAccuracy = {
+ 100: "Highest",
+ 102: "Balanced (about 100 meters)",
+ 104: "Low (up to 10 kilometers)",
+ 105: "Passive (last known location)",
+ };
int _locationInterval = AppSettings().defaultLocationUpdateIntervalMinutes;
int _activeLocationInterval = AppSettings().defaultActiveLocationUpdateIntervalSeconds;
@@ -19,6 +25,7 @@ class _IntegrationSettingsPageState extends State {
bool _foregroundLocationTrackingEnabled = false;
bool _wait = false;
bool _changedHere = false;
+ int _accuracy = 102;
@override
void initState() {
@@ -33,10 +40,11 @@ class _IntegrationSettingsPageState extends State {
SharedPreferences.getInstance().then((prefs) {
setState(() {
_locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
- _foregroundLocationTrackingEnabled = prefs.getBool("foreground-location-service") ?? false;
+ _accuracy = prefs.getInt("location-updates-priority") ?? 102;
+ _foregroundLocationTrackingEnabled = (prefs.getInt("location-updates-state") ?? 0) > 0;
_locationInterval = prefs.getInt("location-interval") ??
AppSettings().defaultLocationUpdateIntervalMinutes;
- _activeLocationInterval = prefs.getInt("active-location-interval") ??
+ _activeLocationInterval = prefs.getInt("location-updates-interval") ??
AppSettings().defaultActiveLocationUpdateIntervalSeconds;
if (_locationInterval < 15) {
_locationInterval = 15;
@@ -94,9 +102,13 @@ class _IntegrationSettingsPageState extends State {
}
_switchForegroundLocationTrackingState(bool state) async {
- await AppSettings().save({'active-location-interval': _activeLocationInterval});
+ await AppSettings().save({'location-updates-interval': _activeLocationInterval, 'location-updates-priority': _accuracy});
if (state) {
- await platform.invokeMethod('startLocationService');
+ try {
+ await platform.invokeMethod('startLocationService');
+ } catch (e) {
+ _foregroundLocationTrackingEnabled = false;
+ }
} else {
await platform.invokeMethod('stopLocationService');
}
@@ -154,11 +166,7 @@ class _IntegrationSettingsPageState extends State {
),
Container(height: Sizes.rowPadding),
Text("Active location tracking", style: Theme.of(context).textTheme.title),
- Text("Works in foreground noticeably affecting phone battery. Sends most accurate location getting it from phone if possible. Can be very frequent.",
- style: Theme.of(context).textTheme.caption,
- softWrap: true,
- ),
- Container(height: Sizes.rowPadding,),
+ Container(height: Sizes.rowPadding),
Row(
children: [
Text("Enable"),
@@ -175,7 +183,26 @@ class _IntegrationSettingsPageState extends State {
],
),
Container(height: Sizes.rowPadding),
- Text("Update device location every"),
+ Text("Accuracy:", style: Theme.of(context).textTheme.body2),
+ Container(height: Sizes.rowPadding),
+ DropdownButton(
+ value: _accuracy,
+ iconSize: 30.0,
+ isExpanded: true,
+ items: locationAccuracy.keys.map((value) {
+ return new DropdownMenuItem(
+ value: value,
+ child: Text('${locationAccuracy[value]}'),
+ );
+ }).toList(),
+ onChanged: _foregroundLocationTrackingEnabled ? null : (val) {
+ setState(() {
+ _accuracy = val;
+ });
+ },
+ ),
+ Container(height: Sizes.rowPadding),
+ Text("Update intervals"),
Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,