WIP #571
This commit is contained in:
parent
08e1327a29
commit
6ba1e88b09
@ -16,7 +16,6 @@ import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.app.NotificationCompat;
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
|
||||
|
||||
@ -27,8 +26,6 @@ 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.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
|
||||
/**
|
||||
* A bound and started service that is promoted to a foreground service when location updates have
|
||||
@ -47,14 +44,11 @@ import com.google.android.gms.tasks.Task;
|
||||
public class LocationUpdatesService extends Service {
|
||||
|
||||
private static final String PACKAGE_NAME =
|
||||
"com.google.android.gms.location.sample.locationupdatesforegroundservice";
|
||||
"com.keyboardcrumbs.hassclient";
|
||||
|
||||
private static final String TAG = LocationUpdatesService.class.getSimpleName();
|
||||
|
||||
/**
|
||||
* The name of the channel for notifications.
|
||||
*/
|
||||
private static final String CHANNEL_ID = "channel_01";
|
||||
private static final String CHANNEL_ID = "location_service";
|
||||
|
||||
static final String ACTION_BROADCAST = PACKAGE_NAME + ".broadcast";
|
||||
|
||||
@ -64,18 +58,6 @@ public class LocationUpdatesService extends Service {
|
||||
|
||||
private final IBinder mBinder = new LocalBinder();
|
||||
|
||||
/**
|
||||
* The desired interval for location updates. Inexact. Updates may be more or less frequent.
|
||||
*/
|
||||
private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000;
|
||||
|
||||
/**
|
||||
* The fastest rate for active location updates. Updates will never be more frequent
|
||||
* than this value.
|
||||
*/
|
||||
private static final long FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS =
|
||||
UPDATE_INTERVAL_IN_MILLISECONDS / 2;
|
||||
|
||||
/**
|
||||
* The identifier for the notification displayed for the foreground service.
|
||||
*/
|
||||
@ -167,7 +149,7 @@ public class LocationUpdatesService extends Service {
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
// Called when a client (MainActivity in case of this sample) comes to the foreground
|
||||
// Called when MainActivity comes to the foreground
|
||||
// and binds with this service. The service should cease to be a foreground service
|
||||
// when that happens.
|
||||
Log.i(TAG, "in onBind()");
|
||||
@ -178,7 +160,7 @@ public class LocationUpdatesService extends Service {
|
||||
|
||||
@Override
|
||||
public void onRebind(Intent intent) {
|
||||
// Called when a client (MainActivity in case of this sample) returns to the foreground
|
||||
// Called when MainActivity returns to the foreground
|
||||
// and binds once again with this service. The service should cease to be a foreground
|
||||
// service when that happens.
|
||||
Log.i(TAG, "in onRebind()");
|
||||
@ -191,20 +173,10 @@ public class LocationUpdatesService extends Service {
|
||||
public boolean onUnbind(Intent intent) {
|
||||
Log.i(TAG, "Last client unbound from service");
|
||||
|
||||
// Called when the last client (MainActivity in case of this sample) unbinds from this
|
||||
// Called when the last client (MainActivity ) unbinds from this
|
||||
// service. If this method is called due to a configuration change in MainActivity, we
|
||||
// do nothing. Otherwise, we make this service a foreground service.
|
||||
if (!mChangingConfiguration && Utils.requestingLocationUpdates(this)) {
|
||||
Log.i(TAG, "Starting foreground service");
|
||||
/*
|
||||
// TODO(developer). If targeting O, use the following code.
|
||||
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
|
||||
mNotificationManager.startServiceInForeground(new Intent(this,
|
||||
LocationUpdatesService.class), NOTIFICATION_ID, getNotification());
|
||||
} else {
|
||||
startForeground(NOTIFICATION_ID, getNotification());
|
||||
}
|
||||
*/
|
||||
startForeground(NOTIFICATION_ID, getNotification());
|
||||
}
|
||||
return true; // Ensures onRebind() is called when a client re-binds.
|
||||
@ -215,10 +187,6 @@ public class LocationUpdatesService extends Service {
|
||||
mServiceHandler.removeCallbacksAndMessages(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a request for location updates. Note that in this sample we merely log the
|
||||
* {@link SecurityException}.
|
||||
*/
|
||||
public void requestLocationUpdates() {
|
||||
Log.i(TAG, "Requesting location updates");
|
||||
Utils.setRequestingLocationUpdates(this, true);
|
||||
@ -227,15 +195,11 @@ public class LocationUpdatesService extends Service {
|
||||
mFusedLocationClient.requestLocationUpdates(mLocationRequest,
|
||||
mLocationCallback, Looper.myLooper());
|
||||
} catch (SecurityException unlikely) {
|
||||
//When we lost permission
|
||||
Utils.setRequestingLocationUpdates(this, false);
|
||||
Log.e(TAG, "Lost location permission. Could not request updates. " + unlikely);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes location updates. Note that in this sample we merely log the
|
||||
* {@link SecurityException}.
|
||||
*/
|
||||
public void removeLocationUpdates() {
|
||||
Log.i(TAG, "Removing location updates");
|
||||
try {
|
||||
@ -243,8 +207,8 @@ public class LocationUpdatesService extends Service {
|
||||
Utils.setRequestingLocationUpdates(this, false);
|
||||
stopSelf();
|
||||
} catch (SecurityException unlikely) {
|
||||
//When we lost permission
|
||||
Utils.setRequestingLocationUpdates(this, true);
|
||||
Log.e(TAG, "Lost location permission. Could not remove updates. " + unlikely);
|
||||
}
|
||||
}
|
||||
|
||||
@ -273,11 +237,9 @@ public class LocationUpdatesService extends Service {
|
||||
.addAction(R.drawable.blank_icon, "Stop",
|
||||
servicePendingIntent)
|
||||
.setContentText(text)
|
||||
.setContentTitle(Utils.getLocationTitle(this))
|
||||
.setContentTitle(Utils.getLocationTitle(mLocation))
|
||||
.setOngoing(true)
|
||||
.setPriority(Notification.PRIORITY_HIGH)
|
||||
.setSmallIcon(R.mipmap.ic_launcher)
|
||||
.setTicker(text)
|
||||
.setWhen(System.currentTimeMillis());
|
||||
|
||||
return builder.build();
|
||||
@ -286,14 +248,11 @@ public class LocationUpdatesService extends Service {
|
||||
private void getLastLocation() {
|
||||
try {
|
||||
mFusedLocationClient.getLastLocation()
|
||||
.addOnCompleteListener(new OnCompleteListener<Location>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<Location> task) {
|
||||
if (task.isSuccessful() && task.getResult() != null) {
|
||||
mLocation = task.getResult();
|
||||
} else {
|
||||
Log.w(TAG, "Failed to get location.");
|
||||
}
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful() && task.getResult() != null) {
|
||||
mLocation = task.getResult();
|
||||
} else {
|
||||
Log.w(TAG, "Failed to get location.");
|
||||
}
|
||||
});
|
||||
} catch (SecurityException unlikely) {
|
||||
@ -321,9 +280,10 @@ public class LocationUpdatesService extends Service {
|
||||
* Sets the location request parameters.
|
||||
*/
|
||||
private void createLocationRequest() {
|
||||
long interval = Utils.getLocationUpdateIntervals(getApplicationContext());
|
||||
mLocationRequest = new LocationRequest();
|
||||
mLocationRequest.setInterval(UPDATE_INTERVAL_IN_MILLISECONDS);
|
||||
mLocationRequest.setFastestInterval(FASTEST_UPDATE_INTERVAL_IN_MILLISECONDS);
|
||||
mLocationRequest.setInterval(interval);
|
||||
mLocationRequest.setFastestInterval(interval);
|
||||
mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
|
||||
}
|
||||
|
||||
|
@ -16,46 +16,30 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ServiceConnection;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.Editor;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import io.flutter.plugin.common.MethodCall;
|
||||
import io.flutter.plugin.common.MethodChannel;
|
||||
|
||||
import com.google.android.gms.tasks.OnCompleteListener;
|
||||
import com.google.android.gms.tasks.Task;
|
||||
import com.google.android.gms.common.GoogleApiAvailability;
|
||||
import com.google.android.gms.common.ConnectionResult;
|
||||
import com.google.firebase.iid.FirebaseInstanceId;
|
||||
import com.google.firebase.iid.InstanceIdResult;
|
||||
import com.google.firebase.messaging.FirebaseMessaging;
|
||||
|
||||
public class MainActivity extends FlutterActivity {
|
||||
|
||||
private static final String TAG = MainActivity.class.getSimpleName();
|
||||
|
||||
private static final String CHANNEL = "com.keyboardcrumbs.hassclient/native";
|
||||
|
||||
// Used in checking for runtime permissions.
|
||||
private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34;
|
||||
|
||||
// The BroadcastReceiver used to listen from broadcasts from the service.
|
||||
private MyReceiver myReceiver;
|
||||
|
||||
// A reference to the service used to get location updates.
|
||||
private LocationUpdatesService mService = null;
|
||||
|
||||
// Tracks the bound state of the service.
|
||||
private boolean mBound = false;
|
||||
|
||||
// Monitors the state of the connection to the service.
|
||||
private final ServiceConnection mServiceConnection = new ServiceConnection() {
|
||||
|
||||
@Override
|
||||
@ -76,42 +60,46 @@ public class MainActivity extends FlutterActivity {
|
||||
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
|
||||
GeneratedPluginRegistrant.registerWith(flutterEngine);
|
||||
new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), CHANNEL).setMethodCallHandler(
|
||||
new MethodChannel.MethodCallHandler() {
|
||||
@Override
|
||||
public void onMethodCall(MethodCall call, MethodChannel.Result result) {
|
||||
(call, result) -> {
|
||||
Context context = getActivity();
|
||||
if (call.method.equals("getFCMToken")) {
|
||||
if (checkPlayServices()) {
|
||||
FirebaseInstanceId.getInstance().getInstanceId()
|
||||
.addOnCompleteListener(new OnCompleteListener<InstanceIdResult>() {
|
||||
@Override
|
||||
public void onComplete(@NonNull Task<InstanceIdResult> task) {
|
||||
if (task.isSuccessful()) {
|
||||
String token = task.getResult().getToken();
|
||||
UpdateTokenTask updateTokenTask = new UpdateTokenTask(context);
|
||||
updateTokenTask.execute(token);
|
||||
result.success(token);
|
||||
} else {
|
||||
result.error("fcm_error", task.getException().getMessage(), null);
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result.error("google_play_service_error", "Google Play Services unavailable", null);
|
||||
}
|
||||
} else if (call.method.equals("startLocationService")) {
|
||||
if (!checkPermissions()) {
|
||||
requestPermissions();
|
||||
} else {
|
||||
mService.requestLocationUpdates();
|
||||
}
|
||||
result.success("");
|
||||
} else if (call.method.equals("stopLocationService")) {
|
||||
mService.removeLocationUpdates();
|
||||
result.success("");
|
||||
switch (call.method) {
|
||||
case "getFCMToken":
|
||||
if (checkPlayServices()) {
|
||||
FirebaseInstanceId.getInstance().getInstanceId()
|
||||
.addOnCompleteListener(task -> {
|
||||
if (task.isSuccessful()) {
|
||||
String token = task.getResult().getToken();
|
||||
UpdateTokenTask updateTokenTask = new UpdateTokenTask(context);
|
||||
updateTokenTask.execute(token);
|
||||
result.success(token);
|
||||
} else {
|
||||
Exception ex = task.getException();
|
||||
if (ex != null) {
|
||||
result.error("fcm_error", ex.getMessage(), null);
|
||||
} else {
|
||||
result.error("fcm_error", "Unknown", null);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
} else {
|
||||
result.error("google_play_service_error", "Google Play Services unavailable", null);
|
||||
}
|
||||
break;
|
||||
case "startLocationService":
|
||||
if (checkPermissions()) {
|
||||
requestPermissions();
|
||||
} else {
|
||||
mService.requestLocationUpdates();
|
||||
}
|
||||
result.success("");
|
||||
break;
|
||||
case "stopLocationService":
|
||||
mService.removeLocationUpdates();
|
||||
result.success("");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@ -123,9 +111,8 @@ public class MainActivity extends FlutterActivity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
myReceiver = new MyReceiver();
|
||||
// Check that the user hasn't revoked permissions by going to Settings.
|
||||
if (Utils.requestingLocationUpdates(this)) {
|
||||
if (!checkPermissions()) {
|
||||
if (checkPermissions()) {
|
||||
requestPermissions();
|
||||
}
|
||||
}
|
||||
@ -134,8 +121,6 @@ public class MainActivity extends FlutterActivity {
|
||||
@Override
|
||||
protected void onStart() {
|
||||
super.onStart();
|
||||
// Bind to the service. If the service is in foreground mode, this signals to the service
|
||||
// that since this activity is in the foreground, the service can exit foreground mode.
|
||||
bindService(new Intent(this, LocationUpdatesService.class), mServiceConnection,
|
||||
Context.BIND_AUTO_CREATE);
|
||||
}
|
||||
@ -156,112 +141,39 @@ public class MainActivity extends FlutterActivity {
|
||||
@Override
|
||||
protected void onStop() {
|
||||
if (mBound) {
|
||||
// Unbind from the service. This signals to the service that this activity is no longer
|
||||
// in the foreground, and the service can respond by promoting itself to a foreground
|
||||
// service.
|
||||
unbindService(mServiceConnection);
|
||||
mBound = false;
|
||||
}
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current state of the permissions needed.
|
||||
*/
|
||||
private boolean checkPermissions() {
|
||||
return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(this,
|
||||
return PackageManager.PERMISSION_GRANTED != ActivityCompat.checkSelfPermission(this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
}
|
||||
|
||||
private void requestPermissions() {
|
||||
boolean shouldProvideRationale =
|
||||
ActivityCompat.shouldShowRequestPermissionRationale(this,
|
||||
Manifest.permission.ACCESS_FINE_LOCATION);
|
||||
|
||||
// Provide an additional rationale to the user. This would happen if the user denied the
|
||||
// request previously, but didn't check the "Don't ask again" checkbox.
|
||||
if (shouldProvideRationale) {
|
||||
Log.i(TAG, "Displaying permission rationale to provide additional context.");
|
||||
/*
|
||||
Snackbar.make(
|
||||
findViewById(R.id.activity_main),
|
||||
R.string.permission_rationale,
|
||||
Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.ok, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// Request permission
|
||||
ActivityCompat.requestPermissions(MainActivity.this,
|
||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
||||
REQUEST_PERMISSIONS_REQUEST_CODE);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
*/
|
||||
} else {
|
||||
Log.i(TAG, "Requesting permission");
|
||||
// Request permission. It's possible this can be auto answered if device policy
|
||||
// sets the permission in a given state or the user denied the permission
|
||||
// previously and checked "Never ask again".
|
||||
ActivityCompat.requestPermissions(MainActivity.this,
|
||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
||||
REQUEST_PERMISSIONS_REQUEST_CODE);
|
||||
}
|
||||
ActivityCompat.requestPermissions(MainActivity.this,
|
||||
new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
|
||||
REQUEST_PERMISSIONS_REQUEST_CODE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback received when a permissions request has been completed.
|
||||
*/
|
||||
@Override
|
||||
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
|
||||
@NonNull int[] grantResults) {
|
||||
if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
|
||||
if (grantResults.length <= 0) {
|
||||
// If user interaction was interrupted, the permission request is cancelled and you
|
||||
// receive empty arrays.
|
||||
Log.i(TAG, "User interaction was cancelled.");
|
||||
} else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
// Permission was granted.
|
||||
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||
mService.requestLocationUpdates();
|
||||
} else {
|
||||
// Permission denied.
|
||||
/*
|
||||
setButtonsState(false);
|
||||
Snackbar.make(
|
||||
findViewById(R.id.activity_main),
|
||||
R.string.permission_denied_explanation,
|
||||
Snackbar.LENGTH_INDEFINITE)
|
||||
.setAction(R.string.settings, new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
// Build intent that displays the App settings screen.
|
||||
Intent intent = new Intent();
|
||||
intent.setAction(
|
||||
Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
|
||||
Uri uri = Uri.fromParts("package",
|
||||
BuildConfig.APPLICATION_ID, null);
|
||||
intent.setData(uri);
|
||||
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||
startActivity(intent);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Receiver for broadcasts sent by {@link LocationUpdatesService}.
|
||||
*/
|
||||
private class MyReceiver extends BroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Location location = intent.getParcelableExtra(LocationUpdatesService.EXTRA_LOCATION);
|
||||
if (location != null) {
|
||||
Toast.makeText(MainActivity.this, Utils.getLocationText(location),
|
||||
Toast.LENGTH_SHORT).show();
|
||||
//TODO looks like we need to remove this
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -10,20 +10,16 @@ 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";
|
||||
|
||||
/**
|
||||
* Returns true if requesting location updates, otherwise returns false.
|
||||
*
|
||||
* @param context The {@link Context}.
|
||||
*/
|
||||
static boolean requestingLocationUpdates(Context context) {
|
||||
return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getBoolean(KEY_REQUESTING_LOCATION_UPDATES, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the location updates state in SharedPreferences.
|
||||
* @param requestingLocationUpdates The location updates state.
|
||||
*/
|
||||
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()
|
||||
@ -31,16 +27,12 @@ class Utils {
|
||||
.apply();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@code location} object as a human readable string.
|
||||
* @param location The {@link Location}.
|
||||
*/
|
||||
static String getLocationText(Location location) {
|
||||
return location == null ? "Unknown location" :
|
||||
"(" + location.getLatitude() + ", " + location.getLongitude() + ")";
|
||||
return location == null ? "Accuracy: unknown" :
|
||||
"Accuracy: " + location.getAccuracy();
|
||||
}
|
||||
|
||||
static String getLocationTitle(Context context) {
|
||||
return "Location updated: " + DateFormat.getDateTimeInstance().format(new Date());
|
||||
static String getLocationTitle(Location location) {
|
||||
return "Location updated at " + DateFormat.getDateTimeInstance().format(new Date(location.getTime()));
|
||||
}
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ class AppSettings {
|
||||
DisplayMode displayMode;
|
||||
AppTheme appTheme;
|
||||
final int defaultLocationUpdateIntervalMinutes = 20;
|
||||
final int defaultActiveLocationUpdateIntervalSeconds = 90;
|
||||
Duration locationUpdateInterval;
|
||||
bool locationTrackingEnabled = false;
|
||||
|
||||
|
@ -14,6 +14,7 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||
static const platform = const MethodChannel('com.keyboardcrumbs.hassclient/native');
|
||||
|
||||
int _locationInterval = AppSettings().defaultLocationUpdateIntervalMinutes;
|
||||
int _activeLocationInterval = AppSettings().defaultActiveLocationUpdateIntervalSeconds;
|
||||
bool _locationTrackingEnabled = false;
|
||||
bool _foregroundLocationTrackingEnabled = false;
|
||||
bool _wait = false;
|
||||
@ -35,7 +36,11 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||
_foregroundLocationTrackingEnabled = prefs.getBool("foreground-location-service") ?? false;
|
||||
_locationInterval = prefs.getInt("location-interval") ??
|
||||
AppSettings().defaultLocationUpdateIntervalMinutes;
|
||||
if (_locationInterval % 5 != 0) {
|
||||
_activeLocationInterval = prefs.getInt("active-location-interval") ??
|
||||
AppSettings().defaultActiveLocationUpdateIntervalSeconds;
|
||||
if (_locationInterval < 15) {
|
||||
_locationInterval = 15;
|
||||
} else if (_locationInterval % 5 != 0) {
|
||||
_locationInterval = 5 * (_locationInterval ~/ 5);
|
||||
}
|
||||
});
|
||||
@ -52,7 +57,7 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||
}
|
||||
|
||||
void _decLocationInterval() {
|
||||
if (_locationInterval > 5) {
|
||||
if (_locationInterval > 15) {
|
||||
setState(() {
|
||||
_locationInterval = _locationInterval - 5;
|
||||
_changedHere = true;
|
||||
@ -60,6 +65,24 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
void _incActiveLocationInterval() {
|
||||
if (_activeLocationInterval < 7200) {
|
||||
setState(() {
|
||||
_activeLocationInterval = _activeLocationInterval + 5;
|
||||
_changedHere = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void _decActiveLocationInterval() {
|
||||
if (_activeLocationInterval > 5) {
|
||||
setState(() {
|
||||
_activeLocationInterval = _activeLocationInterval - 5;
|
||||
_changedHere = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
_switchLocationTrackingState(bool state) async {
|
||||
if (state) {
|
||||
await LocationManager().updateDeviceLocation();
|
||||
@ -71,6 +94,7 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||
}
|
||||
|
||||
_switchForegroundLocationTrackingState(bool state) async {
|
||||
await AppSettings().save({'active-location-interval': _activeLocationInterval});
|
||||
if (state) {
|
||||
await platform.invokeMethod('startLocationService');
|
||||
} else {
|
||||
@ -83,81 +107,96 @@ class _IntegrationSettingsPageState extends State<IntegrationSettingsPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!_wait && !_changedHere) {
|
||||
_loadSettings();
|
||||
} else if (_changedHere) {
|
||||
_changedHere = false;
|
||||
}
|
||||
return ListView(
|
||||
scrollDirection: Axis.vertical,
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
children: <Widget>[
|
||||
Text("Location tracking", style: Theme.of(context).textTheme.title),
|
||||
Container(height: Sizes.rowPadding,),
|
||||
InkWell(
|
||||
onTap: () => Launcher.launchURLInCustomTab(context: context, url: "http://ha-client.app/docs#location-tracking"),
|
||||
child: Text(
|
||||
"Please read documentation!",
|
||||
style: Theme.of(context).textTheme.subhead.copyWith(
|
||||
color: Colors.blue,
|
||||
decoration: TextDecoration.underline
|
||||
)
|
||||
),
|
||||
),
|
||||
Container(height: Sizes.rowPadding,),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text("Enable location tracking"),
|
||||
Switch(
|
||||
value: _locationTrackingEnabled,
|
||||
onChanged: _wait ? null : (value) {
|
||||
setState(() {
|
||||
_locationTrackingEnabled = value;
|
||||
_wait = true;
|
||||
});
|
||||
_switchLocationTrackingState(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(height: Sizes.rowPadding),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text("Foreground tracking"),
|
||||
Switch(
|
||||
value: _foregroundLocationTrackingEnabled,
|
||||
onChanged: _wait ? null : (value) {
|
||||
setState(() {
|
||||
_foregroundLocationTrackingEnabled = value;
|
||||
_wait = true;
|
||||
});
|
||||
_switchForegroundLocationTrackingState(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(height: Sizes.rowPadding),
|
||||
Text("Location update interval in minutes:"),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
//Expanded(child: Container(),),
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(0.0),
|
||||
child: Text("-", style: Theme.of(context).textTheme.title),
|
||||
onPressed: () => _decLocationInterval(),
|
||||
),
|
||||
Text("$_locationInterval", style: Theme.of(context).textTheme.title),
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(0.0),
|
||||
child: Text("+", style: Theme.of(context).textTheme.title),
|
||||
onPressed: () => _incLocationInterval(),
|
||||
),
|
||||
],
|
||||
)
|
||||
]
|
||||
);
|
||||
Text("Passive location tracking", style: Theme.of(context).textTheme.title),
|
||||
Text("Works in background not affecting phone battery. Usually sends last known device location. Can't be more frequent than once in 15 minutes.",
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
softWrap: true,
|
||||
),
|
||||
Container(height: Sizes.rowPadding,),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text("Enable"),
|
||||
Switch(
|
||||
value: _locationTrackingEnabled,
|
||||
onChanged: _wait ? null : (value) {
|
||||
setState(() {
|
||||
_locationTrackingEnabled = value;
|
||||
_wait = true;
|
||||
});
|
||||
_switchLocationTrackingState(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(height: Sizes.rowPadding),
|
||||
Text("Send device location every"),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
//Expanded(child: Container(),),
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(0.0),
|
||||
child: Text("-", style: Theme.of(context).textTheme.title),
|
||||
onPressed: () => _decLocationInterval(),
|
||||
),
|
||||
Text("$_locationInterval minutes", style: Theme.of(context).textTheme.title),
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(0.0),
|
||||
child: Text("+", style: Theme.of(context).textTheme.title),
|
||||
onPressed: () => _incLocationInterval(),
|
||||
),
|
||||
],
|
||||
),
|
||||
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,),
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Text("Enable"),
|
||||
Switch(
|
||||
value: _foregroundLocationTrackingEnabled,
|
||||
onChanged: _wait ? null : (value) {
|
||||
setState(() {
|
||||
_foregroundLocationTrackingEnabled = value;
|
||||
_wait = true;
|
||||
});
|
||||
_switchForegroundLocationTrackingState(value);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Container(height: Sizes.rowPadding),
|
||||
Text("Update device location every"),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: <Widget>[
|
||||
//Expanded(child: Container(),),
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(0.0),
|
||||
child: Text("-", style: Theme.of(context).textTheme.title),
|
||||
onPressed: _foregroundLocationTrackingEnabled ? null : () => _decActiveLocationInterval(),
|
||||
),
|
||||
Text("$_activeLocationInterval seconds",
|
||||
style: _foregroundLocationTrackingEnabled ? Theme.of(context).textTheme.title.copyWith(color: HAClientTheme().getDisabledStateColor(context)) : Theme.of(context).textTheme.title),
|
||||
FlatButton(
|
||||
padding: EdgeInsets.all(0.0),
|
||||
child: Text("+", style: Theme.of(context).textTheme.title),
|
||||
onPressed: _foregroundLocationTrackingEnabled ? null : () => _incActiveLocationInterval(),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
|
Reference in New Issue
Block a user