From 93cae8d160815c243ad982d93caf927ea93f4771 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20D=C3=B6rflinger?= Date: Wed, 9 Apr 2025 12:57:06 +0200 Subject: [PATCH] [AA] Working GridView for Android Auto With this commit we have the first functional version of the AndroidAuto integration. --- app/src/main/AndroidManifest.xml | 13 +- .../familyhelpers/ShareLocationActivity.java | 4 + .../auto/ShareLocationCarAppService.java | 18 ++- .../auto/ShareLocationScreen.java | 122 ++++++++---------- .../auto/ShareLocationSession.java | 7 + app/src/main/res/values-de/strings.xml | 8 +- app/src/main/res/values-en/strings.xml | 11 +- app/src/main/res/values/strings.xml | 7 +- app/src/main/res/xml/automotive_app_desc.xml | 2 +- 9 files changed, 111 insertions(+), 81 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index efae3d4..240ed16 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -15,6 +15,12 @@ + + + + + - @@ -71,9 +79,8 @@ - - + diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/ShareLocationActivity.java b/app/src/main/java/com/aldo/apps/familyhelpers/ShareLocationActivity.java index 5503a33..3cba800 100644 --- a/app/src/main/java/com/aldo/apps/familyhelpers/ShareLocationActivity.java +++ b/app/src/main/java/com/aldo/apps/familyhelpers/ShareLocationActivity.java @@ -476,6 +476,10 @@ public class ShareLocationActivity extends AppCompatActivity implements OnMapRea @Override public void onMapReady(@NonNull final GoogleMap googleMap) { + if (googleMap == null) { + Log.w(TAG, "onMapReady: Map null, cannot continue"); + return; + } mGmap = googleMap; if (mIsNightMode) { mGmap.setMapStyle(MapStyleOptions.loadRawResourceStyle(this, R.raw.map_style_night)); diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationCarAppService.java b/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationCarAppService.java index 3d6a3bc..ef0690e 100644 --- a/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationCarAppService.java +++ b/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationCarAppService.java @@ -7,8 +7,16 @@ import androidx.car.app.CarAppService; import androidx.car.app.Session; import androidx.car.app.validation.HostValidator; +/** + * The {@link CarAppService} extension to be called upon connection. + */ public class ShareLocationCarAppService extends CarAppService { + + /** + * Tag for debugging purposes. + */ private static final String TAG = "ShareLocationCarAppServ"; + @NonNull @Override public HostValidator createHostValidator() { @@ -19,7 +27,13 @@ public class ShareLocationCarAppService extends CarAppService { @NonNull @Override public Session onCreateSession() { - Log.d(TAG, "onCreateSession: "); - return new ShareLocationSession(); + try { + Log.d(TAG, "onCreateSession: "); + return new ShareLocationSession(); + } catch (Exception e) { + Log.e(TAG, "onCreateSession: ", e); + return new ShareLocationSession(); + } } + } 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 9a39959..ed47340 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 @@ -1,10 +1,5 @@ package com.aldo.apps.familyhelpers.auto; -import static androidx.core.app.NotificationManagerCompat.IMPORTANCE_DEFAULT; - -import static com.aldo.apps.familyhelpers.utils.GlobalConstants.SHARE_LOCATION_CANCEL_ACTION; - -import android.app.PendingIntent; import android.content.Intent; import android.util.Log; @@ -17,136 +12,127 @@ import androidx.car.app.Screen; import androidx.car.app.annotations.ExperimentalCarApi; import androidx.car.app.model.CarIcon; import androidx.car.app.model.GridItem; +import androidx.car.app.model.GridTemplate; import androidx.car.app.model.ItemList; -import androidx.car.app.model.ListTemplate; import androidx.car.app.model.Template; -import androidx.car.app.notification.CarAppExtender; -import androidx.car.app.notification.CarNotificationManager; -import androidx.core.app.NotificationChannelCompat; -import androidx.core.app.NotificationCompat; import androidx.core.graphics.drawable.IconCompat; import com.aldo.apps.familyhelpers.R; import com.aldo.apps.familyhelpers.workers.LocationHelper; import com.aldo.apps.familyhelpers.workers.ShareLocationBackgroundWorker; +/** + * {@link Screen} implementation to be shown in the Android Auto environment. + */ public class ShareLocationScreen extends Screen { - private static final String AA_NOTIFICATION_CHANNEL = "ShareLocation_AA"; - - private static final int AA_NOTIFICATION_ID = 1; - + /** + * Tag for debugging purpose. + */ private static final String TAG = "ShareLocationScreen"; + /** + * {@link LocationHelper} instance to observe the current sharing state. + */ private LocationHelper mLocationHelper; - // Constructor for ShareLocationScreen + /** + * C'Tor. + * + * @param carContext The {@link CarContext} this was instantiated in. + */ protected ShareLocationScreen(@NonNull CarContext carContext) { super(carContext); Log.d(TAG, "ShareLocationScreen() called with: carContext = [" + carContext + "]"); - mLocationHelper = LocationHelper.getInstance(getCarContext()); } - @ExperimentalCarApi @NonNull @Override public Template onGetTemplate() { Log.d(TAG, "onGetTemplate() called"); + mLocationHelper = LocationHelper.getInstance(getCarContext()); final GridItem startItem = new GridItem.Builder() .setTitle(getString(R.string.android_auto_share_location_start)) .setText(getString(R.string.android_auto_share_location_start_desc)) - .setImage(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_start_sharing)) - .build(), GridItem.IMAGE_TYPE_LARGE) + .setImage(getIconForResource(R.drawable.ic_start_sharing), GridItem.IMAGE_TYPE_ICON) .setOnClickListener(this::startLocationShareService) .build(); final GridItem stopItem = new GridItem.Builder() .setTitle(getString(R.string.android_auto_share_location_stop)) .setText(getString(R.string.android_auto_share_location_stop_desc)) - .setImage(new CarIcon.Builder(IconCompat.createWithResource(getCarContext(), R.drawable.ic_stop_sharing)) - .build(), GridItem.IMAGE_TYPE_LARGE) + .setImage(getIconForResource(R.drawable.ic_stop_sharing), GridItem.IMAGE_TYPE_ICON) .setOnClickListener(this::stopLocationSharingService) .build(); final ItemList itemList = new ItemList.Builder() - .setNoItemsMessage("No Items yet, something went wrong I guess") + .setNoItemsMessage(getString(R.string.android_auto_share_location_no_items_yet)) .addItem(startItem) .addItem(stopItem) .build(); - mLocationHelper.getSharingStateSubject().subscribe(this::createNotification, this::handleError); - - return new ListTemplate.Builder() + return new GridTemplate.Builder() .setLoading(false) - .setTitle("Share Location") + .setTitle(getString(R.string.android_auto_share_location_start_desc)) .setSingleList(itemList) .build(); } - private void createNotification(final Boolean isSharing) { - Log.d(TAG, "createNotification() called with: isSharing = [" + isSharing + "]"); - CarNotificationManager notificationManager = CarNotificationManager.from(getCarContext()); - notificationManager.createNotificationChannel( - new NotificationChannelCompat.Builder(AA_NOTIFICATION_CHANNEL, IMPORTANCE_DEFAULT) - .build()); - final PendingIntent serviceIntent; - @DrawableRes final int iconId; - final String title; - if (isSharing) { - // Create an intent to start the ShareLocationBackgroundWorker service - final Intent stopService = new Intent(getCarContext(), ShareLocationBackgroundWorker.class); - stopService.setAction(SHARE_LOCATION_CANCEL_ACTION); - serviceIntent = PendingIntent.getService(getCarContext(), 0, stopService, PendingIntent.FLAG_IMMUTABLE); - title = getString(R.string.android_auto_share_location_stop); - iconId = R.drawable.ic_stop_sharing; - } else { - // Create an intent to start the ShareLocationBackgroundWorker service - final Intent startServiceIntent = new Intent(getCarContext(), ShareLocationBackgroundWorker.class); - serviceIntent = PendingIntent.getService(getCarContext(), 0, startServiceIntent, PendingIntent.FLAG_IMMUTABLE); - title = getString(R.string.android_auto_share_location_start); - iconId = R.drawable.ic_start_sharing; - } - - final NotificationCompat.Builder carNotification = new NotificationCompat.Builder(getCarContext(), AA_NOTIFICATION_CHANNEL) - .setContentTitle("Share Location") - .addAction(iconId, title, serviceIntent) - .extend(new CarAppExtender.Builder() - .build()); - - notificationManager.notify(AA_NOTIFICATION_ID, carNotification); - + /** + * Helper method to get an Icon from Resources and tint it into the proper color. + * + * @param iconId The DrawableId of the icon. + * + * @return The CarIcon. + */ + private CarIcon getIconForResource(@DrawableRes final int iconId) { + final IconCompat iconCompat = IconCompat.createWithResource(getCarContext(), iconId); + iconCompat.setTint(getCarContext().getColor(R.color.md_theme_primary)); + return new CarIcon.Builder(iconCompat).build(); } + + /** + * Helper method to start the location sharing by starting the {@link ShareLocationBackgroundWorker}. + */ private void startLocationShareService() { Log.d(TAG, "startLocationShareService: "); if (mLocationHelper != null && mLocationHelper.isCurrentlySharing()) { - CarToast.makeText(getCarContext(), "You already are sharing", CarToast.LENGTH_SHORT).show(); + CarToast.makeText(getCarContext(), R.string.android_auto_share_location_already_sharing, + CarToast.LENGTH_SHORT).show(); return; } // Create an intent to start the ShareLocationBackgroundWorker service - final Intent startServiceIntent = new Intent(getCarContext(), ShareLocationBackgroundWorker.class); + final Intent serviceIntent = new Intent(getCarContext(), ShareLocationBackgroundWorker.class); // Start the service using the car context - getCarContext().startForegroundService(startServiceIntent); + getCarContext().startForegroundService(serviceIntent); } + /** + * Helper method to stop the location sharing by stopping the {@link ShareLocationBackgroundWorker}. + */ private void stopLocationSharingService() { Log.d(TAG, "stopLocationSharingService: "); if (mLocationHelper != null && !mLocationHelper.isCurrentlySharing()) { - CarToast.makeText(getCarContext(), "You are not sharing", CarToast.LENGTH_SHORT).show(); + CarToast.makeText(getCarContext(), R.string.android_auto_share_location_not_yet_sharing, + CarToast.LENGTH_SHORT).show(); return; } // Create an intent to start the ShareLocationBackgroundWorker service - final Intent startServiceIntent = new Intent(getCarContext(), ShareLocationBackgroundWorker.class); + final Intent serviceIntent = new Intent(getCarContext(), ShareLocationBackgroundWorker.class); // Start the service using the car context - getCarContext().stopService(startServiceIntent); + getCarContext().stopService(serviceIntent); } + /** + * Helper method to extract a string resource. + * + * @param stringId The String resource ID. + * + * @return The unwrapped string. + */ private String getString(@StringRes final int stringId) { return getCarContext().getString(stringId); } - - private void handleError(final Throwable error) { - Log.e(TAG, "handleErrot: ", error); - } } diff --git a/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationSession.java b/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationSession.java index 952eafc..f1d4af6 100644 --- a/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationSession.java +++ b/app/src/main/java/com/aldo/apps/familyhelpers/auto/ShareLocationSession.java @@ -7,7 +7,14 @@ import androidx.annotation.NonNull; import androidx.car.app.Screen; import androidx.car.app.Session; +/** + * The {@link Session} to be started by the CarAppService to show the {@link ShareLocationScreen}. + */ public class ShareLocationSession extends Session { + + /** + * Tag for debugging purposes. + */ private static final String TAG = "ShareLocationSession"; @NonNull diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml index c5f4a5e..c386bb8 100644 --- a/app/src/main/res/values-de/strings.xml +++ b/app/src/main/res/values-de/strings.xml @@ -63,9 +63,13 @@ Ja, fang an zu teilen Ja, hör auf zu teilen Start - Anfangen den Standort zu teilen + Standrot teilen Stop - Aufhören den Standort zu teilen + Nicht mehr teilen Wähle eine eigene Farbe für deine Bildschirm-Taschenlampe Eigene Farbe + Noch keine Einträge, seltsam... + Du teilst deinen Standort schon + Du teilst deinen Standort noch nicht + \ 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 de2b369..73a6dcb 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -62,10 +62,15 @@ Android Auto start has been detected, do you wanna share your location? Yes, start to share Yes, stop sharing - Start - Start to share location + Share Location Stop - Stop to share the location + Stop Sharing + Start Choose an own color to be displayed in the on-screen flashlight. Custom Color + No Items yet, something went wrong + You already share your location + You are not yet sharing your location + + \ 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 15bf45c..253aa5c 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -94,8 +94,11 @@ Yes, start to share Yes, stop sharing Start - Start to share location + Share Location Stop - Stop to share the location + Stop Sharing + No Items yet, something went wrong + You already share your location + You are not yet sharing your location \ No newline at end of file diff --git a/app/src/main/res/xml/automotive_app_desc.xml b/app/src/main/res/xml/automotive_app_desc.xml index 66dd335..bb31111 100644 --- a/app/src/main/res/xml/automotive_app_desc.xml +++ b/app/src/main/res/xml/automotive_app_desc.xml @@ -1,4 +1,4 @@ - +