#571 Finish native part
This commit is contained in:
parent
f39dbe3b24
commit
3a7f3db6cd
@ -81,6 +81,7 @@ dependencies {
|
|||||||
implementation 'com.google.firebase:firebase-analytics:17.2.2'
|
implementation 'com.google.firebase:firebase-analytics:17.2.2'
|
||||||
implementation 'com.google.firebase:firebase-messaging:20.2.0'
|
implementation 'com.google.firebase:firebase-messaging:20.2.0'
|
||||||
implementation 'androidx.work:work-runtime:2.3.4'
|
implementation 'androidx.work:work-runtime:2.3.4'
|
||||||
|
implementation "androidx.concurrent:concurrent-futures:1.0.0"
|
||||||
testImplementation 'junit:junit:4.12'
|
testImplementation 'junit:junit:4.12'
|
||||||
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
androidTestImplementation 'com.android.support.test:runner:1.0.2'
|
||||||
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
|
||||||
|
@ -72,7 +72,7 @@
|
|||||||
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
|
<action android:name="android.app.action.NEXT_ALARM_CLOCK_CHANGED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
<receiver android:name=".Autostart">
|
<receiver android:name=".LocationUpdatesAfterReboot">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
<action android:name="android.intent.action.BOOT_COMPLETED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -7,7 +7,6 @@ import android.app.PendingIntent;
|
|||||||
import android.app.Service;
|
import android.app.Service;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.os.Binder;
|
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Handler;
|
import android.os.Handler;
|
||||||
import android.os.HandlerThread;
|
import android.os.HandlerThread;
|
||||||
@ -78,9 +77,6 @@ public class LocationUpdatesService extends Service {
|
|||||||
};
|
};
|
||||||
|
|
||||||
mLocationRequest = new LocationRequest();
|
mLocationRequest = new LocationRequest();
|
||||||
mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);
|
|
||||||
|
|
||||||
getLastLocation();
|
|
||||||
|
|
||||||
HandlerThread handlerThread = new HandlerThread(TAG);
|
HandlerThread handlerThread = new HandlerThread(TAG);
|
||||||
handlerThread.start();
|
handlerThread.start();
|
||||||
@ -130,8 +126,10 @@ public class LocationUpdatesService extends Service {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void requestLocationUpdates() {
|
private void requestLocationUpdates() {
|
||||||
long requestInterval = Utils.getLocationUpdateIntervals(getApplicationContext());
|
long requestInterval = LocationUtils.getLocationUpdateIntervals(getApplicationContext());
|
||||||
Log.i(TAG, "Requesting location updates. Interval is " + requestInterval);
|
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.setInterval(requestInterval);
|
||||||
mLocationRequest.setFastestInterval(requestInterval);
|
mLocationRequest.setFastestInterval(requestInterval);
|
||||||
startForeground(NOTIFICATION_ID, getNotification());
|
startForeground(NOTIFICATION_ID, getNotification());
|
||||||
@ -146,7 +144,7 @@ public class LocationUpdatesService extends Service {
|
|||||||
private Notification getNotification() {
|
private Notification getNotification() {
|
||||||
Intent intent = new Intent(this, LocationUpdatesService.class);
|
Intent intent = new Intent(this, LocationUpdatesService.class);
|
||||||
|
|
||||||
CharSequence text = Utils.getLocationText(mLocation);
|
CharSequence text = LocationUtils.getLocationText(mLocation);
|
||||||
|
|
||||||
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
|
intent.putExtra(EXTRA_STARTED_FROM_NOTIFICATION, true);
|
||||||
|
|
||||||
@ -157,13 +155,13 @@ public class LocationUpdatesService extends Service {
|
|||||||
new Intent(this, MainActivity.class), 0);
|
new Intent(this, MainActivity.class), 0);
|
||||||
|
|
||||||
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
|
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)
|
activityPendingIntent)
|
||||||
.addAction(R.drawable.blank_icon, "Stop",
|
.addAction(R.drawable.blank_icon, "Stop tracking",
|
||||||
servicePendingIntent)
|
servicePendingIntent)
|
||||||
.setContentText(text)
|
.setContentText(text)
|
||||||
.setPriority(-1)
|
.setPriority(-1)
|
||||||
.setContentTitle(Utils.getLocationTitle(mLocation))
|
.setContentTitle(LocationUtils.getLocationTitle(mLocation))
|
||||||
.setOngoing(true)
|
.setOngoing(true)
|
||||||
.setSmallIcon(R.drawable.mini_icon)
|
.setSmallIcon(R.drawable.mini_icon)
|
||||||
.setWhen(System.currentTimeMillis());
|
.setWhen(System.currentTimeMillis());
|
||||||
@ -171,21 +169,6 @@ public class LocationUpdatesService extends Service {
|
|||||||
return builder.build();
|
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) {
|
private void onNewLocation(Location location) {
|
||||||
Log.i(TAG, "New location: " + location);
|
Log.i(TAG, "New location: " + location);
|
||||||
|
|
||||||
@ -198,6 +181,7 @@ public class LocationUpdatesService extends Service {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
Data locationData = new Data.Builder()
|
Data locationData = new Data.Builder()
|
||||||
|
.putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_LOCATION)
|
||||||
.putDouble("Lat", mLocation.getLatitude())
|
.putDouble("Lat", mLocation.getLatitude())
|
||||||
.putDouble("Long", mLocation.getLongitude())
|
.putDouble("Long", mLocation.getLongitude())
|
||||||
.putFloat("Acc", mLocation.getAccuracy())
|
.putFloat("Acc", mLocation.getAccuracy())
|
||||||
@ -205,7 +189,7 @@ public class LocationUpdatesService extends Service {
|
|||||||
|
|
||||||
|
|
||||||
OneTimeWorkRequest uploadWorkRequest =
|
OneTimeWorkRequest uploadWorkRequest =
|
||||||
new OneTimeWorkRequest.Builder(SendLocationWorker.class)
|
new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
|
||||||
.setBackoffCriteria(
|
.setBackoffCriteria(
|
||||||
BackoffPolicy.EXPONENTIAL,
|
BackoffPolicy.EXPONENTIAL,
|
||||||
10,
|
10,
|
||||||
|
@ -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<Result> 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;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
@ -2,24 +2,19 @@ package com.keyboardcrumbs.hassclient;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.ActivityCompat;
|
import androidx.core.app.ActivityCompat;
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
import androidx.work.WorkManager;
|
||||||
|
|
||||||
import io.flutter.embedding.android.FlutterActivity;
|
import io.flutter.embedding.android.FlutterActivity;
|
||||||
import io.flutter.embedding.engine.FlutterEngine;
|
import io.flutter.embedding.engine.FlutterEngine;
|
||||||
import io.flutter.plugins.GeneratedPluginRegistrant;
|
import io.flutter.plugins.GeneratedPluginRegistrant;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.content.BroadcastReceiver;
|
|
||||||
import android.content.ComponentName;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.IntentFilter;
|
import android.content.SharedPreferences;
|
||||||
import android.content.ServiceConnection;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import android.location.Location;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.IBinder;
|
|
||||||
|
|
||||||
import io.flutter.plugin.common.MethodChannel;
|
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 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
|
@Override
|
||||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||||
@ -46,8 +44,7 @@ public class MainActivity extends FlutterActivity {
|
|||||||
.addOnCompleteListener(task -> {
|
.addOnCompleteListener(task -> {
|
||||||
if (task.isSuccessful()) {
|
if (task.isSuccessful()) {
|
||||||
String token = task.getResult().getToken();
|
String token = task.getResult().getToken();
|
||||||
UpdateTokenTask updateTokenTask = new UpdateTokenTask(context);
|
context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).edit().putString("flutter.npush-token", token).apply();
|
||||||
updateTokenTask.execute(token);
|
|
||||||
result.success(token);
|
result.success(token);
|
||||||
} else {
|
} else {
|
||||||
Exception ex = task.getException();
|
Exception ex = task.getException();
|
||||||
@ -64,17 +61,25 @@ public class MainActivity extends FlutterActivity {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case "startLocationService":
|
case "startLocationService":
|
||||||
Utils.setRequestingLocationUpdates(this, true);
|
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()) {
|
if (isNoLocationPermissions()) {
|
||||||
requestLocationPermissions();
|
requestLocationPermissions();
|
||||||
} else {
|
} else {
|
||||||
startLocationService();
|
startLocationUpdates();
|
||||||
}
|
}
|
||||||
result.success("");
|
result.success("");
|
||||||
|
} catch (Exception e) {
|
||||||
|
result.error("location_error", e.getMessage(), null);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "stopLocationService":
|
case "stopLocationService":
|
||||||
Utils.setRequestingLocationUpdates(this, false);
|
stopLocationUpdates();
|
||||||
stopLocationService();
|
|
||||||
result.success("");
|
result.success("");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -86,24 +91,28 @@ public class MainActivity extends FlutterActivity {
|
|||||||
return (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS);
|
return (GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startLocationService() {
|
private void startLocationUpdates() {
|
||||||
Intent myService = new Intent(MainActivity.this, LocationUpdatesService.class);
|
if (locationUpdatesType == LocationUtils.LOCATION_UPDATES_SERVICE) {
|
||||||
startService(myService);
|
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);
|
Intent myService = new Intent(MainActivity.this, LocationUpdatesService.class);
|
||||||
stopService(myService);
|
stopService(myService);
|
||||||
|
WorkManager.getInstance(this).cancelUniqueWork(LocationUtils.LOCATION_WORK_NAME);
|
||||||
|
LocationUtils.setLocationUpdatesState(this, LocationUtils.LOCATION_UPDATES_DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
/*if (Utils.requestingLocationUpdates(this)) {
|
|
||||||
if (isNoLocationPermissions()) {
|
|
||||||
requestLocationPermissions();
|
|
||||||
}
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -142,7 +151,9 @@ public class MainActivity extends FlutterActivity {
|
|||||||
@NonNull int[] grantResults) {
|
@NonNull int[] grantResults) {
|
||||||
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
|
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
|
||||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
startLocationService();
|
startLocationUpdates();
|
||||||
|
} else {
|
||||||
|
stopLocationUpdates();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,6 @@ package com.keyboardcrumbs.hassclient;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.net.URLConnection;
|
import java.net.URLConnection;
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
import android.app.NotificationChannel;
|
import android.app.NotificationChannel;
|
||||||
@ -14,6 +13,8 @@ import android.content.Intent;
|
|||||||
import android.media.RingtoneManager;
|
import android.media.RingtoneManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.core.app.NotificationCompat;
|
import androidx.core.app.NotificationCompat;
|
||||||
|
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService;
|
import com.google.firebase.messaging.FirebaseMessagingService;
|
||||||
@ -26,7 +27,7 @@ import android.webkit.URLUtil;
|
|||||||
|
|
||||||
public class MessagingService extends FirebaseMessagingService {
|
public class MessagingService extends FirebaseMessagingService {
|
||||||
|
|
||||||
private static final String TAG = "MessagingService";
|
public static final String NOTIFICATION_ACTION_BROADCAST = "com.keyboardcrumbs.hassclient.haNotificationAction";
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onMessageReceived(RemoteMessage remoteMessage) {
|
public void onMessageReceived(RemoteMessage remoteMessage) {
|
||||||
@ -39,19 +40,19 @@ public class MessagingService extends FirebaseMessagingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onNewToken(String token) {
|
public void onNewToken(@NonNull String token) {
|
||||||
UpdateTokenTask updateTokenTask = new UpdateTokenTask(this);
|
getApplicationContext().getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).edit().putString("flutter.npush-token", token).apply();
|
||||||
updateTokenTask.execute(token);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendNotification(Map<String, String> data) {
|
private void sendNotification(Map<String, String> data) {
|
||||||
String channelId, messageBody, messageTitle, imageUrl, nTag, channelDescription;
|
String channelId, messageBody, messageTitle, imageUrl, nTag, channelDescription;
|
||||||
boolean autoCancel;
|
boolean autoCancel;
|
||||||
if (!data.containsKey("channelId")) {
|
String customChannelId = data.get("channelId");
|
||||||
|
if (customChannelId == null) {
|
||||||
channelId = "ha_notify";
|
channelId = "ha_notify";
|
||||||
channelDescription = "Default notification channel";
|
channelDescription = "Default notification channel";
|
||||||
} else {
|
} else {
|
||||||
channelId = data.get("channelId");
|
channelId = customChannelId;
|
||||||
channelDescription = channelId;
|
channelDescription = channelId;
|
||||||
}
|
}
|
||||||
if (!data.containsKey("body")) {
|
if (!data.containsKey("body")) {
|
||||||
@ -114,7 +115,7 @@ public class MessagingService extends FirebaseMessagingService {
|
|||||||
}
|
}
|
||||||
for (int i = 1; i <= 3; i++) {
|
for (int i = 1; i <= 3; i++) {
|
||||||
if (data.containsKey("action" + 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) {
|
if (autoCancel) {
|
||||||
broadcastIntent.putExtra("tag", nTag);
|
broadcastIntent.putExtra("tag", nTag);
|
||||||
}
|
}
|
||||||
|
@ -7,19 +7,17 @@ import android.content.Intent;
|
|||||||
|
|
||||||
import androidx.work.BackoffPolicy;
|
import androidx.work.BackoffPolicy;
|
||||||
import androidx.work.Constraints;
|
import androidx.work.Constraints;
|
||||||
|
import androidx.work.Data;
|
||||||
import androidx.work.ExistingWorkPolicy;
|
import androidx.work.ExistingWorkPolicy;
|
||||||
import androidx.work.NetworkType;
|
import androidx.work.NetworkType;
|
||||||
import androidx.work.OneTimeWorkRequest;
|
import androidx.work.OneTimeWorkRequest;
|
||||||
import androidx.work.WorkManager;
|
import androidx.work.WorkManager;
|
||||||
import androidx.work.WorkRequest;
|
|
||||||
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
|
||||||
public class NextAlarmBroadcastReceiver extends BroadcastReceiver {
|
public class NextAlarmBroadcastReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = "NextAlarmReceiver";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
@ -35,12 +33,17 @@ public class NextAlarmBroadcastReceiver extends BroadcastReceiver {
|
|||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
Data workerData = new Data.Builder()
|
||||||
|
.putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_NEXT_ALARM)
|
||||||
|
.build();
|
||||||
|
|
||||||
OneTimeWorkRequest uploadWorkRequest =
|
OneTimeWorkRequest uploadWorkRequest =
|
||||||
new OneTimeWorkRequest.Builder(UpdateNextAlarmWorker.class)
|
new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
|
||||||
.setBackoffCriteria(
|
.setBackoffCriteria(
|
||||||
BackoffPolicy.EXPONENTIAL,
|
BackoffPolicy.EXPONENTIAL,
|
||||||
10,
|
10,
|
||||||
TimeUnit.SECONDS)
|
TimeUnit.SECONDS)
|
||||||
|
.setInputData(workerData)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
|
@ -1,73 +1,58 @@
|
|||||||
package com.keyboardcrumbs.hassclient;
|
package com.keyboardcrumbs.hassclient;
|
||||||
|
|
||||||
import android.app.AlarmManager;
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.util.Log;
|
|
||||||
import android.content.BroadcastReceiver;
|
import android.content.BroadcastReceiver;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
|
||||||
import android.app.NotificationManager;
|
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 java.util.concurrent.TimeUnit;
|
||||||
import android.content.SharedPreferences;
|
|
||||||
|
|
||||||
public class NotificationActionReceiver extends BroadcastReceiver {
|
public class NotificationActionReceiver extends BroadcastReceiver {
|
||||||
|
|
||||||
private static final String TAG = "NotificationAction";
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
if (intent == null) {
|
if (intent == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
String intentAction = intent.getAction();
|
||||||
|
if (intentAction == null || !intentAction.equalsIgnoreCase(MessagingService.NOTIFICATION_ACTION_BROADCAST)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
String rawActionData = intent.getStringExtra("actionData");
|
String rawActionData = intent.getStringExtra("actionData");
|
||||||
if (intent.hasExtra("tag")) {
|
if (intent.hasExtra("tag")) {
|
||||||
String notificationTag = intent.getStringExtra("tag");
|
String notificationTag = intent.getStringExtra("tag");
|
||||||
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
NotificationManager notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
notificationManager.cancel(notificationTag, 0);
|
notificationManager.cancel(notificationTag, 0);
|
||||||
}
|
}
|
||||||
SharedPreferences prefs = context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE);
|
Constraints constraints = new Constraints.Builder()
|
||||||
String webhookId = prefs.getString("flutter.app-webhook-id", null);
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
if (webhookId != null) {
|
.build();
|
||||||
try {
|
Data workerData = new Data.Builder()
|
||||||
String requestUrl = prefs.getString("flutter.hassio-res-protocol", "") +
|
.putInt(SendDataHomeWorker.DATA_TYPE_KEY, SendDataHomeWorker.DATA_TYPE_NOTIFICATION_ACTION)
|
||||||
"://" +
|
.putString("rawActionData", rawActionData)
|
||||||
prefs.getString("flutter.hassio-domain", "") +
|
.build();
|
||||||
":" +
|
|
||||||
prefs.getString("flutter.hassio-port", "") + "/api/webhook/" + webhookId;
|
OneTimeWorkRequest uploadWorkRequest =
|
||||||
JSONObject actionData = new JSONObject(rawActionData);
|
new OneTimeWorkRequest.Builder(SendDataHomeWorker.class)
|
||||||
if (URLUtil.isValidUrl(requestUrl)) {
|
.setBackoffCriteria(
|
||||||
JSONObject dataToSend = new JSONObject();
|
BackoffPolicy.EXPONENTIAL,
|
||||||
JSONObject requestData = new JSONObject();
|
10,
|
||||||
if (actionData.getString("action").equals("call-service")) {
|
TimeUnit.SECONDS)
|
||||||
dataToSend.put("type", "call_service");
|
.setInputData(workerData)
|
||||||
requestData.put("domain", actionData.getString("service").split("\\.")[0]);
|
.setConstraints(constraints)
|
||||||
requestData.put("service", actionData.getString("service").split("\\.")[1]);
|
.build();
|
||||||
if (actionData.has("service_data")) {
|
|
||||||
requestData.put("service_data", actionData.get("service_data"));
|
WorkManager
|
||||||
}
|
.getInstance(context)
|
||||||
} else {
|
.enqueueUniqueWork("NotificationAction", ExistingWorkPolicy.APPEND, uploadWorkRequest);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<String, String, String> {
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
@ -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<String, String, String> {
|
|
||||||
|
|
||||||
private static final String TAG = "UpdateTokenTask";
|
|
||||||
|
|
||||||
private WeakReference<Context> 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;
|
|
||||||
}
|
|
||||||
}
|
|
@ -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()));
|
|
||||||
}
|
|
||||||
}
|
|
@ -32,7 +32,7 @@ class AppSettings {
|
|||||||
DisplayMode displayMode;
|
DisplayMode displayMode;
|
||||||
AppTheme appTheme;
|
AppTheme appTheme;
|
||||||
final int defaultLocationUpdateIntervalMinutes = 20;
|
final int defaultLocationUpdateIntervalMinutes = 20;
|
||||||
final int defaultActiveLocationUpdateIntervalSeconds = 90;
|
final int defaultActiveLocationUpdateIntervalSeconds = 900;
|
||||||
Duration locationUpdateInterval;
|
Duration locationUpdateInterval;
|
||||||
bool locationTrackingEnabled = false;
|
bool locationTrackingEnabled = false;
|
||||||
|
|
||||||
|
@ -12,6 +12,12 @@ class IntegrationSettingsPage extends StatefulWidget {
|
|||||||
class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||||
|
|
||||||
static const platform = const MethodChannel('com.keyboardcrumbs.hassclient/native');
|
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 _locationInterval = AppSettings().defaultLocationUpdateIntervalMinutes;
|
||||||
int _activeLocationInterval = AppSettings().defaultActiveLocationUpdateIntervalSeconds;
|
int _activeLocationInterval = AppSettings().defaultActiveLocationUpdateIntervalSeconds;
|
||||||
@ -19,6 +25,7 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
|||||||
bool _foregroundLocationTrackingEnabled = false;
|
bool _foregroundLocationTrackingEnabled = false;
|
||||||
bool _wait = false;
|
bool _wait = false;
|
||||||
bool _changedHere = false;
|
bool _changedHere = false;
|
||||||
|
int _accuracy = 102;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -33,10 +40,11 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
|||||||
SharedPreferences.getInstance().then((prefs) {
|
SharedPreferences.getInstance().then((prefs) {
|
||||||
setState(() {
|
setState(() {
|
||||||
_locationTrackingEnabled = prefs.getBool("location-enabled") ?? false;
|
_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") ??
|
_locationInterval = prefs.getInt("location-interval") ??
|
||||||
AppSettings().defaultLocationUpdateIntervalMinutes;
|
AppSettings().defaultLocationUpdateIntervalMinutes;
|
||||||
_activeLocationInterval = prefs.getInt("active-location-interval") ??
|
_activeLocationInterval = prefs.getInt("location-updates-interval") ??
|
||||||
AppSettings().defaultActiveLocationUpdateIntervalSeconds;
|
AppSettings().defaultActiveLocationUpdateIntervalSeconds;
|
||||||
if (_locationInterval < 15) {
|
if (_locationInterval < 15) {
|
||||||
_locationInterval = 15;
|
_locationInterval = 15;
|
||||||
@ -94,9 +102,13 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_switchForegroundLocationTrackingState(bool state) async {
|
_switchForegroundLocationTrackingState(bool state) async {
|
||||||
await AppSettings().save({'active-location-interval': _activeLocationInterval});
|
await AppSettings().save({'location-updates-interval': _activeLocationInterval, 'location-updates-priority': _accuracy});
|
||||||
if (state) {
|
if (state) {
|
||||||
|
try {
|
||||||
await platform.invokeMethod('startLocationService');
|
await platform.invokeMethod('startLocationService');
|
||||||
|
} catch (e) {
|
||||||
|
_foregroundLocationTrackingEnabled = false;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
await platform.invokeMethod('stopLocationService');
|
await platform.invokeMethod('stopLocationService');
|
||||||
}
|
}
|
||||||
@ -154,11 +166,7 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
|||||||
),
|
),
|
||||||
Container(height: Sizes.rowPadding),
|
Container(height: Sizes.rowPadding),
|
||||||
Text("Active location tracking", style: Theme.of(context).textTheme.title),
|
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.",
|
Container(height: Sizes.rowPadding),
|
||||||
style: Theme.of(context).textTheme.caption,
|
|
||||||
softWrap: true,
|
|
||||||
),
|
|
||||||
Container(height: Sizes.rowPadding,),
|
|
||||||
Row(
|
Row(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Text("Enable"),
|
Text("Enable"),
|
||||||
@ -175,7 +183,26 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
Container(height: Sizes.rowPadding),
|
Container(height: Sizes.rowPadding),
|
||||||
Text("Update device location every"),
|
Text("Accuracy:", style: Theme.of(context).textTheme.body2),
|
||||||
|
Container(height: Sizes.rowPadding),
|
||||||
|
DropdownButton<int>(
|
||||||
|
value: _accuracy,
|
||||||
|
iconSize: 30.0,
|
||||||
|
isExpanded: true,
|
||||||
|
items: locationAccuracy.keys.map((value) {
|
||||||
|
return new DropdownMenuItem<int>(
|
||||||
|
value: value,
|
||||||
|
child: Text('${locationAccuracy[value]}'),
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
onChanged: _foregroundLocationTrackingEnabled ? null : (val) {
|
||||||
|
setState(() {
|
||||||
|
_accuracy = val;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Container(height: Sizes.rowPadding),
|
||||||
|
Text("Update intervals"),
|
||||||
Row(
|
Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
mainAxisSize: MainAxisSize.max,
|
mainAxisSize: MainAxisSize.max,
|
||||||
|
Reference in New Issue
Block a user