diff --git a/.idea/sonarlint.xml b/.idea/sonarlint.xml
new file mode 100644
index 0000000..5b670f2
--- /dev/null
+++ b/.idea/sonarlint.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 7822a96..4fca161 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -42,7 +42,8 @@ dependencies {
implementation 'com.google.android.gms:play-services-location:21.3.0'
// Glide
- implementation 'com.github.bumptech.glide:glide:4.16.0' // Check for the latest version
+ implementation 'com.github.bumptech.glide:glide:4.16.0'
+ implementation 'androidx.preference:preference:1.2.0'// Check for the latest version
annotationProcessor 'com.github.bumptech.glide:compiler:4.16.0'
//CircleImageView
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 9591bd0..df1d6c6 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -20,10 +20,15 @@
android:supportsRtl="true"
android:theme="@style/Theme.MyApplication"
tools:targetApi="31">
+
+
@@ -33,23 +38,23 @@
-
-
+
-
-
+
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/HelperGridActivity.java b/app/src/main/java/com/aldo/apps/familyhelpers/HelperGridActivity.java
index 9c276bd..5174f5b 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/HelperGridActivity.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/HelperGridActivity.java
@@ -50,6 +50,11 @@ public class HelperGridActivity extends AppCompatActivity {
*/
private HelperGroupTile mShareLocationTile;
+ /**
+ * {@link HelperGroupTile} holding the settings.
+ */
+ private HelperGroupTile mSettingsTile;
+
/**
* Instance of the {@link DevicePolicyManagerHelper} to roll out device specific actions.
*/
@@ -110,6 +115,7 @@ public class HelperGridActivity extends AppCompatActivity {
mDevicePolicyHelper = DevicePolicyManagerHelper.getInstance(this);
initSleepTimer();
initShareLocation();
+ initSettings();
}
/**
@@ -165,7 +171,21 @@ public class HelperGridActivity extends AppCompatActivity {
};
mShareLocationTile.setLogo(R.drawable.ic_location_helper);
mShareLocationTile.setTitle(R.string.title_share_location);
+ }
+ /**
+ * Helper method to initialize the settings tile.
+ */
+ private void initSettings() {
+ mSettingsTile = new HelperGroupTile(findViewById(R.id.tile_settings)) {
+ @Override
+ public void launchHelper() {
+ final Intent intent = new Intent(HelperGridActivity.this, SettingsActivity.class);
+ startActivity(intent);
+ }
+ };
+ mSettingsTile.setTitle(R.string.title_settings);
+ mSettingsTile.setLogo(R.drawable.ic_settings);
}
/**
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/SettingsActivity.java b/app/src/main/java/com/aldo/apps/familyhelpers/SettingsActivity.java
new file mode 100644
index 0000000..6ef3481
--- /dev/null
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/SettingsActivity.java
@@ -0,0 +1,39 @@
+package com.aldo.apps.familyhelpers;
+
+import android.os.Bundle;
+
+import androidx.appcompat.app.ActionBar;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.preference.PreferenceFragmentCompat;
+
+/**
+ * Simple Settings Activity for some app specific settings.
+ */
+public class SettingsActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(final Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.settings_activity);
+ if (savedInstanceState == null) {
+ getSupportFragmentManager()
+ .beginTransaction()
+ .replace(R.id.settings, new SettingsFragment())
+ .commit();
+ }
+ final ActionBar actionBar = getSupportActionBar();
+ if (actionBar != null) {
+ actionBar.setDisplayHomeAsUpEnabled(true);
+ }
+ }
+
+ /**
+ * The actual Settings fragment, containing the settings as defined in R.xml.root_preferences.
+ */
+ public static class SettingsFragment extends PreferenceFragmentCompat {
+ @Override
+ public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
+ setPreferencesFromResource(R.xml.root_preferences, rootKey);
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/workers/LocationHelper.java b/app/src/main/java/com/aldo/apps/familyhelpers/workers/LocationHelper.java
index 5383929..3da08a3 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/workers/LocationHelper.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/workers/LocationHelper.java
@@ -39,7 +39,6 @@ import io.reactivex.rxjava3.subjects.BehaviorSubject;
/**
* Helper class to encapsulate all Location specific calls into one utility class.
- * TODO: Change logic to make use of the FusedLocationProvider.
*/
public final class LocationHelper {
@@ -67,6 +66,10 @@ public final class LocationHelper {
*/
private final FusedLocationProviderClient mFusedLocationProvider;
+ /**
+ * The {@link LocationCallback} to be invoked by the {@link FusedLocationProviderClient} as soon
+ * as a new {@link LocationResult} was received.
+ */
private final LocationCallback mLocationCallback = new LocationCallback() {
@Override
public void onLocationResult(@NonNull final LocationResult locationResult) {
@@ -113,6 +116,11 @@ public final class LocationHelper {
*/
private boolean mIsSubscribed;
+ /**
+ * The currently selected frequency.
+ */
+ private int mCurrentFrequency = -1;
+
/**
* The current granularity used.
*/
@@ -219,8 +227,8 @@ public final class LocationHelper {
*/
public boolean startLocationUpdates(final Context context, final int minIntervalMillis,
final int minDistance, final int priority) {
- if (priority == mCurrentPriority) {
- Log.d(TAG, "startLocationUpdates: Already subscribed with this granularity, no need to update");
+ if (priority == mCurrentPriority && mCurrentFrequency == minIntervalMillis) {
+ Log.d(TAG, "startLocationUpdates: Already subscribed with this granularity and frequency, no need to update");
return true;
}
if (mIsSubscribed) {
@@ -230,7 +238,8 @@ public final class LocationHelper {
}
if (ContextCompat.checkSelfPermission(context, ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
mCurrentPriority = priority;
- final LocationRequest locationRequest = new LocationRequest.Builder(minIntervalMillis)
+ mCurrentFrequency = minIntervalMillis;
+ final LocationRequest locationRequest = new LocationRequest.Builder(mCurrentFrequency)
.setGranularity(GRANULARITY_FINE)
.setMinUpdateDistanceMeters(minDistance)
.setPriority(mCurrentPriority)
@@ -279,6 +288,12 @@ public final class LocationHelper {
return mSharingStateSubject;
}
+ /**
+ * Helper method to handle a received location by putting it to the database and inform listeners
+ * about the new location.
+ *
+ * @param location The received {@link Location}.
+ */
private void handleReceivedLocation(final Location location) {
final LocationObject locationObject = LocationObject.fromLocation(location);
Log.d(TAG, "onLocationChanged: Received update with " + locationObject);
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/workers/ShareLocationBackgroundWorker.java b/app/src/main/java/com/aldo/apps/familyhelpers/workers/ShareLocationBackgroundWorker.java
index 18ce427..58e4986 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/workers/ShareLocationBackgroundWorker.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/workers/ShareLocationBackgroundWorker.java
@@ -17,17 +17,21 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.Nullable;
+import androidx.preference.PreferenceManager;
+
+import com.aldo.apps.familyhelpers.R;
/**
* Service implementation to keep location updates running also in the background.
*/
-public class ShareLocationBackgroundWorker extends Service {
+public class ShareLocationBackgroundWorker extends Service implements SharedPreferences.OnSharedPreferenceChangeListener {
/**
* Tag for debugging purpose.
@@ -49,6 +53,24 @@ public class ShareLocationBackgroundWorker extends Service {
*/
private Runnable mShareLocationRunnable;
+ /**
+ * Integer holding the frequency in which updates shall be received. Defaults to
+ * {@link com.aldo.apps.familyhelpers.utils.GlobalConstants#DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS}
+ */
+ private int mSelectedFrequency;
+
+ /**
+ * Flag indicating whether the subscription priority shall be automatically selected based on
+ * charging state. Defaults to true.
+ */
+ private boolean mAutoPriority;
+
+ /**
+ * Flag indicatin whether the non-automatically selected priority shall be high accuracy (== true)
+ * or balanced power consumption (== false). Defaults to false.
+ */
+ private boolean mManualHighAccuracy;
+
@Override
public void onCreate() {
super.onCreate();
@@ -57,6 +79,11 @@ public class ShareLocationBackgroundWorker extends Service {
batteryFilter.addAction(ACTION_POWER_CONNECTED);
batteryFilter.addAction(ACTION_POWER_DISCONNECTED);
registerReceiver(new BatteryStateReceiver(), batteryFilter);
+ final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
+ mSelectedFrequency = preferences.getInt(getString(R.string.pref_key_share_location_freq), DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS);
+ mAutoPriority = preferences.getBoolean(getString(R.string.pref_key_share_location_auto_acc), true);
+ mManualHighAccuracy = preferences.getBoolean(getString(R.string.pref_key_share_location_man_acc), false);
+ preferences.registerOnSharedPreferenceChangeListener(this);
}
@Override
@@ -71,20 +98,7 @@ public class ShareLocationBackgroundWorker extends Service {
stopSelf();
return START_NOT_STICKY;
}
- final IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
- final Intent batteryStatus = registerReceiver(null, batteryFilter);
- final int priority;
- if (batteryStatus != null && batteryStatus.getIntExtra(EXTRA_STATUS, -1) == BATTERY_STATUS_CHARGING) {
- Log.d(TAG, "onStartCommand: Phone is charging, go for high accuracy");
- priority = PRIORITY_HIGH_ACCURACY;
- } else {
- Log.d(TAG, "onStartCommand: Status unknown or not charging, balanced power consumption.");
- priority = PRIORITY_BALANCED_POWER_ACCURACY;
- }
- mShareLocationRunnable = () ->
- mLocationHelper.startLocationUpdates(ShareLocationBackgroundWorker.this,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_METERS, priority);
+ mShareLocationRunnable = this::triggerLocationSharing;
mHandler.post(mShareLocationRunnable);
startForeground(SLEEP_TIMER_NOTIFICATION_ID, mLocationHelper.buildNotification(this));
return super.onStartCommand(intent, flags, startId);
@@ -103,6 +117,53 @@ public class ShareLocationBackgroundWorker extends Service {
super.onDestroy();
}
+ /**
+ * Triggers the location updates based on the preferences set in the application. Will read out the
+ * currently selected switch values for whether the priority should be selected automatically or not
+ * and if not it will take the selected priority from the setting. If auto selection is enabled, the
+ * priority will be selected based on the current charging state.
+ */
+ private void triggerLocationSharing() {
+ final int priority;
+ if (mAutoPriority) {
+ final IntentFilter batteryFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
+ final Intent batteryStatus = registerReceiver(null, batteryFilter);
+ if (batteryStatus != null && batteryStatus.getIntExtra(EXTRA_STATUS, -1) == BATTERY_STATUS_CHARGING) {
+ Log.d(TAG, "onStartCommand: Phone is charging, go for high accuracy");
+ priority = PRIORITY_HIGH_ACCURACY;
+ } else {
+ Log.d(TAG, "onStartCommand: Status unknown or not charging, balanced power consumption.");
+ priority = PRIORITY_BALANCED_POWER_ACCURACY;
+ }
+ } else if (mManualHighAccuracy) {
+ priority = PRIORITY_HIGH_ACCURACY;
+ } else {
+ priority = PRIORITY_BALANCED_POWER_ACCURACY;
+ }
+ mLocationHelper.startLocationUpdates(ShareLocationBackgroundWorker.this,
+ mSelectedFrequency,
+ DEFAULT_MINIMUM_LOCATION_INTERVAL_METERS, priority);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences, @Nullable final String key) {
+ if (!mLocationHelper.isCurrentlySharing()) {
+ Log.d(TAG, "onSharedPreferenceChanged: currently not sharing, nothing to do.");
+ return;
+ }
+ if (getString(R.string.pref_key_share_location_freq).equalsIgnoreCase(key)) {
+ mSelectedFrequency = sharedPreferences.getInt(key, DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS);
+ Log.d(TAG, "onSharedPreferenceChanged: Update Frequency changed to [" + mSelectedFrequency + "]");
+ } else if (getString(R.string.pref_key_share_location_auto_acc).equalsIgnoreCase(key)) {
+ mAutoPriority = sharedPreferences.getBoolean(key, true);
+ Log.d(TAG, "onSharedPreferenceChanged: Auto Priority switch changed to [" + mAutoPriority + "]");
+ } else if (getString(R.string.pref_key_share_location_man_acc).equalsIgnoreCase(key)) {
+ mManualHighAccuracy = sharedPreferences.getBoolean(key, false);
+ Log.d(TAG, "onSharedPreferenceChanged: HighPriority switch changed to [" + mManualHighAccuracy + "]");
+ }
+ triggerLocationSharing();
+ }
+
/**
* Base {@link BroadcastReceiver} to listen for the battery state update, listening for whether
* the device got plugged or unplugged.
@@ -115,24 +176,14 @@ public class ShareLocationBackgroundWorker extends Service {
Log.w(TAG, "onReceive: Empty intent, return...");
return;
}
- if (ACTION_POWER_CONNECTED.equals(intent.getAction())) {
- Log.d(TAG, "onReceive: Phone was plugged in, changing to high accuracy mode");
- mLocationHelper.startLocationUpdates(context,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_METERS,
- PRIORITY_HIGH_ACCURACY);
- } else if (ACTION_POWER_DISCONNECTED.equals(intent.getAction())) {
- Log.d(TAG, "onReceive: Phone was unplugged, changing to battery saving mode");
- mLocationHelper.startLocationUpdates(context,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_METERS,
- PRIORITY_BALANCED_POWER_ACCURACY);
- } else {
- Log.d(TAG, "onReceive: Unknown action [" + intent.getAction() + "], go to low power mode");
- mLocationHelper.startLocationUpdates(context,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_MILLIS,
- DEFAULT_MINIMUM_LOCATION_INTERVAL_METERS,
- PRIORITY_LOW_POWER);
+ if (!mAutoPriority) {
+ Log.d(TAG, "onReceive: Automatic priority selection is not selected, no need to update.");
+ return;
+ }
+ final String action = intent.getAction();
+ if (ACTION_POWER_CONNECTED.equals(action) || ACTION_POWER_DISCONNECTED.equals(action)) {
+ Log.d(TAG, "onReceive: Received [" + action + "], with automatic prio, retrigger");
+ triggerLocationSharing();
}
}
}
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
new file mode 100644
index 0000000..ddef9ee
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -0,0 +1,17 @@
+
+
+
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index b636f8d..fb59a6b 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -16,26 +16,33 @@
app:layout_constraintEnd_toEndOf="parent"
tools:text="@string/welcome_message_test"/>
-
+ android:columnCount="2">
+ android:layout_columnWeight="1"/>
+ android:layout_columnWeight="1"/>
-
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/settings_activity.xml b/app/src/main/res/layout/settings_activity.xml
new file mode 100644
index 0000000..de6591a
--- /dev/null
+++ b/app/src/main/res/layout/settings_activity.xml
@@ -0,0 +1,9 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
new file mode 100644
index 0000000..e5f8fdc
--- /dev/null
+++ b/app/src/main/res/values/arrays.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index e009b0b..ee87e48 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -32,5 +32,25 @@
This update was received at: %sShare your locationIn order to share your position also while in the background, please grant the always permission
+ SettingsActivity
+
+
+ Settings
+
+
+ Share Location
+ Location Update frequency
+ The minimum amount of seconds to wait between two location updates\nNote: The lower the value the higher the battery consumption
+ Automatic accuracy detection
+ Accuracy will be auto selected based on the current charging state
+ Select high accuracy vs. balanced power consumption below
+ Force high accuracy
+ High accuracy for location data, may drain battery faster
+ Lower accuracy for location data, but better battery consumption
+
+
+ location_update_freq
+ auto_accuracy
+ manual_accuracy
\ No newline at end of file
diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml
new file mode 100644
index 0000000..fed5b95
--- /dev/null
+++ b/app/src/main/res/xml/root_preferences.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file