From ccbc2eec471d4f0718eee22ab3d90c3d5983ee07 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Tue, 7 Jul 2020 23:11:25 +0300 Subject: [PATCH 01/22] Syncfusion update --- lib/main.dart | 2 +- pubspec.yaml | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/main.dart b/lib/main.dart index 3539c9a..296c0c3 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -154,7 +154,7 @@ part 'managers/app_settings.dart'; EventBus eventBus = new EventBus(); const String appName = 'HA Client'; const String appVersion = String.fromEnvironment('versionName', defaultValue: '0.0.0'); -const whatsNewUrl = 'http://ha-client.app/service/whats_new_1.2.0.md'; +const whatsNewUrl = 'http://ha-client.app/service/whats_new_1.3.0.md'; Future _reportError(dynamic error, dynamic stackTrace) async { // Print the exception to the console. diff --git a/pubspec.yaml b/pubspec.yaml index a0b30dc..6dabe24 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1300 +version: 1.3.0+1301 environment: @@ -27,8 +27,8 @@ dependencies: hive_flutter: ^0.3.0+2 device_info: ^0.4.2+4 firebase_crashlytics: ^0.1.3+3 - syncfusion_flutter_core: ^18.1.52 - syncfusion_flutter_gauges: ^18.1.52 + syncfusion_flutter_core: ^18.2.44 + syncfusion_flutter_gauges: ^18.2.44 dev_dependencies: From 819dfc725d32683107e3d73fe903f0dc21a337c7 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Tue, 7 Jul 2020 23:42:21 +0300 Subject: [PATCH 02/22] Restart location service after app update --- android/app/src/main/AndroidManifest.xml | 3 ++- ...ionUpdatesAfterReboot.java => RestartLocationUpdate.java} | 5 +++-- pubspec.yaml | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) rename android/app/src/main/java/com/keyboardcrumbs/hassclient/{LocationUpdatesAfterReboot.java => RestartLocationUpdate.java} (56%) diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index fb61996..a36dfda 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -72,9 +72,10 @@ - + + Date: Wed, 8 Jul 2020 10:54:41 +0300 Subject: [PATCH 03/22] Fix type cast error in location util --- .../java/com/keyboardcrumbs/hassclient/LocationUtils.java | 2 +- lib/pages/settings/integration_settings.part.dart | 7 +++++-- pubspec.yaml | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index 60521e7..41508b9 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -38,7 +38,7 @@ class LocationUtils { 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); + return (int) context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_REQUESTING_LOCATION_UPDATES, LOCATION_UPDATES_DISABLED); } static long getLocationUpdateIntervals(Context context) { diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index 972f704..e3f7705 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -97,10 +97,13 @@ class _IntegrationSettingsPageState extends State { } _switchLocationTrackingState(bool state) async { - await AppSettings().save({'location-updates-interval': _locationInterval.inSeconds, 'location-updates-priority': _accuracy, 'location-updates-show-notification': _showNotification}); if (state) { try { - await platform.invokeMethod('startLocationService'); + await platform.invokeMethod('startLocationService', { + 'location-updates-interval': _locationInterval.inSeconds, + 'location-updates-priority': _accuracy, + 'location-updates-show-notification': _showNotification + }); } catch (e) { _locationTrackingEnabled = false; } diff --git a/pubspec.yaml b/pubspec.yaml index a157e62..3797369 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1302 +version: 1.3.0+1303 environment: From 2fb296b7a8e1f3abd5d61e6598a51e6dc0b46db6 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 11:12:30 +0300 Subject: [PATCH 04/22] Resolves #575 Location settings --- .../hassclient/LocationUtils.java | 11 +++- .../hassclient/MainActivity.java | 51 +++++++++++-------- 2 files changed, 40 insertions(+), 22 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index 41508b9..59cbb8a 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -38,7 +38,7 @@ class LocationUtils { static final long MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS = 900000; //15 minutes static int getLocationUpdatesState(Context context) { - return (int) context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_REQUESTING_LOCATION_UPDATES, LOCATION_UPDATES_DISABLED); + return (int) context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_REQUESTING_LOCATION_UPDATES, LOCATION_UPDATES_DISABLED); } static long getLocationUpdateIntervals(Context context) { @@ -60,6 +60,15 @@ class LocationUtils { .apply(); } + static void setLocationUpdatesSettings(Context context, int priority, long interval, boolean showNotification) { + context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) + .edit() + .putInt(KEY_LOCATION_UPDATE_PRIORITY, priority) + .putBoolean(KEY_LOCATION_SHOW_NOTIFICATION, showNotification) + .putLong(KEY_LOCATION_UPDATE_INTERVAL, interval/1000) + .apply(); + } + static String getLocationText(Location location) { return location == null ? "Accuracy: unknown" : "Accuracy: " + location.getAccuracy(); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java index a598237..a631177 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java @@ -39,35 +39,40 @@ public class MainActivity extends FlutterActivity { Context context = getActivity(); switch (call.method) { case "getFCMToken": - if (checkPlayServices()) { - FirebaseInstanceId.getInstance().getInstanceId() - .addOnCompleteListener(task -> { - if (task.isSuccessful()) { - String token = task.getResult().getToken(); - context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).edit().putString("flutter.npush-token", token).apply(); - result.success(token); - } else { - Exception ex = task.getException(); - if (ex != null) { - result.error("fcm_error", ex.getMessage(), null); + try { + if (checkPlayServices()) { + FirebaseInstanceId.getInstance().getInstanceId() + .addOnCompleteListener(task -> { + if (task.isSuccessful()) { + String token = task.getResult().getToken(); + context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).edit().putString("flutter.npush-token", token).apply(); + result.success(token); } else { - result.error("fcm_error", "Unknown", null); - } + 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); + } + }); + } else { + result.error("google_play_service_error", "Google Play Services unavailable", null); + } + } catch (Exception e) { + result.error("get_token_exception", e.getMessage(), e); } break; case "startLocationService": try { - locationUpdatesInterval = LocationUtils.getLocationUpdateIntervals(this); + locationUpdatesInterval = (long) call.argument("location-updates-interval") * 1000; if (locationUpdatesInterval >= LocationUtils.MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS) { locationUpdatesType = LocationUtils.LOCATION_UPDATES_WORKER; } else { locationUpdatesType = LocationUtils.LOCATION_UPDATES_SERVICE; } + LocationUtils.setLocationUpdatesSettings(this, (int)call.argument("location-updates-priority"), locationUpdatesInterval, (boolean)call.argument("location-updates-show-notification")); if (isNoLocationPermissions()) { requestLocationPermissions(); } else { @@ -75,12 +80,16 @@ public class MainActivity extends FlutterActivity { } result.success(""); } catch (Exception e) { - result.error("location_error", e.getMessage(), null); + result.error("location_error", e.getMessage(), e); } break; case "stopLocationService": - stopLocationUpdates(); - result.success(""); + try { + stopLocationUpdates(); + result.success(""); + } catch (Exception e) { + result.error("location_error", e.getMessage(), e); + } break; case "cancelOldLocationWorker": WorkManager.getInstance(this).cancelAllWorkByTag("haclocation"); From 5aa6171c505bf9a6707b4963e17c7c007bc1a98c Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 11:49:05 +0300 Subject: [PATCH 05/22] Location fixes --- .../hassclient/LocationUpdatesService.java | 4 ---- .../hassclient/LocationUpdatesWorker.java | 7 ------- .../com/keyboardcrumbs/hassclient/LocationUtils.java | 10 +++++----- .../com/keyboardcrumbs/hassclient/MainActivity.java | 4 ++-- lib/pages/settings/integration_settings.part.dart | 4 ++-- 5 files changed, 9 insertions(+), 20 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java index 975bdf8..c9992c5 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java @@ -136,10 +136,6 @@ public class LocationUpdatesService extends Service { OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(SendDataHomeWorker.class) - .setBackoffCriteria( - BackoffPolicy.EXPONENTIAL, - 10, - TimeUnit.SECONDS) .setConstraints(constraints) .setInputData(locationData) .build(); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java index 7dcee13..c37cf30 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java @@ -1,6 +1,5 @@ package com.keyboardcrumbs.hassclient; -import android.app.AlarmManager; import android.app.NotificationChannel; import android.app.NotificationManager; import android.content.Context; @@ -29,8 +28,6 @@ import com.google.common.util.concurrent.ListenableFuture; import java.util.concurrent.TimeUnit; -import static android.content.Context.NOTIFICATION_SERVICE; - public class LocationUpdatesWorker extends ListenableWorker { private Context currentContext; @@ -73,10 +70,6 @@ public class LocationUpdatesWorker extends ListenableWorker { OneTimeWorkRequest uploadWorkRequest = new OneTimeWorkRequest.Builder(SendDataHomeWorker.class) - .setBackoffCriteria( - BackoffPolicy.EXPONENTIAL, - 10, - TimeUnit.SECONDS) .setConstraints(constraints) .setInputData(locationData) .build(); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index 59cbb8a..237f819 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -34,19 +34,19 @@ class LocationUtils { 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 int DEFAULT_LOCATION_UPDATE_INTERVAL_MS = 900000; //15 minutes static final long MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS = 900000; //15 minutes static int getLocationUpdatesState(Context context) { - return (int) context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_REQUESTING_LOCATION_UPDATES, LOCATION_UPDATES_DISABLED); + 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; + return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_LOCATION_UPDATE_INTERVAL, DEFAULT_LOCATION_UPDATE_INTERVAL_MS); } static int getLocationUpdatesPriority(Context context) { - return (int) context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_LOCATION_UPDATE_PRIORITY, 102); + return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_LOCATION_UPDATE_PRIORITY, 102); } static boolean showNotification(Context context) { @@ -65,7 +65,7 @@ class LocationUtils { .edit() .putInt(KEY_LOCATION_UPDATE_PRIORITY, priority) .putBoolean(KEY_LOCATION_SHOW_NOTIFICATION, showNotification) - .putLong(KEY_LOCATION_UPDATE_INTERVAL, interval/1000) + .putLong(KEY_LOCATION_UPDATE_INTERVAL, interval) .apply(); } diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java index a631177..64321f1 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java @@ -29,7 +29,7 @@ public class MainActivity extends FlutterActivity { private static final int REQUEST_PERMISSIONS_REQUEST_CODE = 34; private int locationUpdatesType = LocationUtils.LOCATION_UPDATES_DISABLED; - private long locationUpdatesInterval = LocationUtils.DEFAULT_LOCATION_UPDATE_INTERVAL_S * 1000; + private long locationUpdatesInterval = LocationUtils.DEFAULT_LOCATION_UPDATE_INTERVAL_MS; @Override public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) { @@ -66,7 +66,7 @@ public class MainActivity extends FlutterActivity { break; case "startLocationService": try { - locationUpdatesInterval = (long) call.argument("location-updates-interval") * 1000; + locationUpdatesInterval = ((Number)call.argument("location-updates-interval")).longValue(); if (locationUpdatesInterval >= LocationUtils.MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS) { locationUpdatesType = LocationUtils.LOCATION_UPDATES_WORKER; } else { diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index e3f7705..64bf713 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -40,7 +40,7 @@ class _IntegrationSettingsPageState extends State { _accuracy = prefs.getInt("location-updates-priority") ?? 102; _locationTrackingEnabled = (prefs.getInt("location-updates-state") ?? 0) > 0; _showNotification = prefs.getBool("location-updates-show-notification") ?? true; - _locationInterval = Duration(seconds: prefs.getInt("location-updates-interval") ?? + _locationInterval = Duration(milliseconds: prefs.getInt("location-updates-interval") ?? AppSettings().defaultLocationUpdateIntervalSeconds); }); }); @@ -100,7 +100,7 @@ class _IntegrationSettingsPageState extends State { if (state) { try { await platform.invokeMethod('startLocationService', { - 'location-updates-interval': _locationInterval.inSeconds, + 'location-updates-interval': _locationInterval.inMilliseconds, 'location-updates-priority': _accuracy, 'location-updates-show-notification': _showNotification }); From a8e7ab6f06849b5593102ae7bea1465170c6e73e Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 14:21:00 +0300 Subject: [PATCH 06/22] Location notification tweeks --- .../hassclient/LocationUpdatesService.java | 4 ++- .../hassclient/LocationUpdatesWorker.java | 4 ++- .../hassclient/LocationUtils.java | 28 ++++++++---------- .../main/res/drawable/mini_icon_location.png | Bin 0 -> 571 bytes .../settings/integration_settings.part.dart | 6 ++-- pubspec.yaml | 2 +- 6 files changed, 21 insertions(+), 23 deletions(-) create mode 100644 android/app/src/main/res/drawable/mini_icon_location.png diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java index c9992c5..cb82f82 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java @@ -107,7 +107,9 @@ public class LocationUpdatesService extends Service { Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority); mLocationRequest.setPriority(priority); mLocationRequest.setInterval(requestInterval); - mLocationRequest.setFastestInterval(requestInterval); + if (priority == 102 && requestInterval > 60000) { + mLocationRequest.setFastestInterval(30000); + } startForeground(LocationUtils.SERVICE_NOTIFICATION_ID, LocationUtils.getNotification(this, null, LocationUtils.SERVICE_NOTIFICATION_CHANNEL_ID)); try { mFusedLocationClient.requestLocationUpdates(mLocationRequest, diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java index c37cf30..e69c930 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java @@ -102,7 +102,9 @@ public class LocationUpdatesWorker extends ListenableWorker { int accuracy = LocationUtils.getLocationUpdatesPriority(getApplicationContext()); locationRequest.setPriority(accuracy); locationRequest.setInterval(5000); - locationRequest.setFastestInterval(1000); + if (accuracy == 102) { + locationRequest.setFastestInterval(1000); + } try { fusedLocationClient.requestLocationUpdates(locationRequest, callback, Looper.myLooper()); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index 237f819..99f7c0a 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -46,7 +46,7 @@ class LocationUtils { } static int getLocationUpdatesPriority(Context context) { - return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_LOCATION_UPDATE_PRIORITY, 102); + return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_LOCATION_UPDATE_PRIORITY, 100); } static boolean showNotification(Context context) { @@ -69,15 +69,6 @@ class LocationUtils { .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); @@ -93,19 +84,24 @@ class LocationUtils { } static Notification getNotification(Context context, Location location, String channelId) { - CharSequence text = LocationUtils.getLocationText(location); + CharSequence title = "Location tracking"; + CharSequence text = location == null ? "Accuracy: unknown" : "Accuracy: " + location.getAccuracy() + " m"; + CharSequence bigText = location == null ? "Waiting for location..." : "Location updated at " + DateFormat.getDateTimeInstance().format(new Date(location.getTime())) + + System.getProperty("line.separator") + "Accuracy: " + location.getAccuracy() + " m" + + System.getProperty("line.separator") + "Location: " + location.getLatitude() + ", " + location.getLongitude(); - PendingIntent activityPendingIntent = PendingIntent.getActivity(context, 0, + PendingIntent activityPendingIntent = PendingIntent.getActivity(context, 0, new Intent(context, MainActivity.class), 0); NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId) - .addAction(R.drawable.blank_icon, "Open HA Client", - activityPendingIntent) + .setContentIntent(activityPendingIntent) + .setContentTitle(title) .setContentText(text) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(bigText)) .setPriority(-1) - .setContentTitle(LocationUtils.getLocationTitle(location)) .setOngoing(true) - .setSmallIcon(R.drawable.mini_icon) + .setSmallIcon(R.drawable.mini_icon_location) .setWhen(System.currentTimeMillis()); return builder.build(); diff --git a/android/app/src/main/res/drawable/mini_icon_location.png b/android/app/src/main/res/drawable/mini_icon_location.png new file mode 100644 index 0000000000000000000000000000000000000000..08dbb4ee96b43b1d253494bcefde1726a1ff5073 GIT binary patch literal 571 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`GjEa{HEjtmSN`?>!lvI6-E$sR$z z3=CCj3=9n|3=F@3LJcn%7)lKo7+xhXFj&oCU=S~uvn$XBD8ZKG?d}4kf#9d}?s_1_ zS>O>_%)r2R1cVulHqbM43^HVa@DsgL=vn{m}s6i5BLvVgtNqJ&XDnogBxn5>oc5!lIL8@MUQTpt6 RHc~)E44$rjF6*2UngGXM){X!G literal 0 HcmV?d00001 diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index 64bf713..b31e67d 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -13,10 +13,8 @@ class _IntegrationSettingsPageState extends State { static const platform = const MethodChannel('com.keyboardcrumbs.hassclient/native'); static final locationAccuracy = { - 100: "Highest", - 102: "Balanced (about 100 meters)", - 104: "Low (up to 10 kilometers)", - 105: "Passive (last known location)", + 100: "High", + 102: "Balanced" }; Duration _locationInterval; diff --git a/pubspec.yaml b/pubspec.yaml index 3797369..f7c8aa7 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1303 +version: 1.3.0+1304 environment: From 3215556440ce6eb2091f3386f27f2e2c206bd22a Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 14:22:32 +0300 Subject: [PATCH 07/22] Resolves #574 --- .../java/com/keyboardcrumbs/hassclient/MessagingService.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java index 525588d..a04e325 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java @@ -103,6 +103,8 @@ public class MessagingService extends FirebaseMessagingService { .setSmallIcon(R.drawable.mini_icon) .setContentTitle(messageTitle) .setContentText(messageBody) + .setStyle(new NotificationCompat.BigTextStyle() + .bigText(messageBody)) .setAutoCancel(autoCancel) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); From d94cdf0d1bb90ebbc67802bba774ee373cc9c004 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 17:59:43 +0300 Subject: [PATCH 08/22] Fix long notification with images conflict --- .../java/com/keyboardcrumbs/hassclient/MessagingService.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java index a04e325..271583d 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java @@ -103,8 +103,6 @@ public class MessagingService extends FirebaseMessagingService { .setSmallIcon(R.drawable.mini_icon) .setContentTitle(messageTitle) .setContentText(messageBody) - .setStyle(new NotificationCompat.BigTextStyle() - .bigText(messageBody)) .setAutoCancel(autoCancel) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); @@ -114,6 +112,9 @@ public class MessagingService extends FirebaseMessagingService { notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(image).bigLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.blank_icon))); notificationBuilder.setLargeIcon(image); } + } else { + notificationBuilder.setStyle(new NotificationCompat.BigTextStyle() + .bigText(messageBody)); } for (int i = 1; i <= 3; i++) { if (data.containsKey("action" + i)) { From 2126bc4f0209bab1b034e1f87cddec55c9dcf1b4 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 18:01:22 +0300 Subject: [PATCH 09/22] Fix long notification with images conflict 2 --- .../keyboardcrumbs/hassclient/MessagingService.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java index 271583d..943d8fa 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java @@ -106,12 +106,13 @@ public class MessagingService extends FirebaseMessagingService { .setAutoCancel(autoCancel) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); + Bitmap image; if (URLUtil.isValidUrl(imageUrl)) { - Bitmap image = getBitmapFromURL(imageUrl); - if (image != null) { - notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(image).bigLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.blank_icon))); - notificationBuilder.setLargeIcon(image); - } + image = getBitmapFromURL(imageUrl); + } + if (image != null) { + notificationBuilder.setStyle(new NotificationCompat.BigPictureStyle().bigPicture(image).bigLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.blank_icon))); + notificationBuilder.setLargeIcon(image); } else { notificationBuilder.setStyle(new NotificationCompat.BigTextStyle() .bigText(messageBody)); From 01b8ec9b97838594e5b3b1c82419912e9233ea07 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 18:08:27 +0300 Subject: [PATCH 10/22] Resolves #576 Fix location tracking migration --- lib/managers/app_settings.dart | 14 +++++++------- lib/pages/settings/integration_settings.part.dart | 4 ++-- pubspec.yaml | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/managers/app_settings.dart b/lib/managers/app_settings.dart index 9a181a9..297822e 100644 --- a/lib/managers/app_settings.dart +++ b/lib/managers/app_settings.dart @@ -75,21 +75,21 @@ class AppSettings { bool oldLocationTrackingEnabled = prefs.getBool("location-enabled") ?? false; if (oldLocationTrackingEnabled) { await platform.invokeMethod('cancelOldLocationWorker'); - await prefs.setInt("location-updates-state", 2); //Setting new location tracking mode to worker - await prefs.setInt("location-updates-priority", 100); //Setting location accuracy to high int oldLocationTrackingInterval = prefs.getInt("location-interval") ?? 0; if (oldLocationTrackingInterval < 15) { oldLocationTrackingInterval = 15; } - await prefs.setInt("location-updates-interval", oldLocationTrackingInterval * 60); //moving old interval in minutes to new interval in seconds try { - await platform.invokeMethod('startLocationService'); - } catch (e) { - await prefs.setInt("location-updates-state", 0); //Disabling location tracking if can't start + await platform.invokeMethod('startLocationService', { + 'location-updates-interval': oldLocationTrackingInterval * 60 * 1000, + 'location-updates-priority': 100, + 'location-updates-show-notification': true + }); + } catch (e, stack) { + Logger.e("[MIGRATION] Can't start new location tracking: $e", stacktrace: stack); } } else { Logger.d("[MIGRATION] Old location tracking was disabled"); - await prefs.setInt("location-updates-state", 0); //Setting new location tracking mode to disabled } await prefs.setBool("location-tracking-migrated", true); } diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index b31e67d..a83c2cc 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -21,7 +21,7 @@ class _IntegrationSettingsPageState extends State { bool _locationTrackingEnabled = false; bool _wait = false; bool _showNotification = true; - int _accuracy = 102; + int _accuracy = 100; @override void initState() { @@ -35,7 +35,7 @@ class _IntegrationSettingsPageState extends State { await prefs.reload(); SharedPreferences.getInstance().then((prefs) { setState(() { - _accuracy = prefs.getInt("location-updates-priority") ?? 102; + _accuracy = prefs.getInt("location-updates-priority") ?? 100; _locationTrackingEnabled = (prefs.getInt("location-updates-state") ?? 0) > 0; _showNotification = prefs.getBool("location-updates-show-notification") ?? true; _locationInterval = Duration(milliseconds: prefs.getInt("location-updates-interval") ?? diff --git a/pubspec.yaml b/pubspec.yaml index f7c8aa7..f15e3f6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1304 +version: 1.3.0+1305 environment: From 595406bb7e40baf06e4ca3c8863c1578b31df4ff Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 18:30:31 +0300 Subject: [PATCH 11/22] Resolves #577 request_location_update notification support --- .../hassclient/LocationUtils.java | 23 ++++++++++++++----- .../hassclient/MessagingService.java | 16 ++++++++----- 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index 99f7c0a..f3cb0df 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -9,6 +9,8 @@ import android.os.Build; import androidx.core.app.NotificationCompat; import androidx.work.ExistingPeriodicWorkPolicy; +import androidx.work.ExistingWorkPolicy; +import androidx.work.OneTimeWorkRequest; import androidx.work.PeriodicWorkRequest; import androidx.work.WorkManager; @@ -28,7 +30,10 @@ class LocationUtils { static final String SERVICE_NOTIFICATION_CHANNEL_ID = "location_service"; static final int SERVICE_NOTIFICATION_ID = 954311; + static final String REQUEST_LOCATION_NOTIFICATION = "request_location_update"; + static final String LOCATION_WORK_NAME = "HALocationWorker"; + static final String LOCATION_REQUEST_NAME = "HALocationRequest"; static final int LOCATION_UPDATES_DISABLED = 0; static final int LOCATION_UPDATES_SERVICE = 1; @@ -83,6 +88,18 @@ class LocationUtils { } } + 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); + } + + static void requestLocationOnce(Context context) { + OneTimeWorkRequest oneTimeWork = new OneTimeWorkRequest.Builder(LocationUpdatesWorker.class) + .build(); + WorkManager.getInstance(context).enqueueUniqueWork(LocationUtils.LOCATION_REQUEST_NAME, ExistingWorkPolicy.REPLACE, oneTimeWork); + } + static Notification getNotification(Context context, Location location, String channelId) { CharSequence title = "Location tracking"; CharSequence text = location == null ? "Accuracy: unknown" : "Accuracy: " + location.getAccuracy() + " m"; @@ -106,10 +123,4 @@ class LocationUtils { return builder.build(); } - - static void startWorker(Context context, long interval) { - PeriodicWorkRequest periodicWork = new PeriodicWorkRequest.Builder(LocationUpdatesWorker.class, interval, TimeUnit.MILLISECONDS) - .build(); - WorkManager.getInstance(context).enqueueUniquePeriodicWork(LocationUtils.LOCATION_WORK_NAME, ExistingPeriodicWorkPolicy.REPLACE, periodicWork); - } } diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java index 943d8fa..ddfd233 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java @@ -47,6 +47,15 @@ public class MessagingService extends FirebaseMessagingService { private void sendNotification(Map data) { String channelId, messageBody, messageTitle, imageUrl, nTag, channelDescription; boolean autoCancel; + if (!data.containsKey("body")) { + messageBody = ""; + } else { + messageBody = data.get("body"); + } + if (messageBody != null && messageBody.equals(LocationUtils.REQUEST_LOCATION_NOTIFICATION)) { + LocationUtils.requestLocationOnce(this); + return; + } String customChannelId = data.get("channelId"); if (customChannelId == null) { channelId = "ha_notify"; @@ -55,11 +64,6 @@ public class MessagingService extends FirebaseMessagingService { channelId = customChannelId; channelDescription = channelId; } - if (!data.containsKey("body")) { - messageBody = ""; - } else { - messageBody = data.get("body"); - } if (!data.containsKey("title")) { messageTitle = "HA Client"; } else { @@ -106,7 +110,7 @@ public class MessagingService extends FirebaseMessagingService { .setAutoCancel(autoCancel) .setSound(defaultSoundUri) .setContentIntent(pendingIntent); - Bitmap image; + Bitmap image = null; if (URLUtil.isValidUrl(imageUrl)) { image = getBitmapFromURL(imageUrl); } From bc729563652a9a5985c576130838d8c3e5eae370 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 18:56:07 +0300 Subject: [PATCH 12/22] Remove location priority settings --- .../com/keyboardcrumbs/hassclient/LocationUpdatesService.java | 4 ++-- .../com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java index cb82f82..c9a2fe1 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java @@ -107,9 +107,9 @@ public class LocationUpdatesService extends Service { Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority); mLocationRequest.setPriority(priority); mLocationRequest.setInterval(requestInterval); - if (priority == 102 && requestInterval > 60000) { + /*if (priority == 102 && requestInterval > 60000) { mLocationRequest.setFastestInterval(30000); - } + }*/ startForeground(LocationUtils.SERVICE_NOTIFICATION_ID, LocationUtils.getNotification(this, null, LocationUtils.SERVICE_NOTIFICATION_CHANNEL_ID)); try { mFusedLocationClient.requestLocationUpdates(mLocationRequest, diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java index e69c930..04f3bec 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java @@ -102,9 +102,9 @@ public class LocationUpdatesWorker extends ListenableWorker { int accuracy = LocationUtils.getLocationUpdatesPriority(getApplicationContext()); locationRequest.setPriority(accuracy); locationRequest.setInterval(5000); - if (accuracy == 102) { + /*if (accuracy == 102) { locationRequest.setFastestInterval(1000); - } + }*/ try { fusedLocationClient.requestLocationUpdates(locationRequest, callback, Looper.myLooper()); From 40eb564c29aa53446106ce42145a9bf9d9f7feb6 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 20:21:34 +0300 Subject: [PATCH 13/22] Missed location changes --- .../hassclient/LocationUpdatesWorker.java | 1 - lib/cards/card.class.dart | 29 +++++++++++++++++++ lib/cards/map_card.dart | 25 ++++++++++++++++ lib/main.dart | 1 + lib/managers/app_settings.dart | 1 - .../settings/integration_settings.part.dart | 16 +++++----- 6 files changed, 62 insertions(+), 11 deletions(-) create mode 100644 lib/cards/map_card.dart diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java index 04f3bec..f239470 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java @@ -9,7 +9,6 @@ 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; diff --git a/lib/cards/card.class.dart b/lib/cards/card.class.dart index b7c6b73..b134673 100644 --- a/lib/cards/card.class.dart +++ b/lib/cards/card.class.dart @@ -644,6 +644,35 @@ class MarkdownCardData extends CardData { } +class MapCardData extends CardData { + + String title; + + @override + Widget buildCardWidget() { + return MapCard(card: this); + } + + MapCardData(rawData) : super(rawData) { + //Parsing card data + title = rawData['title']; + List geoLocationSources = rawData['geo_location_sources'] ?? []; + if (geoLocationSources.isNotEmpty) { + //TODO add entities by source + } + var rawEntities = rawData["entities"] ?? []; + rawEntities.forEach((rawEntity) { + if (rawEntity is String) { + if (HomeAssistant().entities.isExist(rawEntity)) { + entities.add( + EntityWrapper(entity: HomeAssistant().entities.get(rawEntity))); + } + } + }); + } + +} + class MediaControlCardData extends CardData { @override diff --git a/lib/cards/map_card.dart b/lib/cards/map_card.dart new file mode 100644 index 0000000..d376133 --- /dev/null +++ b/lib/cards/map_card.dart @@ -0,0 +1,25 @@ +part of '../main.dart'; + +class MapCard extends StatelessWidget { + final MapCardData card; + + const MapCard({Key key, this.card}) : super(key: key); + + @override + Widget build(BuildContext context) { + return CardWrapper( + child: Padding( + padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + CardHeader(name: card.title) + ], + ), + ) + ); + } + + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 296c0c3..feae6c2 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -58,6 +58,7 @@ part 'entities/entity_model.widget.dart'; part 'entities/default_entity_container.widget.dart'; part 'entities/missed_entity.widget.dart'; part 'cards/entity_button_card.dart'; +part 'cards/map_card.dart'; part 'pages/widgets/entity_attributes_list.dart'; part 'entities/entity_icon.widget.dart'; part 'entities/entity_name.widget.dart'; diff --git a/lib/managers/app_settings.dart b/lib/managers/app_settings.dart index 297822e..f72d6d9 100644 --- a/lib/managers/app_settings.dart +++ b/lib/managers/app_settings.dart @@ -33,7 +33,6 @@ class AppSettings { bool nextAlarmSensorCreated = false; DisplayMode displayMode; AppTheme appTheme; - final int defaultLocationUpdateIntervalSeconds = 900; bool get isAuthenticated => longLivedToken != null; bool get isTempAuthenticated => tempToken != null; diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index a83c2cc..cef68bf 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -12,10 +12,10 @@ class IntegrationSettingsPage extends StatefulWidget { class _IntegrationSettingsPageState extends State { static const platform = const MethodChannel('com.keyboardcrumbs.hassclient/native'); - static final locationAccuracy = { + /*static final locationAccuracy = { 100: "High", 102: "Balanced" - }; + };*/ Duration _locationInterval; bool _locationTrackingEnabled = false; @@ -35,11 +35,11 @@ class _IntegrationSettingsPageState extends State { await prefs.reload(); SharedPreferences.getInstance().then((prefs) { setState(() { - _accuracy = prefs.getInt("location-updates-priority") ?? 100; + _accuracy = /*prefs.getInt("location-updates-priority") ??*/ 100; _locationTrackingEnabled = (prefs.getInt("location-updates-state") ?? 0) > 0; _showNotification = prefs.getBool("location-updates-show-notification") ?? true; _locationInterval = Duration(milliseconds: prefs.getInt("location-updates-interval") ?? - AppSettings().defaultLocationUpdateIntervalSeconds); + 900000); }); }); } @@ -146,9 +146,7 @@ class _IntegrationSettingsPageState extends State { } if ((_locationInterval?.inMinutes ?? 15) < 15) { notes.add(_getNoteWidget('* Notification is mandatory for location updates with interval less than every 15 minutes', false)); - if (_accuracy < 102) { - notes.add(_getNoteWidget('* Battery consumption will be noticeable', true)); - } + notes.add(_getNoteWidget('* Battery consumption will be noticeable', true)); } if (notes.isEmpty) { return Container(width: 0, height: 0); @@ -184,7 +182,7 @@ class _IntegrationSettingsPageState extends State { ], ), Container(height: Sizes.rowPadding), - Text("Accuracy:", style: Theme.of(context).textTheme.body2), + /*Text("Accuracy:", style: Theme.of(context).textTheme.body2), Container(height: Sizes.rowPadding), DropdownButton( value: _accuracy, @@ -203,7 +201,7 @@ class _IntegrationSettingsPageState extends State { }); }, ), - Container(height: Sizes.rowPadding), + Container(height: Sizes.rowPadding),*/ Text("Update interval"), Row( mainAxisAlignment: MainAxisAlignment.center, From bf7983d72ea57d29c3da3396feb359d95d82ffa4 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 8 Jul 2020 20:22:00 +0300 Subject: [PATCH 14/22] Bump build number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index f15e3f6..90adf4a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1305 +version: 1.3.0+1306 environment: From d2d037e468cb7ad6508179be985a63d3c9cf1b23 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Mon, 20 Jul 2020 13:53:18 +0300 Subject: [PATCH 15/22] Map card WIP --- lib/cards/card.class.dart | 25 ++++++++-- lib/cards/map_card.dart | 74 ++++++++++++++++++++++++----- lib/main.dart | 3 ++ lib/pages/main/main.page.dart | 2 +- lib/utils/RandomColorGenerator.dart | 28 +++++++++++ lib/view.class.dart | 2 +- pubspec.yaml | 1 + 7 files changed, 118 insertions(+), 17 deletions(-) create mode 100644 lib/utils/RandomColorGenerator.dart diff --git a/lib/cards/card.class.dart b/lib/cards/card.class.dart index b134673..98bc6ef 100644 --- a/lib/cards/card.class.dart +++ b/lib/cards/card.class.dart @@ -21,7 +21,6 @@ class CardData { switch (rawData['type']) { case CardType.ENTITIES: case CardType.HISTORY_GRAPH: - case CardType.MAP: case CardType.PICTURE_GLANCE: case CardType.SENSOR: case CardType.ENTITY: @@ -47,6 +46,9 @@ class CardData { return CardData(null); } break; + case CardType.MAP: + return MapCardData(rawData); + break; case CardType.ENTITY_BUTTON: case CardType.BUTTON: case CardType.PICTURE_ENTITY: @@ -656,7 +658,7 @@ class MapCardData extends CardData { MapCardData(rawData) : super(rawData) { //Parsing card data title = rawData['title']; - List geoLocationSources = rawData['geo_location_sources'] ?? []; + List geoLocationSources = rawData['geo_location_sources'] ?? []; if (geoLocationSources.isNotEmpty) { //TODO add entities by source } @@ -664,8 +666,25 @@ class MapCardData extends CardData { rawEntities.forEach((rawEntity) { if (rawEntity is String) { if (HomeAssistant().entities.isExist(rawEntity)) { + entities.add(EntityWrapper(entity: HomeAssistant().entities.get(rawEntity))); + } else { + entities.add(EntityWrapper(entity: Entity.missed(rawEntity))); + } + } else { + if (HomeAssistant().entities.isExist(rawEntity["entity"])) { + Entity e = HomeAssistant().entities.get(rawEntity["entity"]); entities.add( - EntityWrapper(entity: HomeAssistant().entities.get(rawEntity))); + EntityWrapper( + entity: e, + stateColor: stateColor, + overrideName: rawEntity["name"]?.toString(), + overrideIcon: rawEntity["icon"], + stateFilter: rawEntity['state_filter'] ?? [], + uiAction: EntityUIAction(rawEntityData: rawEntity) + ) + ); + } else { + entities.add(EntityWrapper(entity: Entity.missed(rawEntity["entity"]))); } } }); diff --git a/lib/cards/map_card.dart b/lib/cards/map_card.dart index d376133..e38318a 100644 --- a/lib/cards/map_card.dart +++ b/lib/cards/map_card.dart @@ -1,25 +1,75 @@ part of '../main.dart'; -class MapCard extends StatelessWidget { +class MapCard extends StatefulWidget { final MapCardData card; const MapCard({Key key, this.card}) : super(key: key); + @override + _MapCardState createState() => _MapCardState(); +} + +class _MapCardState extends State { + + GlobalKey _mapKey = new GlobalKey(); + MapController mapController = MapController(); + @override Widget build(BuildContext context) { + List markers = []; + List points = []; + widget.card.entities.forEach((entityWrapper) { + double lat = entityWrapper.entity._getDoubleAttributeValue("latitude"); + double long = entityWrapper.entity._getDoubleAttributeValue("longitude"); + if (lat != null && long != null) { + points.add(LatLng(lat, long)); + markers.add( + Marker( + width: 36, + height: 36, + point: LatLng(lat, long), + builder: (ctx) => EntityModel( + handleTap: true, + entityWrapper: entityWrapper, + child: EntityIcon( + size: 36, + ), + ) + ) + ); + } + }); return CardWrapper( - child: Padding( - padding: EdgeInsets.fromLTRB(Sizes.leftWidgetPadding, Sizes.rowPadding, Sizes.rightWidgetPadding, Sizes.rowPadding), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - CardHeader(name: card.title) - ], - ), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + CardHeader(name: widget.card.title), + AspectRatio( + aspectRatio: 1, + child: GestureDetector( + child: FlutterMap( + key: _mapKey, + mapController: mapController, + options: new MapOptions( + interactive: true, + bounds: LatLngBounds.fromPoints(points), + boundsOptions: FitBoundsOptions(padding: EdgeInsets.all(30)), + ), + layers: [ + new TileLayerOptions( + urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + subdomains: ['a', 'b', 'c'] + ), + new MarkerLayerOptions( + markers: markers, + ), + ], + ) + ), + ) + ], ) ); } - - } \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index feae6c2..790e76b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -27,12 +27,15 @@ import 'package:flutter_webview_plugin/flutter_webview_plugin.dart' as standalon import 'package:webview_flutter/webview_flutter.dart'; import 'package:syncfusion_flutter_core/core.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; +import 'package:flutter_map/flutter_map.dart'; +import 'package:latlong/latlong.dart'; import 'utils/logger.dart'; import '.secrets.dart'; part 'const.dart'; part 'utils/launcher.dart'; +part 'utils/RandomColorGenerator.dart'; part 'entities/entity.class.dart'; part 'entities/entity_wrapper.class.dart'; part 'entities/timer/timer_entity.class.dart'; diff --git a/lib/pages/main/main.page.dart b/lib/pages/main/main.page.dart index 03de9c3..a726915 100644 --- a/lib/pages/main/main.page.dart +++ b/lib/pages/main/main.page.dart @@ -408,7 +408,7 @@ class _MainPageState extends State with WidgetsBindingObserver, Ticker int currentViewCount = HomeAssistant().ui?.views?.length ?? 0; if (_previousViewCount != currentViewCount) { - Logger.d("Views count changed ($_previousViewCount->$currentViewCount). Creating new tabs controller."); + //Logger.d("Views count changed ($_previousViewCount->$currentViewCount). Creating new tabs controller."); _viewsTabController = TabController(vsync: this, length: currentViewCount); _previousViewCount = currentViewCount; } diff --git a/lib/utils/RandomColorGenerator.dart b/lib/utils/RandomColorGenerator.dart new file mode 100644 index 0000000..01dcfec --- /dev/null +++ b/lib/utils/RandomColorGenerator.dart @@ -0,0 +1,28 @@ +part of '../main.dart'; + +class RandomColorGenerator { + static const colorsList = [ + Colors.green, + Colors.purple, + Colors.indigo, + Colors.red, + Colors.orange, + Colors.cyan + ]; + + int _index = 0; + + Color getCurrent() { + return colorsList[_index]; + } + + Color getNext() { + if (_index < colorsList.length - 1) { + _index += 1; + } else { + _index = 1; + } + return getCurrent(); + } + +} \ No newline at end of file diff --git a/lib/view.class.dart b/lib/view.class.dart index 599fc2c..78f4fcc 100644 --- a/lib/view.class.dart +++ b/lib/view.class.dart @@ -74,7 +74,7 @@ class HAView { Widget build(BuildContext context) { return ViewWidget( - view: this, + view: this ); } } diff --git a/pubspec.yaml b/pubspec.yaml index 90adf4a..903da5c 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -29,6 +29,7 @@ dependencies: firebase_crashlytics: ^0.1.3+3 syncfusion_flutter_core: ^18.2.44 syncfusion_flutter_gauges: ^18.2.44 + flutter_map: ^0.10.1 dev_dependencies: From f87cff7a7e9ffa5a9aa04504c783fc92b8077efc Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Mon, 20 Jul 2020 15:21:31 +0300 Subject: [PATCH 16/22] Allow to choose foreground location servcie manualy --- .../hassclient/LocationUpdatesService.java | 13 ++-- .../hassclient/LocationUpdatesWorker.java | 6 +- .../hassclient/LocationUtils.java | 8 +-- .../hassclient/MainActivity.java | 11 ++-- lib/home_assistant.class.dart | 1 + lib/managers/app_settings.dart | 5 +- .../settings/integration_settings.part.dart | 64 ++++++++++++------- lib/panels/panel_class.dart | 2 +- pubspec.yaml | 2 +- 9 files changed, 64 insertions(+), 48 deletions(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java index c9a2fe1..365a46e 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java @@ -103,13 +103,16 @@ public class LocationUpdatesService extends Service { private void requestLocationUpdates() { long requestInterval = LocationUtils.getLocationUpdateIntervals(getApplicationContext()); - int priority = LocationUtils.getLocationUpdatesPriority(getApplicationContext()); - Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority); + int priority; + if (requestInterval >= 600000) { + mLocationRequest.setFastestInterval(60000); + priority = LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY; + } else { + priority = LocationRequest.PRIORITY_HIGH_ACCURACY; + } mLocationRequest.setPriority(priority); mLocationRequest.setInterval(requestInterval); - /*if (priority == 102 && requestInterval > 60000) { - mLocationRequest.setFastestInterval(30000); - }*/ + Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority); startForeground(LocationUtils.SERVICE_NOTIFICATION_ID, LocationUtils.getNotification(this, null, LocationUtils.SERVICE_NOTIFICATION_CHANNEL_ID)); try { mFusedLocationClient.requestLocationUpdates(mLocationRequest, diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java index f239470..1ed5db3 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesWorker.java @@ -98,12 +98,8 @@ public class LocationUpdatesWorker extends ListenableWorker { }; LocationRequest locationRequest = new LocationRequest(); - int accuracy = LocationUtils.getLocationUpdatesPriority(getApplicationContext()); - locationRequest.setPriority(accuracy); + locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); locationRequest.setInterval(5000); - /*if (accuracy == 102) { - locationRequest.setFastestInterval(1000); - }*/ try { fusedLocationClient.requestLocationUpdates(locationRequest, callback, Looper.myLooper()); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index f3cb0df..e1fcaeb 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -22,7 +22,6 @@ 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 KEY_LOCATION_SHOW_NOTIFICATION = "flutter.location-updates-show-notification"; static final String WORKER_NOTIFICATION_CHANNEL_ID = "location_worker"; @@ -50,10 +49,6 @@ class LocationUtils { return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getLong(KEY_LOCATION_UPDATE_INTERVAL, DEFAULT_LOCATION_UPDATE_INTERVAL_MS); } - static int getLocationUpdatesPriority(Context context) { - return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getInt(KEY_LOCATION_UPDATE_PRIORITY, 100); - } - static boolean showNotification(Context context) { return context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE).getBoolean(KEY_LOCATION_SHOW_NOTIFICATION, true); } @@ -65,10 +60,9 @@ class LocationUtils { .apply(); } - static void setLocationUpdatesSettings(Context context, int priority, long interval, boolean showNotification) { + static void setLocationUpdatesSettings(Context context, long interval, boolean showNotification) { context.getSharedPreferences("FlutterSharedPreferences", Context.MODE_PRIVATE) .edit() - .putInt(KEY_LOCATION_UPDATE_PRIORITY, priority) .putBoolean(KEY_LOCATION_SHOW_NOTIFICATION, showNotification) .putLong(KEY_LOCATION_UPDATE_INTERVAL, interval) .apply(); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java index 64321f1..f8d07b3 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MainActivity.java @@ -14,6 +14,7 @@ import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.location.Location; import android.os.Bundle; import io.flutter.plugin.common.MethodChannel; @@ -67,12 +68,14 @@ public class MainActivity extends FlutterActivity { case "startLocationService": try { locationUpdatesInterval = ((Number)call.argument("location-updates-interval")).longValue(); - if (locationUpdatesInterval >= LocationUtils.MIN_WORKER_LOCATION_UPDATE_INTERVAL_MS) { - locationUpdatesType = LocationUtils.LOCATION_UPDATES_WORKER; - } else { + boolean useForegroundService = (boolean)call.argument("foreground-location-tracking"); + + if (useForegroundService) { locationUpdatesType = LocationUtils.LOCATION_UPDATES_SERVICE; + } else { + locationUpdatesType = LocationUtils.LOCATION_UPDATES_WORKER; } - LocationUtils.setLocationUpdatesSettings(this, (int)call.argument("location-updates-priority"), locationUpdatesInterval, (boolean)call.argument("location-updates-show-notification")); + LocationUtils.setLocationUpdatesSettings(this, locationUpdatesInterval, (boolean)call.argument("location-updates-show-notification")); if (isNoLocationPermissions()) { requestLocationPermissions(); } else { diff --git a/lib/home_assistant.class.dart b/lib/home_assistant.class.dart index 885ff9d..4f2ae23 100644 --- a/lib/home_assistant.class.dart +++ b/lib/home_assistant.class.dart @@ -278,6 +278,7 @@ class HomeAssistant { _rawPanels = data; List dashboards = []; data.forEach((k,v) { + Logger.d('[HA] Panel $k: title=${v['title']}; component=${v['component_name']}'); String title = v['title'] == null ? "${k[0].toUpperCase()}${k.substring(1)}" : "${v['title'][0].toUpperCase()}${v['title'].substring(1)}"; if (v['component_name'] != null && v['component_name'] == 'lovelace') { dashboards.add( diff --git a/lib/managers/app_settings.dart b/lib/managers/app_settings.dart index f72d6d9..9754340 100644 --- a/lib/managers/app_settings.dart +++ b/lib/managers/app_settings.dart @@ -81,8 +81,9 @@ class AppSettings { try { await platform.invokeMethod('startLocationService', { 'location-updates-interval': oldLocationTrackingInterval * 60 * 1000, - 'location-updates-priority': 100, - 'location-updates-show-notification': true + //'location-updates-priority': 100, + 'location-updates-show-notification': true, + 'foreground-location-tracking': false }); } catch (e, stack) { Logger.e("[MIGRATION] Can't start new location tracking: $e", stacktrace: stack); diff --git a/lib/pages/settings/integration_settings.part.dart b/lib/pages/settings/integration_settings.part.dart index cef68bf..e0379d9 100644 --- a/lib/pages/settings/integration_settings.part.dart +++ b/lib/pages/settings/integration_settings.part.dart @@ -21,7 +21,8 @@ class _IntegrationSettingsPageState extends State { bool _locationTrackingEnabled = false; bool _wait = false; bool _showNotification = true; - int _accuracy = 100; + //int _accuracy = 100; + bool _useForegroundService = false; @override void initState() { @@ -35,9 +36,10 @@ class _IntegrationSettingsPageState extends State { await prefs.reload(); SharedPreferences.getInstance().then((prefs) { setState(() { - _accuracy = /*prefs.getInt("location-updates-priority") ??*/ 100; + //_accuracy = prefs.getInt("location-updates-priority") ?? 100; _locationTrackingEnabled = (prefs.getInt("location-updates-state") ?? 0) > 0; _showNotification = prefs.getBool("location-updates-show-notification") ?? true; + _useForegroundService = prefs.getBool("foreground-location-tracking") ?? false; _locationInterval = Duration(milliseconds: prefs.getInt("location-updates-interval") ?? 900000); }); @@ -69,28 +71,20 @@ class _IntegrationSettingsPageState extends State { } void _decLocationInterval() { - if (_locationInterval.inSeconds > 5) { - if (_locationInterval.inSeconds <= 60) { - setState(() { + if ((_useForegroundService && _locationInterval.inSeconds > 5) || (!_useForegroundService && _locationInterval.inMinutes > 15)) { + setState(() { + if (_locationInterval.inSeconds <= 60) { _locationInterval = _locationInterval - Duration(seconds: 5); - }); - } else if (_locationInterval.inMinutes <= 15) { - setState(() { + } else if (_locationInterval.inMinutes <= 15) { _locationInterval = _locationInterval - Duration(minutes: 1); - }); - } else if (_locationInterval.inMinutes <= 60) { - setState(() { + } else if (_locationInterval.inMinutes <= 60) { _locationInterval = _locationInterval - Duration(minutes: 5); - }); - } else if (_locationInterval.inHours <= 4) { - setState(() { + } else if (_locationInterval.inHours <= 4) { _locationInterval = _locationInterval - Duration(minutes: 10); - }); - } else if (_locationInterval.inHours > 4) { - setState(() { + } else if (_locationInterval.inHours > 4) { _locationInterval = _locationInterval - Duration(hours: 1); - }); - } + } + }); } } @@ -99,7 +93,8 @@ class _IntegrationSettingsPageState extends State { try { await platform.invokeMethod('startLocationService', { 'location-updates-interval': _locationInterval.inMilliseconds, - 'location-updates-priority': _accuracy, + //'location-updates-priority': _accuracy, + 'foreground-location-tracking': _useForegroundService, 'location-updates-show-notification': _showNotification }); } catch (e) { @@ -144,8 +139,12 @@ class _IntegrationSettingsPageState extends State { if (_locationTrackingEnabled) { notes.add(_getNoteWidget('* Stop location tracking to change settings', false)); } - if ((_locationInterval?.inMinutes ?? 15) < 15) { - notes.add(_getNoteWidget('* Notification is mandatory for location updates with interval less than every 15 minutes', false)); + if (_useForegroundService) { + notes.add(_getNoteWidget('* Notification is mandatory for foreground service', false)); + } else { + notes.add(_getNoteWidget('* Use foreground service for intervals less then 15 minutes', false)); + } + if (_useForegroundService && _locationInterval.inMinutes < 10) { notes.add(_getNoteWidget('* Battery consumption will be noticeable', true)); } if (notes.isEmpty) { @@ -182,6 +181,25 @@ class _IntegrationSettingsPageState extends State { ], ), Container(height: Sizes.rowPadding), + Row( + children: [ + Text("Use foreground service"), + Switch( + value: _useForegroundService, + onChanged: _locationTrackingEnabled ? null : (value) { + setState(() { + _useForegroundService = value; + if (!_useForegroundService && _locationInterval.inMinutes < 15) { + _locationInterval = Duration(minutes: 15); + } else if (_useForegroundService) { + _showNotification = true; + } + }); + }, + ), + ], + ), + Container(height: Sizes.rowPadding), /*Text("Accuracy:", style: Theme.of(context).textTheme.body2), Container(height: Sizes.rowPadding), DropdownButton( @@ -231,7 +249,7 @@ class _IntegrationSettingsPageState extends State { Text("Show notification"), Switch( value: _showNotification, - onChanged: (_locationTrackingEnabled || (_locationInterval?.inMinutes ?? 0) < 15) ? null : (value) { + onChanged: (_locationTrackingEnabled || _useForegroundService) ? null : (value) { setState(() { _showNotification = value; }); diff --git a/lib/panels/panel_class.dart b/lib/panels/panel_class.dart index 745bdb1..bde9040 100644 --- a/lib/panels/panel_class.dart +++ b/lib/panels/panel_class.dart @@ -39,7 +39,7 @@ class Panel { eventBus.fire(ReloadUIEvent()); }); } else { - Launcher.launchAuthenticatedWebView(context: context, url: "${AppSettings().httpWebHost}/$urlPath", title: "${this.title}"); + Launcher.launchAuthenticatedWebView(context: context, url: "${AppSettings().httpWebHost}/$urlPath", title: "Back to app"); } } diff --git a/pubspec.yaml b/pubspec.yaml index 903da5c..9f2f10b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1306 +version: 1.3.0+1307 environment: From f4b6d7a33233b6b51d2b17d4ef1dccdd32582541 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Mon, 20 Jul 2020 16:23:12 +0300 Subject: [PATCH 17/22] Location requests through foreground service --- android/app/src/main/AndroidManifest.xml | 4 + .../hassclient/LocationRequestService.java | 146 ++++++++++++++++++ .../hassclient/LocationUpdatesService.java | 14 +- .../hassclient/LocationUtils.java | 31 +++- 4 files changed, 185 insertions(+), 10 deletions(-) create mode 100644 android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationRequestService.java diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index a36dfda..688d50b 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -60,6 +60,10 @@ android:name=".LocationUpdatesService" android:enabled="true" android:exported="false" /> + diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationRequestService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationRequestService.java new file mode 100644 index 0000000..f617756 --- /dev/null +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationRequestService.java @@ -0,0 +1,146 @@ +package com.keyboardcrumbs.hassclient; + +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.Service; +import android.content.Intent; +import android.location.Location; +import android.os.Build; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.Nullable; +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 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; + +public class LocationRequestService extends Service { + + private static final String TAG = LocationRequestService.class.getSimpleName(); + + private NotificationManager mNotificationManager; + + private LocationRequest mLocationRequest; + + private FusedLocationProviderClient mFusedLocationClient; + + private LocationCallback mLocationCallback; + + private Handler mServiceHandler; + + public LocationRequestService() { + } + + @Override + public void onCreate() { + mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); + + mLocationCallback = new LocationCallback() { + @Override + public void onLocationResult(LocationResult locationResult) { + super.onLocationResult(locationResult); + onNewLocation(locationResult.getLastLocation()); + } + }; + + mLocationRequest = new LocationRequest(); + + HandlerThread handlerThread = new HandlerThread(TAG); + handlerThread.start(); + mServiceHandler = new Handler(handlerThread.getLooper()); + mNotificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + CharSequence name = "Location requests"; + NotificationChannel mChannel = + new NotificationChannel(LocationUtils.ONETIME_NOTIFICATION_CHANNEL_ID, name, NotificationManager.IMPORTANCE_LOW); + + mNotificationManager.createNotificationChannel(mChannel); + } + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.i(TAG, "Service started. startId="+startId); + + requestLocationUpdates(); + + return START_STICKY; + } + + @Override + public void onDestroy() { + try { + mFusedLocationClient.removeLocationUpdates(mLocationCallback); + } catch (SecurityException unlikely) { + //When we lost permission + Log.i(TAG, "No location permission"); + } + mServiceHandler.removeCallbacksAndMessages(null); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private void requestLocationUpdates() { + Log.i(TAG, "Requesting location update in 5 seconds."); + mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + mLocationRequest.setInterval(5000); + + startForeground(LocationUtils.ONETIME_NOTIFICATION_ID, LocationUtils.getRequestNotification(this, null, LocationUtils.ONETIME_NOTIFICATION_CHANNEL_ID)); + try { + mFusedLocationClient.requestLocationUpdates(mLocationRequest, + mLocationCallback, Looper.myLooper()); + } catch (SecurityException unlikely) { + stopSelf(); + } + } + + private void onNewLocation(Location location) { + Log.i(TAG, "New location: " + location); + + mNotificationManager.notify(LocationUtils.ONETIME_NOTIFICATION_ID, LocationUtils.getRequestNotification( + this, + location, + LocationUtils.ONETIME_NOTIFICATION_CHANNEL_ID + )); + + 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) + .setConstraints(constraints) + .setInputData(locationData) + .build(); + + WorkManager + .getInstance(getApplicationContext()) + .enqueueUniqueWork("SendLocationUpdate", ExistingWorkPolicy.REPLACE, uploadWorkRequest); + stopSelf(); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java index 365a46e..fed23c9 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUpdatesService.java @@ -12,7 +12,6 @@ import android.os.IBinder; import android.os.Looper; import androidx.annotation.Nullable; -import androidx.work.BackoffPolicy; import androidx.work.Constraints; import androidx.work.Data; import androidx.work.ExistingWorkPolicy; @@ -28,8 +27,6 @@ import com.google.android.gms.location.LocationRequest; import com.google.android.gms.location.LocationResult; import com.google.android.gms.location.LocationServices; -import java.util.concurrent.TimeUnit; - public class LocationUpdatesService extends Service { private static final String TAG = LocationUpdatesService.class.getSimpleName(); @@ -77,7 +74,7 @@ public class LocationUpdatesService extends Service { @Override public int onStartCommand(Intent intent, int flags, int startId) { - Log.i(TAG, "Service started"); + Log.i(TAG, "Service started. startId="+startId); requestLocationUpdates(); @@ -110,9 +107,10 @@ public class LocationUpdatesService extends Service { } else { priority = LocationRequest.PRIORITY_HIGH_ACCURACY; } + Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority); mLocationRequest.setPriority(priority); mLocationRequest.setInterval(requestInterval); - Log.i(TAG, "Requesting location updates. Every " + requestInterval + "ms with priority of " + priority); + startForeground(LocationUtils.SERVICE_NOTIFICATION_ID, LocationUtils.getNotification(this, null, LocationUtils.SERVICE_NOTIFICATION_CHANNEL_ID)); try { mFusedLocationClient.requestLocationUpdates(mLocationRequest, @@ -125,7 +123,11 @@ public class LocationUpdatesService extends Service { private void onNewLocation(Location location) { Log.i(TAG, "New location: " + location); - mNotificationManager.notify(LocationUtils.SERVICE_NOTIFICATION_ID, LocationUtils.getNotification(this, location, LocationUtils.SERVICE_NOTIFICATION_CHANNEL_ID)); + mNotificationManager.notify(LocationUtils.SERVICE_NOTIFICATION_ID, LocationUtils.getNotification( + this, + location, + LocationUtils.SERVICE_NOTIFICATION_CHANNEL_ID + )); Constraints constraints = new Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index e1fcaeb..a0e024d 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -28,6 +28,8 @@ class LocationUtils { static final int WORKER_NOTIFICATION_ID = 954322; static final String SERVICE_NOTIFICATION_CHANNEL_ID = "location_service"; static final int SERVICE_NOTIFICATION_ID = 954311; + static final String ONETIME_NOTIFICATION_CHANNEL_ID = "location_request"; + static final int ONETIME_NOTIFICATION_ID = 954333; static final String REQUEST_LOCATION_NOTIFICATION = "request_location_update"; @@ -89,15 +91,17 @@ class LocationUtils { } static void requestLocationOnce(Context context) { - OneTimeWorkRequest oneTimeWork = new OneTimeWorkRequest.Builder(LocationUpdatesWorker.class) - .build(); - WorkManager.getInstance(context).enqueueUniqueWork(LocationUtils.LOCATION_REQUEST_NAME, ExistingWorkPolicy.REPLACE, oneTimeWork); + Intent myService = new Intent(context, LocationRequestService.class); + context.startService(myService); + //OneTimeWorkRequest oneTimeWork = new OneTimeWorkRequest.Builder(LocationUpdatesWorker.class) + // .build(); + //WorkManager.getInstance(context).enqueueUniqueWork(LocationUtils.LOCATION_REQUEST_NAME, ExistingWorkPolicy.REPLACE, oneTimeWork); } static Notification getNotification(Context context, Location location, String channelId) { CharSequence title = "Location tracking"; CharSequence text = location == null ? "Accuracy: unknown" : "Accuracy: " + location.getAccuracy() + " m"; - CharSequence bigText = location == null ? "Waiting for location..." : "Location updated at " + DateFormat.getDateTimeInstance().format(new Date(location.getTime())) + + CharSequence bigText = location == null ? "Waiting for location..." : "Time: " + DateFormat.getDateTimeInstance().format(new Date(location.getTime())) + System.getProperty("line.separator") + "Accuracy: " + location.getAccuracy() + " m" + System.getProperty("line.separator") + "Location: " + location.getLatitude() + ", " + location.getLongitude(); @@ -117,4 +121,23 @@ class LocationUtils { return builder.build(); } + + static Notification getRequestNotification(Context context, Location location, String channelId) { + CharSequence title = "Updating location..."; + CharSequence text = location == null ? "Waiting for location..." : "Accuracy: " + location.getAccuracy() + " m"; + + PendingIntent activityPendingIntent = PendingIntent.getActivity(context, 0, + new Intent(context, MainActivity.class), 0); + + NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId) + .setContentIntent(activityPendingIntent) + .setContentTitle(title) + .setContentText(text) + .setPriority(-1) + .setOngoing(true) + .setSmallIcon(R.drawable.mini_icon_location) + .setWhen(System.currentTimeMillis()); + + return builder.build(); + } } From 5ab34cd32f54fd0330c8b82a6873def58324d7ac Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Mon, 20 Jul 2020 23:41:13 +0300 Subject: [PATCH 18/22] Fix backround launch of location service --- .../java/com/keyboardcrumbs/hassclient/LocationUtils.java | 6 +++++- .../com/keyboardcrumbs/hassclient/MessagingService.java | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java index a0e024d..e651176 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/LocationUtils.java @@ -92,7 +92,11 @@ class LocationUtils { static void requestLocationOnce(Context context) { Intent myService = new Intent(context, LocationRequestService.class); - context.startService(myService); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + context.startForegroundService(myService); + } else { + context.startService(myService); + } //OneTimeWorkRequest oneTimeWork = new OneTimeWorkRequest.Builder(LocationUpdatesWorker.class) // .build(); //WorkManager.getInstance(context).enqueueUniqueWork(LocationUtils.LOCATION_REQUEST_NAME, ExistingWorkPolicy.REPLACE, oneTimeWork); diff --git a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java index ddfd233..7055e30 100644 --- a/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java +++ b/android/app/src/main/java/com/keyboardcrumbs/hassclient/MessagingService.java @@ -22,11 +22,14 @@ import com.google.firebase.messaging.RemoteMessage; import android.graphics.Bitmap; import android.graphics.BitmapFactory; +import android.util.Log; import android.webkit.URLUtil; public class MessagingService extends FirebaseMessagingService { + private static final String TAG = MessagingService.class.getSimpleName(); + public static final String NOTIFICATION_ACTION_BROADCAST = "com.keyboardcrumbs.hassclient.haNotificationAction"; @Override @@ -53,6 +56,7 @@ public class MessagingService extends FirebaseMessagingService { messageBody = data.get("body"); } if (messageBody != null && messageBody.equals(LocationUtils.REQUEST_LOCATION_NOTIFICATION)) { + Log.d(TAG, "Location update request received"); LocationUtils.requestLocationOnce(this); return; } From 9b0b90dba15ddf391ca0b7e950e95e0e18539650 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Mon, 20 Jul 2020 23:43:57 +0300 Subject: [PATCH 19/22] Bump version code --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 9f2f10b..bf4346d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1307 +version: 1.3.0+1308 environment: From f7d8bf9ae77d01d90f09d03086e9711afb3df336 Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Tue, 21 Jul 2020 16:29:08 +0300 Subject: [PATCH 20/22] Create EntitiesMap widget --- lib/cards/map_card.dart | 50 ++--------------------- lib/cards/widgets/entities_map.dart | 62 +++++++++++++++++++++++++++++ lib/main.dart | 2 + 3 files changed, 67 insertions(+), 47 deletions(-) create mode 100644 lib/cards/widgets/entities_map.dart diff --git a/lib/cards/map_card.dart b/lib/cards/map_card.dart index e38318a..1569040 100644 --- a/lib/cards/map_card.dart +++ b/lib/cards/map_card.dart @@ -11,62 +11,18 @@ class MapCard extends StatefulWidget { class _MapCardState extends State { - GlobalKey _mapKey = new GlobalKey(); - MapController mapController = MapController(); - @override Widget build(BuildContext context) { - List markers = []; - List points = []; - widget.card.entities.forEach((entityWrapper) { - double lat = entityWrapper.entity._getDoubleAttributeValue("latitude"); - double long = entityWrapper.entity._getDoubleAttributeValue("longitude"); - if (lat != null && long != null) { - points.add(LatLng(lat, long)); - markers.add( - Marker( - width: 36, - height: 36, - point: LatLng(lat, long), - builder: (ctx) => EntityModel( - handleTap: true, - entityWrapper: entityWrapper, - child: EntityIcon( - size: 36, - ), - ) - ) - ); - } - }); + return CardWrapper( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ CardHeader(name: widget.card.title), - AspectRatio( + EntitiesMap( aspectRatio: 1, - child: GestureDetector( - child: FlutterMap( - key: _mapKey, - mapController: mapController, - options: new MapOptions( - interactive: true, - bounds: LatLngBounds.fromPoints(points), - boundsOptions: FitBoundsOptions(padding: EdgeInsets.all(30)), - ), - layers: [ - new TileLayerOptions( - urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", - subdomains: ['a', 'b', 'c'] - ), - new MarkerLayerOptions( - markers: markers, - ), - ], - ) - ), + entities: widget.card.entities, ) ], ) diff --git a/lib/cards/widgets/entities_map.dart b/lib/cards/widgets/entities_map.dart new file mode 100644 index 0000000..f07b4d4 --- /dev/null +++ b/lib/cards/widgets/entities_map.dart @@ -0,0 +1,62 @@ +part of '../../main.dart'; + + +class EntitiesMap extends StatelessWidget { + + final List entities; + final bool interactive; + final double aspectRatio; + + const EntitiesMap({Key key, this.entities: const [], this.aspectRatio, this.interactive: false}) : super(key: key); + + @override + Widget build(BuildContext context) { + List markers = []; + List points = []; + entities.forEach((entityWrapper) { + double lat = entityWrapper.entity._getDoubleAttributeValue("latitude"); + double long = entityWrapper.entity._getDoubleAttributeValue("longitude"); + if (lat != null && long != null) { + points.add(LatLng(lat, long)); + markers.add( + Marker( + width: 36, + height: 36, + point: LatLng(lat, long), + builder: (ctx) => EntityModel( + handleTap: true, + entityWrapper: entityWrapper, + child: EntityIcon( + size: 36, + ), + ) + ) + ); + } + }); + Widget map = FlutterMap( + options: new MapOptions( + interactive: false, + bounds: LatLngBounds.fromPoints(points), + boundsOptions: FitBoundsOptions(padding: EdgeInsets.all(40)), + ), + layers: [ + new TileLayerOptions( + urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", + subdomains: ['a', 'b', 'c'] + ), + new MarkerLayerOptions( + markers: markers, + ), + ], + ); + if (aspectRatio != null) { + return AspectRatio( + aspectRatio: aspectRatio, + child: map + ); + } + return map; + } + +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 790e76b..92d0e13 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -29,6 +29,7 @@ import 'package:syncfusion_flutter_core/core.dart'; import 'package:syncfusion_flutter_gauges/gauges.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong/latlong.dart'; +import 'package:flutter/gestures.dart'; import 'utils/logger.dart'; import '.secrets.dart'; @@ -48,6 +49,7 @@ part 'entities/date_time/date_time_entity.class.dart'; part 'entities/light/light_entity.class.dart'; part 'entities/select/select_entity.class.dart'; part 'entities/sun/sun_entity.class.dart'; +part 'cards/widgets/entities_map.dart'; part 'entities/sensor/sensor_entity.class.dart'; part 'entities/slider/slider_entity.dart'; part 'entities/media_player/media_player_entity.class.dart'; From 3d27f207982d959a894fabfa1d43027f391c95ad Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 22 Jul 2020 13:32:34 +0300 Subject: [PATCH 21/22] Map fixes --- lib/cards/map_card.dart | 67 ++++++++++++++++++++++++++--- lib/cards/widgets/entities_map.dart | 23 +++++++--- 2 files changed, 79 insertions(+), 11 deletions(-) diff --git a/lib/cards/map_card.dart b/lib/cards/map_card.dart index 1569040..f298bfe 100644 --- a/lib/cards/map_card.dart +++ b/lib/cards/map_card.dart @@ -11,19 +11,76 @@ class MapCard extends StatefulWidget { class _MapCardState extends State { + void _openMap(BuildContext context) { + Navigator.of(context).push(MaterialPageRoute( + builder: (bc) { + return Scaffold( + primary: false, + /*appBar: new AppBar( + backgroundColor: Colors.transparent, + leading: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){ + Navigator.pop(context); + }), + actions: [ + IconButton( + icon: Icon(Icons.fullscreen), + onPressed: () {}, + ) + ], + // Here we take the value from the MyHomePage object that was created by + // the App.build method, and use it to set our appbar title. + title: new Text("${widget.card.title ?? ""}"), + ),*/ + body: Container( + color: Theme.of(context).primaryColor, + child: SafeArea( + child: Stack( + children: [ + EntitiesMap( + entities: widget.card.entities, + interactive: true + ), + Positioned( + top: 0, + left: 0, + child: IconButton(icon: Icon(Icons.arrow_back), onPressed: (){ + Navigator.pop(context); + }) + ) + ], + ) + ) + ) + ); + } + )); + } + @override Widget build(BuildContext context) { - return CardWrapper( child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ CardHeader(name: widget.card.title), - EntitiesMap( - aspectRatio: 1, - entities: widget.card.entities, - ) + Stack( + children: [ + GestureDetector( + onTap: () => _openMap(context), + child: EntitiesMap( + aspectRatio: 1, + interactive: false, + entities: widget.card.entities, + ) + ), + Positioned( + bottom: 0, + left: 0, + child: Text('Tap to open interactive map', style: Theme.of(context).textTheme.caption) + ) + ], + ), ], ) ); diff --git a/lib/cards/widgets/entities_map.dart b/lib/cards/widgets/entities_map.dart index f07b4d4..2ed5faa 100644 --- a/lib/cards/widgets/entities_map.dart +++ b/lib/cards/widgets/entities_map.dart @@ -6,8 +6,10 @@ class EntitiesMap extends StatelessWidget { final List entities; final bool interactive; final double aspectRatio; + final LatLng center; + final double zoom; - const EntitiesMap({Key key, this.entities: const [], this.aspectRatio, this.interactive: false}) : super(key: key); + const EntitiesMap({Key key, this.entities: const [], this.aspectRatio, this.interactive: true, this.center, this.zoom}) : super(key: key); @override Widget build(BuildContext context) { @@ -34,12 +36,22 @@ class EntitiesMap extends StatelessWidget { ); } }); - Widget map = FlutterMap( - options: new MapOptions( - interactive: false, + MapOptions mapOptions; + if (center != null) { + mapOptions = MapOptions( + interactive: interactive, + center: center, + zoom: zoom ?? 10, + ); + } else { + mapOptions = MapOptions( + interactive: interactive, bounds: LatLngBounds.fromPoints(points), boundsOptions: FitBoundsOptions(padding: EdgeInsets.all(40)), - ), + ); + } + Widget map = FlutterMap( + options: mapOptions, layers: [ new TileLayerOptions( urlTemplate: "https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png", @@ -58,5 +70,4 @@ class EntitiesMap extends StatelessWidget { } return map; } - } \ No newline at end of file From a66383828361297a58eeb56ae2541148a529adbe Mon Sep 17 00:00:00 2001 From: estevez-dev Date: Wed, 22 Jul 2020 13:33:24 +0300 Subject: [PATCH 22/22] Bump version code --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index bf4346d..78ab137 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,7 +1,7 @@ name: hass_client description: Home Assistant Android Client -version: 1.3.0+1308 +version: 1.3.0+1309 environment: