diff --git a/app/build.gradle b/app/build.gradle
index a639ca8..299b6f7 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -37,6 +37,7 @@ dependencies {
implementation 'androidx.constraintlayout:constraintlayout:2.2.1'
implementation 'io.reactivex.rxjava3:rxjava:3.1.5'
implementation 'androidx.car.app:app:1.4.0'
+ implementation 'androidx.car.app:app-projected:1.4.0'
implementation 'androidx.concurrent:concurrent-futures:1.2.0'
// Color Picker Preference
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 240ed16..ca5d4c0 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -14,6 +14,8 @@
+
+
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 0850366..7dcd978 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/HelperGridActivity.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/HelperGridActivity.java
@@ -2,6 +2,7 @@ package com.aldo.apps.familyhelpers;
import static android.Manifest.permission.CAMERA;
import static android.Manifest.permission.POST_NOTIFICATIONS;
+import static com.aldo.apps.familyhelpers.utils.GlobalConstants.CAR_SPEED_PERMISSION;
import static com.aldo.apps.familyhelpers.utils.GlobalConstants.SIGN_IN_PROVIDERS;
import android.content.Intent;
@@ -168,6 +169,9 @@ public class HelperGridActivity extends AppCompatActivity {
Log.d(TAG, "launchHelper: Notifications not allowed, return...");
return;
}
+ if (!requestVehicleSpeedPermission()) {
+ Log.d(TAG, "launchHelper: Permission not granted cannot read vehicle speed.");
+ }
if (mLocationHelper.requestLocationPermissions(HelperGridActivity.this)
&& mLocationHelper.requestBackgroundLocationPermission(HelperGridActivity.this)) {
Log.d(TAG, "launchHelper: Permission already granted");
@@ -232,6 +236,26 @@ public class HelperGridActivity extends AppCompatActivity {
}
}
+ /**
+ * Helper method to request the VehicleSpeed permission before launching the ShareLocationActivity.
+ *
+ * @return true if granted, flase otherwise.
+ */
+ private boolean requestVehicleSpeedPermission() {
+ if (ContextCompat.checkSelfPermission(this, CAR_SPEED_PERMISSION) ==
+ PackageManager.PERMISSION_GRANTED) {
+ // Permission already granted
+ return true;
+ } else {
+ if (shouldShowRequestPermissionRationale(CAR_SPEED_PERMISSION)) {
+ Toast.makeText(HelperGridActivity.this, "Consider granting this for the vehicle speed in Android Auto to be more accurate",
+ Toast.LENGTH_LONG).show();
+ }
+ mRequestPermissionLauncher.launch(CAR_SPEED_PERMISSION);
+ return false;
+ }
+ }
+
/**
* Helper method to request the CameraPermission as it is required to access the
* flashlight settings.
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationScreen.java b/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationScreen.java
index ed47340..5f5e4c7 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationScreen.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationScreen.java
@@ -16,6 +16,10 @@ import androidx.car.app.model.GridTemplate;
import androidx.car.app.model.ItemList;
import androidx.car.app.model.Template;
import androidx.core.graphics.drawable.IconCompat;
+import androidx.lifecycle.Lifecycle;
+import androidx.lifecycle.LifecycleEventObserver;
+import androidx.lifecycle.LifecycleObserver;
+import androidx.lifecycle.LifecycleOwner;
import com.aldo.apps.familyhelpers.R;
import com.aldo.apps.familyhelpers.workers.LocationHelper;
@@ -36,6 +40,26 @@ public class ShareLocationScreen extends Screen {
*/
private LocationHelper mLocationHelper;
+ /**
+ * {@link VehicleInformationHelper} to read vehicle information in AA use case.
+ */
+ private VehicleInformationHelper mVehicleInformationHelper;
+
+ /**
+ * {@link LifecycleObserver} to stop listening to Vehicle Speed updates when AA ends.
+ */
+ private LifecycleObserver mLifecycleObserver = new LifecycleEventObserver() {
+ @Override
+ public void onStateChanged(@NonNull final LifecycleOwner lifecycleOwner,
+ @NonNull final Lifecycle.Event event) {
+
+ if (event == Lifecycle.Event.ON_STOP) {
+ Log.d(TAG, "onStateChanged: Activity stopped, unsubscribe");
+ mVehicleInformationHelper.unsubscribeFromSpeedValue();
+ }
+ }
+ };
+
/**
* C'Tor.
*
@@ -44,6 +68,8 @@ public class ShareLocationScreen extends Screen {
protected ShareLocationScreen(@NonNull CarContext carContext) {
super(carContext);
Log.d(TAG, "ShareLocationScreen() called with: carContext = [" + carContext + "]");
+ mVehicleInformationHelper = new VehicleInformationHelper(carContext);
+ getLifecycle().addObserver(mLifecycleObserver);
}
@ExperimentalCarApi
@@ -52,6 +78,7 @@ public class ShareLocationScreen extends Screen {
public Template onGetTemplate() {
Log.d(TAG, "onGetTemplate() called");
mLocationHelper = LocationHelper.getInstance(getCarContext());
+ mVehicleInformationHelper.subscribeToSpeedValues(getCarContext());
final GridItem startItem = new GridItem.Builder()
.setTitle(getString(R.string.android_auto_share_location_start))
@@ -67,10 +94,18 @@ public class ShareLocationScreen extends Screen {
.setOnClickListener(this::stopLocationSharingService)
.build();
+ final GridItem startNavigation = new GridItem.Builder()
+ .setTitle(getString(R.string.android_auto_share_location_navigation_title))
+ .setText(getString(R.string.android_auto_share_location_naviagation_summary))
+ .setImage(getIconForResource(R.drawable.ic_navigation), GridItem.IMAGE_TYPE_ICON)
+ .setOnClickListener(this::startNavigationScreen)
+ .build();
+
final ItemList itemList = new ItemList.Builder()
.setNoItemsMessage(getString(R.string.android_auto_share_location_no_items_yet))
.addItem(startItem)
.addItem(stopItem)
+ .addItem(startNavigation)
.build();
return new GridTemplate.Builder()
@@ -125,6 +160,13 @@ public class ShareLocationScreen extends Screen {
getCarContext().stopService(serviceIntent);
}
+ /**
+ * Helper method to start The Navigation screen.
+ */
+ private void startNavigationScreen() {
+ CarToast.makeText(getCarContext(), "Not yet implemented", CarToast.LENGTH_LONG).show();
+ }
+
/**
* Helper method to extract a string resource.
*
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/auto/VehicleInformationHelper.java b/app/src/main/java/com/aldo/apps/familyhelpers/auto/VehicleInformationHelper.java
new file mode 100644
index 0000000..8fded6f
--- /dev/null
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/auto/VehicleInformationHelper.java
@@ -0,0 +1,82 @@
+package com.aldo.apps.familyhelpers.auto;
+
+import static com.aldo.apps.familyhelpers.utils.GlobalConstants.CAR_SPEED_PERMISSION;
+
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.car.app.CarContext;
+import androidx.car.app.hardware.CarHardwareManager;
+import androidx.car.app.hardware.info.CarInfo;
+import androidx.car.app.hardware.info.Speed;
+
+import com.aldo.apps.familyhelpers.workers.LocationHelper;
+
+/**
+ * Helper class to retrieve a set of {@link CarInfo} to be used in other functionalities.
+ */
+public class VehicleInformationHelper {
+
+ /**
+ * Tag for debugging purposes.
+ */
+ private static final String TAG = "VehicleInformationHelper";
+
+ /**
+ * The {@link CarInfo} as retrieved from the CarService.
+ */
+ private CarInfo mCarInfo;
+
+ /**
+ * The {@link LocationHelper} to apply the speed in.
+ */
+ private LocationHelper mLocationHelper;
+
+ /**
+ * C'Tor.
+ *
+ * @param carContext The {@link CarContext} from which this was instantiated.
+ */
+ public VehicleInformationHelper(final CarContext carContext) {
+ if (carContext.checkCallingOrSelfPermission(CAR_SPEED_PERMISSION) != PackageManager.PERMISSION_GRANTED) {
+ Log.w(TAG, "VehicleInformationHelper: Nothing to do, permission not granted");
+ return;
+ }
+ mLocationHelper = LocationHelper.getInstance(carContext);
+ }
+
+ /**
+ * Subscribe to the Vehicle Speed and handle it.
+ *
+ * @param carContext The {@link CarContext} from which this was called.
+ */
+ public void subscribeToSpeedValues(final CarContext carContext) {
+ if (carContext.checkCallingOrSelfPermission(CAR_SPEED_PERMISSION) == PackageManager.PERMISSION_GRANTED) {
+ mCarInfo = carContext.getCarService(CarHardwareManager.class).getCarInfo();
+ if (mCarInfo == null) {
+ Log.e(TAG, "subscribeToSpeedValues: No car info available");
+ return;
+ }
+ mCarInfo.addSpeedListener(carContext.getMainExecutor(), this::handleReceivedSpeed);
+ } else {
+ Log.w(TAG, "subscribeToSpeedValues: No Speed permission granted, cannot subscribe");
+ }
+ }
+
+ /**
+ * When AA ends, unsubscribe from the speed value again.
+ */
+ public void unsubscribeFromSpeedValue() {
+ mCarInfo.removeSpeedListener(this::handleReceivedSpeed);
+ }
+
+ /**
+ * Handle the received speed value by publishing it to the {@link LocationHelper}.
+ *
+ * @param data The {@link Speed} data.
+ */
+ private void handleReceivedSpeed(@NonNull final Speed data) {
+ mLocationHelper.updateVehicleSpeed(data.getDisplaySpeedMetersPerSecond());
+ }
+}
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/model/LocationObject.java b/app/src/main/java/com/aldo/apps/familyhelpers/model/LocationObject.java
index ff70331..e415eb0 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/model/LocationObject.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/model/LocationObject.java
@@ -126,6 +126,17 @@ public class LocationObject {
return speed;
}
+ /**
+ * Setter for the speed to be used if the speed is received from the vehicle.
+ *
+ * @param vehicleSpeed The received vehicle speed.
+ */
+ public void setSpeed(final Float vehicleSpeed) {
+ if (vehicleSpeed != null) {
+ speed = vehicleSpeed;
+ }
+ }
+
/**
* Returns the last received timestamp.
*
diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/utils/GlobalConstants.java b/app/src/main/java/com/aldo/apps/familyhelpers/utils/GlobalConstants.java
index 9ae1918..820d7f1 100644
--- a/app/src/main/java/com/aldo/apps/familyhelpers/utils/GlobalConstants.java
+++ b/app/src/main/java/com/aldo/apps/familyhelpers/utils/GlobalConstants.java
@@ -77,6 +77,12 @@ public final class GlobalConstants {
new AuthUI.IdpConfig.GoogleBuilder().build()
);
+ /**
+ * Name of the permission for the VehicleSpeed.
+ */
+ public static final String CAR_SPEED_PERMISSION = "com.google.android.gms.permission.CAR_SPEED";
+
+
/**
* Private C'tor to prevent instantiation.
*/
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 3e4e3a0..5627825 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
@@ -19,6 +19,7 @@ import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
+import androidx.car.app.hardware.common.CarValue;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.content.ContextCompat;
@@ -96,7 +97,6 @@ public final class LocationHelper {
/**
* The {@link BehaviorSubject} for the {@link LocationObject} for clients to subscribe to.
- * TODO: Check if needed.
*/
private final BehaviorSubject mLocationSubject = BehaviorSubject.create();
/**
@@ -111,6 +111,11 @@ public final class LocationHelper {
* The {@link BehaviorSubject} holding the state of current subscription.
*/
private final BehaviorSubject mSharingStateSubject = BehaviorSubject.createDefault(false);
+
+ /**
+ * The {@link CarValue} of the vehicles speed in meters per second if available.
+ */
+ private CarValue mVehicleSpeed;
/**
* Boolean flag to check whether a subscription for location updates is already running or not.
*/
@@ -176,6 +181,11 @@ public final class LocationHelper {
return true;
}
+ public void updateVehicleSpeed(final CarValue vehicleSpeed) {
+ Log.d(TAG, "updateVehicleSpeed() called with: vehicleSpeed = [" + vehicleSpeed + "]");
+ mVehicleSpeed = vehicleSpeed;
+ }
+
/**
* Request the permission for {@link android.Manifest.permission#ACCESS_BACKGROUND_LOCATION} if not
* yet granted before.
@@ -296,6 +306,10 @@ public final class LocationHelper {
*/
private void handleReceivedLocation(final Location location) {
final LocationObject locationObject = LocationObject.fromLocation(location);
+ if (mVehicleSpeed != null && mVehicleSpeed.getStatus() == CarValue.STATUS_SUCCESS) {
+ Log.d(TAG, "handleReceivedLocation: VehicleSpeed available");
+ locationObject.setSpeed(mVehicleSpeed.getValue());
+ }
Log.d(TAG, "onLocationChanged: Received update with " + locationObject);
mLocationSubject.onNext(locationObject);
mDbHelper.insertOrUpdateLocation(locationObject);
diff --git a/app/src/main/res/drawable/ic_navigation.xml b/app/src/main/res/drawable/ic_navigation.xml
new file mode 100644
index 0000000..b76cef4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_navigation.xml
@@ -0,0 +1,7 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_start_sharing.xml b/app/src/main/res/drawable/ic_start_sharing.xml
index b1e9e5d..04269e2 100644
--- a/app/src/main/res/drawable/ic_start_sharing.xml
+++ b/app/src/main/res/drawable/ic_start_sharing.xml
@@ -1,16 +1,4 @@
-
-
-
-
-
+
diff --git a/app/src/main/res/drawable/ic_stop_sharing.xml b/app/src/main/res/drawable/ic_stop_sharing.xml
index fc1c269..ff6f9a6 100644
--- a/app/src/main/res/drawable/ic_stop_sharing.xml
+++ b/app/src/main/res/drawable/ic_stop_sharing.xml
@@ -1,8 +1,5 @@
-
-
+
+
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index c386bb8..36e69e6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -63,13 +63,15 @@
Ja, fang an zu teilen
Ja, hör auf zu teilen
Start
- Standrot teilen
+ Standort teilen
Stop
Nicht mehr teilen
Wähle eine eigene Farbe für deine Bildschirm-Taschenlampe
Eigene Farbe
- Noch keine Einträge, seltsam...
+ Noch keine Einträge, seltsam…
Du teilst deinen Standort schon
Du teilst deinen Standort noch nicht
+ Navigation
+ Teilen und navigieren
\ No newline at end of file
diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml
index 73a6dcb..156a860 100644
--- a/app/src/main/res/values-en/strings.xml
+++ b/app/src/main/res/values-en/strings.xml
@@ -71,6 +71,8 @@
No Items yet, something went wrong
You already share your location
You are not yet sharing your location
+ Navigate
+ Share and navigate
\ 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 253aa5c..0366348 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -100,5 +100,7 @@
No Items yet, something went wrong
You already share your location
You are not yet sharing your location
+ Navigate
+ Share and navigate
\ No newline at end of file