diff --git a/README.md b/README.md index 5eac36d91..289352aec 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ For an overview of the existing features, please check the _Developer Guide_ for > For now, HERE SDK (Navigate) is only available upon request. Please contact your HERE representative to receive access including a set of evaluation credentials. -## List of available example apps (Version 4.27.2.0) +## List of available example apps (Version 4.27.3.0) - [List of example apps for the HERE SDK for Android](https://www.here.com/docs/bundle/sdk-for-android-developer-guide/page/topics/examples.html). - [List of example apps for the HERE SDK for iOS](https://www.here.com/docs/bundle/sdk-for-ios-developer-guide/page/topics/examples.html). diff --git a/examples/latest/README.md b/examples/latest/README.md index 7accf18fa..bec4d8625 100644 --- a/examples/latest/README.md +++ b/examples/latest/README.md @@ -1,4 +1,4 @@ -This folder contains the HERE SDK examples apps for version: 4.27.2.0 +This folder contains the HERE SDK examples apps for version: 4.27.3.0 - HERE SDK for Android ([Explore](explore/android/), [Navigate](navigate/android/)) - HERE SDK for iOS ([Explore](explore/ios/), [Navigate](navigate/ios/)) diff --git a/examples/latest/explore/android/Java/EVRouting/app/build.gradle b/examples/latest/explore/android/Java/EVRouting/app/build.gradle index cc6af99b8..2a482798d 100644 --- a/examples/latest/explore/android/Java/EVRouting/app/build.gradle +++ b/examples/latest/explore/android/Java/EVRouting/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/Gestures/app/build.gradle b/examples/latest/explore/android/Java/Gestures/app/build.gradle index b4c52d756..88ea9976b 100644 --- a/examples/latest/explore/android/Java/Gestures/app/build.gradle +++ b/examples/latest/explore/android/Java/Gestures/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/Gestures/build.gradle b/examples/latest/explore/android/Java/Gestures/build.gradle index b92a7d52e..dde6d4c61 100644 --- a/examples/latest/explore/android/Java/Gestures/build.gradle +++ b/examples/latest/explore/android/Java/Gestures/build.gradle @@ -26,7 +26,7 @@ allprojects { if (rootProject.ext.HERESDKBuildConfig == "BUNDLE_FROM_ARTIFACTORY") { maven { name = 'HERE_SDK_Artifactory_Repository' - url = "https://repo.platform.here.com/artifactory/here-sdk-android" + url = project.findProperty('HERESDKArtifactoryURL') ?: "https://repo.platform.here.com/artifactory/here-sdk-android" credentials { // Use the username and token created on https://platform.here.com/access/access-tokens. username = project.findProperty('HERESDKArtifactoryUsername') ?: "YOUR_USER_NAME" diff --git a/examples/latest/explore/android/Java/HelloMap/app/build.gradle b/examples/latest/explore/android/Java/HelloMap/app/build.gradle index 058ba8dfd..b338bebd5 100644 --- a/examples/latest/explore/android/Java/HelloMap/app/build.gradle +++ b/examples/latest/explore/android/Java/HelloMap/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/HelloMapAndroidAuto/app/build.gradle b/examples/latest/explore/android/Java/HelloMapAndroidAuto/app/build.gradle index ec7e6d327..ba9ac8bcd 100644 --- a/examples/latest/explore/android/Java/HelloMapAndroidAuto/app/build.gradle +++ b/examples/latest/explore/android/Java/HelloMapAndroidAuto/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/HelloMapSurface/app/build.gradle b/examples/latest/explore/android/Java/HelloMapSurface/app/build.gradle index e8ea046ca..404c2f946 100644 --- a/examples/latest/explore/android/Java/HelloMapSurface/app/build.gradle +++ b/examples/latest/explore/android/Java/HelloMapSurface/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/MapItems/app/build.gradle b/examples/latest/explore/android/Java/MapItems/app/build.gradle index 3bad9dbc8..978c1e52f 100644 --- a/examples/latest/explore/android/Java/MapItems/app/build.gradle +++ b/examples/latest/explore/android/Java/MapItems/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/MultiDisplays/app/build.gradle b/examples/latest/explore/android/Java/MultiDisplays/app/build.gradle index 57c5b59c4..0260b42fa 100644 --- a/examples/latest/explore/android/Java/MultiDisplays/app/build.gradle +++ b/examples/latest/explore/android/Java/MultiDisplays/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/OffscreenMapSurface/app/build.gradle b/examples/latest/explore/android/Java/OffscreenMapSurface/app/build.gradle index e8ce20922..19cb49bfb 100644 --- a/examples/latest/explore/android/Java/OffscreenMapSurface/app/build.gradle +++ b/examples/latest/explore/android/Java/OffscreenMapSurface/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/PublicTransit/app/build.gradle b/examples/latest/explore/android/Java/PublicTransit/app/build.gradle index a80f88f67..225179530 100644 --- a/examples/latest/explore/android/Java/PublicTransit/app/build.gradle +++ b/examples/latest/explore/android/Java/PublicTransit/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/Routing/app/build.gradle b/examples/latest/explore/android/Java/Routing/app/build.gradle index 8864f81e4..ceb1f5941 100644 --- a/examples/latest/explore/android/Java/Routing/app/build.gradle +++ b/examples/latest/explore/android/Java/Routing/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/Search/app/build.gradle b/examples/latest/explore/android/Java/Search/app/build.gradle index 899b6b441..af985e39d 100644 --- a/examples/latest/explore/android/Java/Search/app/build.gradle +++ b/examples/latest/explore/android/Java/Search/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/Traffic/app/build.gradle b/examples/latest/explore/android/Java/Traffic/app/build.gradle index d17603dc0..b2cbee8e2 100644 --- a/examples/latest/explore/android/Java/Traffic/app/build.gradle +++ b/examples/latest/explore/android/Java/Traffic/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/Traffic/build.gradle b/examples/latest/explore/android/Java/Traffic/build.gradle index 441555412..9435ce012 100644 --- a/examples/latest/explore/android/Java/Traffic/build.gradle +++ b/examples/latest/explore/android/Java/Traffic/build.gradle @@ -26,7 +26,7 @@ allprojects { if (rootProject.ext.HERESDKBuildConfig == "COMPONENTS_FROM_ARTIFACTORY") { maven { name = 'HERE_SDK_Artifactory_Repository' - url = "https://repo.platform.here.com/artifactory/here-sdk-android" + url = project.findProperty('HERESDKArtifactoryURL') ?: "https://repo.platform.here.com/artifactory/here-sdk-android" credentials { // Use the username and token created on https://platform.here.com/access/access-tokens. username = project.findProperty('HERESDKArtifactoryUsername') ?: "YOUR_USER_NAME" diff --git a/examples/latest/explore/android/Java/UnitTesting/README.md b/examples/latest/explore/android/Java/UnitTesting/README.md index a3ee34e42..afa324629 100644 --- a/examples/latest/explore/android/Java/UnitTesting/README.md +++ b/examples/latest/explore/android/Java/UnitTesting/README.md @@ -2,14 +2,15 @@ The UnitTesting example app shows how the HERE SDK can be mocked in unit tests. ![Map view backing the example app that is covered by mocked unit tests](images/unit_testing.png) -This example uses **HERE SDK Units** to support functionality such as permission handling or buttons that are not essential to the code snippets shown in this app, as the focus is on demonstrating how to use the APIs provided by the HERE SDK. The HERE SDK Units are included as AARs in the app’s `libs` folder. For more details, see the "HERESDKUnits" app to customize or create your own unit libraries. Note that this app is intended exclusively for the HERE SDK (Navigate). You can find it in the `navigate` folder. However, it can be easily adapted for the HERE SDK (Explore) by removing any code that is not supported there. At present, most components are compatible and will compile without issues. - Build instructions: ------------------- -1) Copy the AAR and "heresdk-xxx.jar" mock JAR file of the HERE SDK for Android to your app's `app/libs` folder. +1) Copy the AAR file of the HERE SDK for Android to your app's `app/libs` folder. + +2) Copy the "heresdk-xxx.jar" mock JAR file of the HERE SDK for Android to your app's `app/libs` folder. + +Note: If your AAR/JAR versions are different than the version shown in the _Developer Guide_, you may need to adapt the source code of the example app. -Note: If your AAR/JAR version are different than the version shown in the _Developer Guide_, you may need to adapt the source code of the example app. +3) Open Android Studio and sync the project. -2) Open Android Studio and sync the project. -3) Open file TestBasicTypes.java and run unit tests from it. +4) Open file `TestBasicTypes.java` and run unit tests from it. diff --git a/examples/latest/explore/android/Java/UnitTesting/app/build.gradle b/examples/latest/explore/android/Java/UnitTesting/app/build.gradle index 1d1522091..3dbf920e1 100644 --- a/examples/latest/explore/android/Java/UnitTesting/app/build.gradle +++ b/examples/latest/explore/android/Java/UnitTesting/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/explore/android/Java/UnitTesting/app/libs/README.md b/examples/latest/explore/android/Java/UnitTesting/app/libs/README.md index 7b2708307..04724d7bd 100644 --- a/examples/latest/explore/android/Java/UnitTesting/app/libs/README.md +++ b/examples/latest/explore/android/Java/UnitTesting/app/libs/README.md @@ -1 +1,3 @@ -Put the latest AAR file of the HERE SDK for Android and the "heresdk-xxx.jar" mock JAR file to this folder. \ No newline at end of file +This app requires the unit testing mock library for the HERE SDK: Put the latest AAR file of the HERE SDK for Android and the "heresdk-xxx.jar" mock JAR file to this folder. + +On top, you need to add the HERE SDK AAR here. diff --git a/examples/latest/navigate/android/Java/CartoPOIPicking/app/build.gradle b/examples/latest/navigate/android/Java/CartoPOIPicking/app/build.gradle index 7538f9dcd..a5f64ba86 100644 --- a/examples/latest/navigate/android/Java/CartoPOIPicking/app/build.gradle +++ b/examples/latest/navigate/android/Java/CartoPOIPicking/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/EVRouting/app/build.gradle b/examples/latest/navigate/android/Java/EVRouting/app/build.gradle index cc6af99b8..2a482798d 100644 --- a/examples/latest/navigate/android/Java/EVRouting/app/build.gradle +++ b/examples/latest/navigate/android/Java/EVRouting/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/Gestures/app/build.gradle b/examples/latest/navigate/android/Java/Gestures/app/build.gradle index b4c52d756..88ea9976b 100644 --- a/examples/latest/navigate/android/Java/Gestures/app/build.gradle +++ b/examples/latest/navigate/android/Java/Gestures/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/Gestures/build.gradle b/examples/latest/navigate/android/Java/Gestures/build.gradle index b92a7d52e..dde6d4c61 100644 --- a/examples/latest/navigate/android/Java/Gestures/build.gradle +++ b/examples/latest/navigate/android/Java/Gestures/build.gradle @@ -26,7 +26,7 @@ allprojects { if (rootProject.ext.HERESDKBuildConfig == "BUNDLE_FROM_ARTIFACTORY") { maven { name = 'HERE_SDK_Artifactory_Repository' - url = "https://repo.platform.here.com/artifactory/here-sdk-android" + url = project.findProperty('HERESDKArtifactoryURL') ?: "https://repo.platform.here.com/artifactory/here-sdk-android" credentials { // Use the username and token created on https://platform.here.com/access/access-tokens. username = project.findProperty('HERESDKArtifactoryUsername') ?: "YOUR_USER_NAME" diff --git a/examples/latest/navigate/android/Java/HERESDKUnits/app/build.gradle b/examples/latest/navigate/android/Java/HERESDKUnits/app/build.gradle index 39e66dce1..218df0370 100644 --- a/examples/latest/navigate/android/Java/HERESDKUnits/app/build.gradle +++ b/examples/latest/navigate/android/Java/HERESDKUnits/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/HelloMap/app/build.gradle b/examples/latest/navigate/android/Java/HelloMap/app/build.gradle index 058ba8dfd..b338bebd5 100644 --- a/examples/latest/navigate/android/Java/HelloMap/app/build.gradle +++ b/examples/latest/navigate/android/Java/HelloMap/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/HelloMapAndroidAuto/app/build.gradle b/examples/latest/navigate/android/Java/HelloMapAndroidAuto/app/build.gradle index ec7e6d327..ba9ac8bcd 100644 --- a/examples/latest/navigate/android/Java/HelloMapAndroidAuto/app/build.gradle +++ b/examples/latest/navigate/android/Java/HelloMapAndroidAuto/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/HelloMapSurface/app/build.gradle b/examples/latest/navigate/android/Java/HelloMapSurface/app/build.gradle index e8ea046ca..404c2f946 100644 --- a/examples/latest/navigate/android/Java/HelloMapSurface/app/build.gradle +++ b/examples/latest/navigate/android/Java/HelloMapSurface/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/HikingDiary/app/build.gradle b/examples/latest/navigate/android/Java/HikingDiary/app/build.gradle index 3efd03581..907da1640 100644 --- a/examples/latest/navigate/android/Java/HikingDiary/app/build.gradle +++ b/examples/latest/navigate/android/Java/HikingDiary/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/build.gradle b/examples/latest/navigate/android/Java/IndoorMap/app/build.gradle index 187bdf908..90fb71d2d 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/build.gradle +++ b/examples/latest/navigate/android/Java/IndoorMap/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/DrawingSwitcher.java b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/DrawingSwitcher.java index 18b87e5ab..833a06d6e 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/DrawingSwitcher.java +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/DrawingSwitcher.java @@ -122,6 +122,8 @@ public void onItemClick(AdapterView parent, final View view, int position, lo VenueModel venueModel = venue.getVenueModel(); // Set the selected drawing when a user clicks on the item in the list. venue.setSelectedDrawing(venueModel.getDrawings().get(position)); + // Highlight the selected item. + updateSelectedDrawingPosition(); // Hide the list. setCollapsed(true); } @@ -158,6 +160,9 @@ private void setVenue(Venue venue) { final StringArrayAdapter adapter = new StringArrayAdapter(context, drawingNames); listView.setAdapter(adapter); + // Highlight the currently selected drawing. + updateSelectedDrawingPosition(); + // This Runnable gets called after the ListView has been measured // and laid out. Then we calculate the height of listView. listView.post(new Runnable() { @@ -242,6 +247,27 @@ private void onDrawingSelected(final VenueDrawing selectedDrawing) { return; } String selectedDrawingName = getDrawingName(selectedDrawing); + updateSelectedDrawingPosition(); + } + + // Updates the adapter's selected position to match the currently selected drawing. + private void updateSelectedDrawingPosition() { + if (venue == null) return; + ListAdapter adapter = listView.getAdapter(); + if (!(adapter instanceof StringArrayAdapter)) return; + + VenueDrawing selectedDrawing = venue.getSelectedDrawing(); + + VenueModel venueModel = venue.getVenueModel(); + List drawings = venueModel.getDrawings(); + int selectedIndex = -1; + for (int i = 0; i < drawings.size(); i++) { + if (drawings.get(i) == selectedDrawing) { + selectedIndex = i; + break; + } + } + ((StringArrayAdapter) adapter).setSelectedPosition(selectedIndex); } public void setVisible(boolean visible) { diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/IndoorRoutingUIController.java b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/IndoorRoutingUIController.java index 18293babd..00764990a 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/IndoorRoutingUIController.java +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/IndoorRoutingUIController.java @@ -483,9 +483,11 @@ public void showSelectedSpace(VenueGeometry geometry, GeoCoordinates position) { srcPosition = null; cancelBtn.setOnClickListener(v -> handleBackPressed()); - // Check if same level as selected destination geometry level then put a destination marker - // on top of geometry. - handleDstMarkerInMapOnLevelChange(); + // If same level as selected destination geometry, put a destination marker on top of geometry. + if (selectedDestinationGeometry.getLevel() == selectedVenue.getSelectedLevel()) { + dstMarker = new MapMarker(dstPosition, dstMarkerImage, new Anchor2D(0.5, 1)); + mapView.getMapScene().addMapMarker(dstMarker); + } } /** @@ -568,7 +570,7 @@ private void showRouteInMap( final IndoorRoutingError routingError, final List routeList, final List routeNotices) { - ((MainActivity)context).showProgressBarOnMap(false); + ((MainActivity) context).showProgressBarOnMap(false); controller.hideRoute(); // Route calculation happens in async mode, so if user has already closed the UI, no need to render it. @@ -576,35 +578,7 @@ private void showRouteInMap( return; } - if (routingError == null) { - if (routeList != null && !routeList.isEmpty()) { - Route route = routeList.get(0); - // check If length came as 0 it means same source and destination - Log.d(TAG, "Route Calculated with total Length: " + route.getLengthInMeters()); - if (route.getLengthInMeters() <= 0) { - String errorMsg = "Selected Source and Destination are same. Please select different" - + " source and destination points."; - showAlertOnRouteCalculationError(errorMsg); - return; - } - - controller.showRoute(route, routeStyle); - - // change current level on venue to source geometry level. - if (selectedVenue.getSelectedLevel() != selectedSourceGeometry.getLevel()) { - selectedVenue.setSelectedLevel(selectedSourceGeometry.getLevel()); - } - - // Move the camera to source position. - mapView.getCamera().lookAt(srcPosition); - // remove marker from map once route is rendered. - removeMarkerImageFromMap(); - isRouteRenderedOnMap = true; - } else { - isRouteRenderedOnMap = false; - showAlertOnRouteCalculationError("No route found."); - } - } else if (routingError != null) { + if (routingError != null) { isRouteRenderedOnMap = false; String errorMsg; switch (routingError) { @@ -649,7 +623,9 @@ private void showRouteInMap( } Log.d(TAG, "Route Calculation Error Msg: " + errorMsg); showAlertOnRouteCalculationError(errorMsg); + return; } + if (routeNotices != null && !routeNotices.isEmpty()) { isRouteRenderedOnMap = false; StringBuilder noticeMessages = new StringBuilder(); @@ -662,6 +638,31 @@ private void showRouteInMap( Log.d(TAG, "Route Notices: " + noticeMessages); showAlertOnRouteCalculationError(noticeMessages.toString()); } + + if (routeList != null && !routeList.isEmpty()) { + Route route = routeList.get(0); + // check If length came as 0 it means same source and destination + Log.d(TAG, "Route Calculated with total Length: " + route.getLengthInMeters()); + if (route.getLengthInMeters() <= 0) { + String errorMsg = "Selected Source and Destination are same. Please select different" + + " source and destination points."; + showAlertOnRouteCalculationError(errorMsg); + return; + } + + controller.showRoute(route, routeStyle); + + // change current level on venue to source geometry level. + if (selectedVenue.getSelectedLevel() != selectedSourceGeometry.getLevel()) { + selectedVenue.setSelectedLevel(selectedSourceGeometry.getLevel()); + } + + // Move the camera to source position. + mapView.getCamera().lookAt(srcPosition); + // remove marker from map once route is rendered. + removeMarkerImageFromMap(); + isRouteRenderedOnMap = true; + } } /** @@ -808,6 +809,10 @@ public boolean isRoutingSpaceSelectedActiveInBottomSheet() { * destination marker on Venue or remove it. */ public void handleDstMarkerInMapOnLevelChange() { + if (currentState == State.SPACE_SELECTION_DETAILS && selectedDestinationGeometry.getLevel() != selectedVenue.getSelectedLevel()) { + handleBackPressed(); + return; + } // If route is rendered on map, no need to put the marker on map. if(isRouteRenderedOnMap) { return; diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/LevelSwitcher.java b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/LevelSwitcher.java index 48aed18c7..598414d37 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/LevelSwitcher.java +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/LevelSwitcher.java @@ -44,23 +44,17 @@ class LevelItemView extends RelativeLayout { private TextView textView; - private View separator; public LevelItemView(Context context) { super(context); LayoutInflater.from(context).inflate(R.layout.level_item, this, true); textView = findViewById(R.id.levelName); - separator = findViewById(R.id.levelGroundSep); } public void setText(CharSequence text) { textView.setText(text); } - - public void setShowSeparator(boolean isVisible) { - separator.setVisibility(isVisible ? View.VISIBLE : View.INVISIBLE); - } } class LevelAdapter extends BaseAdapter { @@ -101,9 +95,6 @@ public View getView(int position, View convertView, ViewGroup parent) { VenueLevel level = levels.get(position); // Sets the level's short name as a text of the item. item.setText(level.getShortName()); - - // If the level is the main one, visually separates it from the levels below it. - item.setShowSeparator(level.isMainLevel() && position != levels.size() - 1); return item; } } @@ -134,15 +125,25 @@ public LevelSwitcher(Context context, AttributeSet attrs) { levelUp.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { + if (venueMap == null || venueMap.getSelectedVenue() == null) return; + int currLevelIndex = venueMap.getSelectedVenue().getSelectedLevelIndex(); + if (currLevelIndex >= maxLevelIndex) { + return; + } listView.smoothScrollByOffset(1); - venueMap.getSelectedVenue().setSelectedLevelIndex(venueMap.getSelectedVenue().getSelectedLevelIndex() + 1); + venueMap.getSelectedVenue().setSelectedLevelIndex(currLevelIndex + 1); } }); levelDown.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { + if (venueMap == null || venueMap.getSelectedVenue() == null) return; + int currLevelIndex = venueMap.getSelectedVenue().getSelectedLevelIndex(); + if (currLevelIndex - 1 < 0) { + return; + } listView.smoothScrollByOffset(-1); - venueMap.getSelectedVenue().setSelectedLevelIndex(venueMap.getSelectedVenue().getSelectedLevelIndex() - 1); + venueMap.getSelectedVenue().setSelectedLevelIndex(currLevelIndex - 1); } }); setVisibility(View.GONE); diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/MainActivity.java b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/MainActivity.java index 276d30558..649dc659a 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/MainActivity.java +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/MainActivity.java @@ -123,6 +123,12 @@ public class MainActivity extends AppCompatActivity { private int initialPeekHeight; + // Watermark positioning constants + private static final double WATERMARK_HORIZONTAL_POS = 0.0; + private static final double WATERMARK_INITIAL_VERTICAL_POS = 0.84; + private static final double WATERMARK_MIN_VERTICAL = 0.5; + private static final double WATERMARK_SHEET_GAP = 0.08; + private IndoorRoutingUIController routingController; private void initializeHERESDK() { @@ -342,6 +348,10 @@ public void onSlide(@NonNull View bottomSheet, float slideOffset) { } else { recyclerView.setAlpha(1f); } + + // Move watermark to stay just above the bottom sheet's top edge. + // Use the actual pixel position of the sheet relative to the MapView. + updateWatermarkPosition(bottomSheet); } }); @@ -418,7 +428,7 @@ private void loadMapScene() { // Load a scene from the HERE SDK to render the map with a map scheme. mapView.getMapScene().loadScene(MapScheme.NORMAL_DAY, mapError -> { if (mapError == null) { - setWatermark(1800); + setWatermark(); double distanceInMeters = 1000 * 10; MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters); mapView.getCamera().lookAt( @@ -577,7 +587,7 @@ public void onGetVenueCompleted(String venueIdentifier, @Nullable VenueModel ven } else { mapLoadDone = true; mapView.getCamera().zoomTo(18); - setWatermark(1600); + setWatermark(); geometryList = venueModel.getGeometries(); venueTapController.setGeometries(geometryList); recyclerView.setAdapter(new SpaceAdapter(getApplicationContext(), geometryList, MainActivity.this)); @@ -607,7 +617,7 @@ public void onGetVenueCompleted(String venueIdentifier, @Nullable VenueModel ven mapView.getCamera().lookAt( new GeoCoordinates(venueCenter.latitude, venueCenter.longitude), mapMeasureZoom); - setWatermark(1600); + setWatermark(); // Venue selection is done, enable back the button for the venue selection // to be able to select another venue. @@ -676,13 +686,51 @@ public void onVenueLoadError(VenueErrorCode venueLoadError) { alert.show(); } - void setWatermark(int off) + void setWatermark() { - Anchor2D anchor = new Anchor2D(0,0); - Point2D offset = new Point2D(0, off); + Anchor2D anchor = new Anchor2D(WATERMARK_HORIZONTAL_POS, WATERMARK_INITIAL_VERTICAL_POS); + Point2D offset = new Point2D(0, 0); mapView.setWatermarkLocation(anchor, offset); } + /** + * Repositions the watermark to stay just above the given overlay view's top edge. + * Uses the actual pixel position of the view relative to the MapView for accuracy. + */ + public void updateWatermarkPosition(View overlayView) { + int mapViewHeight = mapView.getHeight(); + if (mapViewHeight <= 0) return; + + // Get the overlay view's top Y in the window coordinate space. + int[] sheetLocation = new int[2]; + overlayView.getLocationInWindow(sheetLocation); + int sheetTopY = sheetLocation[1]; + + // Get the MapView's top Y in the window coordinate space. + int[] mapLocation = new int[2]; + mapView.getLocationInWindow(mapLocation); + int mapTopY = mapLocation[1]; + + // Sheet's top position relative to the MapView (in pixels from MapView top). + int sheetTopInMap = sheetTopY - mapTopY; + + // Convert to a normalized vertical position within the MapView [0, 1]. + // Subtract a gap in pixels (WATERMARK_SHEET_GAP * mapViewHeight) so the + // watermark sits above the sheet edge rather than right at it. + double gapPx = WATERMARK_SHEET_GAP * mapViewHeight; + double watermarkYPx = sheetTopInMap - gapPx; + double watermarkVertical = watermarkYPx / mapViewHeight; + + // Clamp: never above half screen (0.5), never below initial position (0.84). + watermarkVertical = Math.max(WATERMARK_MIN_VERTICAL, + Math.min(WATERMARK_INITIAL_VERTICAL_POS, watermarkVertical)); + + mapView.setWatermarkLocation( + new Anchor2D(WATERMARK_HORIZONTAL_POS, watermarkVertical), + new Point2D(0, 0) + ); + } + // Hide a keyboard. public void hideKeyboard() { try { @@ -783,7 +831,7 @@ private void loadBaseMap() { // Load a scene from the HERE SDK to render the map with a map scheme. mapView.getMapScene().loadScene(MapScheme.NORMAL_DAY, mapError -> { if (mapError == null) { - setWatermark(1800); + setWatermark(); double distanceInMeters = 1000 * 10; MapMeasure mapMeasureZoom = new MapMeasure(MapMeasure.Kind.DISTANCE_IN_METERS, distanceInMeters); mapView.getCamera().lookAt( diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/StringArrayAdapter.java b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/StringArrayAdapter.java index 22f40fe38..d80da3251 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/StringArrayAdapter.java +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/StringArrayAdapter.java @@ -35,6 +35,7 @@ class StringArrayAdapter extends ArrayAdapter { private final int listTextSize; private final int listTextColor; + private int selectedPosition = -1; StringArrayAdapter( @NonNull Context context, @@ -52,6 +53,15 @@ class StringArrayAdapter extends ArrayAdapter { this(context, names, 14, 0xFF444444); } + public void setSelectedPosition(int position) { + this.selectedPosition = position; + notifyDataSetChanged(); + } + + public int getSelectedPosition() { + return selectedPosition; + } + @Override public @NonNull View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) { @@ -60,8 +70,13 @@ class StringArrayAdapter extends ArrayAdapter { } TextView textView = convertView.findViewById(R.id.itemText); textView.setTextSize(listTextSize); - textView.setTextColor(listTextColor); textView.setText(getItem(position)); + + if (position == selectedPosition) { + textView.setTextColor(0xFF1976D2); + } else { + textView.setTextColor(listTextColor); + } return convertView; } } diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/VenueTapController.java b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/VenueTapController.java index ab0af8720..5e24a6ca5 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/VenueTapController.java +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/java/com/here/sdk/examples/venues/VenueTapController.java @@ -336,6 +336,9 @@ public void selectTopology(VenueTopology topology, GeoCoordinates position) { sheetBehavior.setPeekHeight(0); topologyLayout.setVisibility(View.VISIBLE); + // Move watermark above the topology panel. + topologyLayout.post(() -> ((MainActivity) context).updateWatermarkPosition(topologyLayout)); + // Set a selected style for the geometry. ArrayList topologies = new ArrayList<>(Collections.singletonList(topology)); selectedVenue.setCustomStyle(topologies, selectedTopologyStyle); @@ -365,6 +368,8 @@ public void deselectTopolgy() { topologyLayout.setVisibility(View.GONE); // restore initial peek height of bottom sheet sheetBehavior.setPeekHeight(((MainActivity)context).getInitialPeekHeight()); + // Reset watermark to initial position. + ((MainActivity) context).setWatermark(); // If there is a selected geometry, reset its style. if (selectedVenue != null && selectedTopology != null) { diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout-v26/level_item.xml b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout-v26/level_item.xml index e35689081..affa866fa 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout-v26/level_item.xml +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout-v26/level_item.xml @@ -9,14 +9,5 @@ android:textColor="@drawable/level_item_text_color" android:textSize="14sp" android:background="@drawable/level_item_background" /> - diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_item.xml b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_item.xml index be280cb18..863a9dd6c 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_item.xml +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_item.xml @@ -9,14 +9,5 @@ android:textColor="@drawable/level_item_text_color" android:textSize="12sp" android:background="@drawable/level_item_background" /> - diff --git a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_switcher.xml b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_switcher.xml index 280ee8b96..81239c26b 100644 --- a/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_switcher.xml +++ b/examples/latest/navigate/android/Java/IndoorMap/app/src/main/res/layout/level_switcher.xml @@ -9,11 +9,16 @@ android:background="@drawable/level_up" /> + + + + + 0): walk all path segments and use // sidePathIndexes to find paths that branch off at each segment. // sidePathIndexes contains indexes into allPaths[], pointing to branching paths. @@ -271,6 +284,9 @@ public void onElectronicHorizonDataLoaderStatusUpdated(@NonNull Map processedSidePathIndexes = new HashSet<>(); for (ElectronicHorizonPath path : allPaths) { for (ElectronicHorizonSegment segment : path.segments) { + if (segment.sidePathIndexes.isEmpty()) { + continue; + } for (Integer sidePathIndex : segment.sidePathIndexes) { if (sidePathIndex < 0 || sidePathIndex >= allPaths.size()) continue; if (!processedSidePathIndexes.add(sidePathIndex)) continue; @@ -285,8 +301,10 @@ public void onElectronicHorizonDataLoaderStatusUpdated(@NonNull Map allPaths) { + for (int pathIndex = 0; pathIndex < allPaths.size(); pathIndex++) { + ElectronicHorizonPath path = allPaths.get(pathIndex); + if (path.level != 1 || path.parentPathIndex == null || path.parentPathIndex != 0) { + continue; + } + + SideStreetInfo sideStreetInfo = findSideStreetInfo(path, pathIndex); + if (sideStreetInfo != null) { + Log.d(LOG_TAG, "SideStreetName near active route: " + sideStreetInfo.streetName + + " at lat/lon: " + sideStreetInfo.coordinateAtOffsetFromSegmentStart.latitude + + "/" + sideStreetInfo.coordinateAtOffsetFromSegmentStart.longitude + + ", pathIndex=" + sideStreetInfo.pathIndex + + ", segmentLocalId=" + sideStreetInfo.segmentLocalId); + } + } + } + + @Nullable + private SideStreetInfo findSideStreetInfo(@NonNull ElectronicHorizonPath branchingPath, int pathIndex) { + for (ElectronicHorizonSegment segment : branchingPath.segments) { + DirectedOCMSegmentId directedOCMSegmentId = segment.segmentId.ocmSegmentId; + if (directedOCMSegmentId == null) { + continue; + } + + ElectronicHorizonDataLoaderResult result = electronicHorizonDataLoader.getSegment(directedOCMSegmentId); + if (result.errorCode != null || result.segmentData == null) { + continue; + } + + SegmentData segmentData = result.segmentData; + String sideStreetName = getFirstStreetLabel(segmentData); + if (sideStreetName == null) { + continue; + } + + GeoPolyline polyline = segmentData.getPolyline(); + if (polyline == null) { + continue; + } + + GeoCoordinates sideStreetCoordinates = polyline.coordinatesAtOffsetInMeters( + SIDE_STREET_LOG_OFFSET_METERS, + GeoPolylineDirection.FROM_BEGINNING); + return new SideStreetInfo( + sideStreetName, + sideStreetCoordinates, + pathIndex, + directedOCMSegmentId.id.localId); + } + + return null; + } + + // Returns the first non-empty street label (street name or road number). + @Nullable + private String getFirstStreetLabel(@NonNull SegmentData segmentData) { + List segmentSpans = segmentData.getSpans(); + if (segmentSpans == null || segmentSpans.isEmpty()) { + return null; + } + + for (SegmentSpanData segmentSpanData : segmentSpans) { + if (segmentSpanData == null) { + continue; + } + + String streetName = null; + if (segmentSpanData.getStreetNames() != null) { + streetName = segmentSpanData.getStreetNames().getDefaultValue(); + } + if ((streetName == null || streetName.trim().isEmpty()) && segmentSpanData.getRoadNumbers() != null) { + streetName = segmentSpanData.getRoadNumbers().getDefaultValue(); + } + if (streetName != null && !streetName.trim().isEmpty()) { + return streetName; + } + } + + return null; + } + // Log road sign information from a fully loaded segment. private void logRoadSigns(SegmentData segmentData, DirectedOCMSegmentId directedOCMSegmentId) { List roadSigns = segmentData.getRoadSigns(); if (roadSigns == null || roadSigns.isEmpty()) return; + GeoPolyline segmentPolyline = segmentData.getPolyline(); + if (segmentPolyline == null) { + Log.w(LOG_TAG, "Skipping road sign logging: segment polyline is null for segmentId=" + directedOCMSegmentId.id.localId); + return; + } for (RoadSign roadSign : roadSigns) { - GeoCoordinates roadSignCoordinates = getGeoCoordinatesFromOffsetInMeters(segmentData.getPolyline(), roadSign.offsetInMeters); + @Nullable GeoCoordinates roadSignCoordinates = getGeoCoordinatesFromOffsetInMeters(segmentPolyline, roadSign.offsetInMeters); + if (roadSignCoordinates == null) { + Log.w(LOG_TAG, "Skipping road sign: coordinates lookup failed for offset=" + roadSign.offsetInMeters + + " on segmentId=" + directedOCMSegmentId.id.localId); + continue; + } Log.d(LOG_TAG, "RoadSign: type = " + roadSign.roadSignType.name() + ", offsetInMeters = " + roadSign.offsetInMeters @@ -396,7 +507,11 @@ private void logRoadSigns(SegmentData segmentData, DirectedOCMSegmentId directed } // Convert an offset in meters along a GeoPolyline to GeoCoordinates using the HERE SDK's coordinatesAtOffsetInMeters. - private GeoCoordinates getGeoCoordinatesFromOffsetInMeters(GeoPolyline geoPolyline, int offsetInMeters) { + @Nullable + private GeoCoordinates getGeoCoordinatesFromOffsetInMeters(@Nullable GeoPolyline geoPolyline, int offsetInMeters) { + if (geoPolyline == null) { + return null; + } return geoPolyline.coordinatesAtOffsetInMeters(offsetInMeters, GeoPolylineDirection.FROM_BEGINNING); } @@ -411,6 +526,25 @@ public void stop() { Log.d(LOG_TAG, "ElectronicHorizonEngine stopped."); } + private static class SideStreetInfo { + private final String streetName; + // Representative point on the matched side-street segment. + private final GeoCoordinates coordinateAtOffsetFromSegmentStart; + private final int pathIndex; + private final long segmentLocalId; + + private SideStreetInfo( + @NonNull String streetName, + @NonNull GeoCoordinates coordinateAtOffsetFromSegmentStart, + int pathIndex, + long segmentLocalId) { + this.streetName = streetName; + this.coordinateAtOffsetFromSegmentStart = coordinateAtOffsetFromSegmentStart; + this.pathIndex = pathIndex; + this.segmentLocalId = segmentLocalId; + } + } + private SDKNativeEngine getSDKNativeEngine() { SDKNativeEngine sdkNativeEngine = SDKNativeEngine.getSharedInstance(); if (sdkNativeEngine == null) { diff --git a/examples/latest/navigate/android/Java/NavigationCustom/app/build.gradle b/examples/latest/navigate/android/Java/NavigationCustom/app/build.gradle index 2bbe1ee6f..26ef8310b 100644 --- a/examples/latest/navigate/android/Java/NavigationCustom/app/build.gradle +++ b/examples/latest/navigate/android/Java/NavigationCustom/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/NavigationHeadless/app/build.gradle b/examples/latest/navigate/android/Java/NavigationHeadless/app/build.gradle index 8e364855c..1ae8d3b93 100644 --- a/examples/latest/navigate/android/Java/NavigationHeadless/app/build.gradle +++ b/examples/latest/navigate/android/Java/NavigationHeadless/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/NavigationQuickStart/app/build.gradle b/examples/latest/navigate/android/Java/NavigationQuickStart/app/build.gradle index 02330479c..f97fe2cf8 100644 --- a/examples/latest/navigate/android/Java/NavigationQuickStart/app/build.gradle +++ b/examples/latest/navigate/android/Java/NavigationQuickStart/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/NavigationWarners/app/build.gradle b/examples/latest/navigate/android/Java/NavigationWarners/app/build.gradle index 3b3049003..6be8c5fb3 100644 --- a/examples/latest/navigate/android/Java/NavigationWarners/app/build.gradle +++ b/examples/latest/navigate/android/Java/NavigationWarners/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/NavigationWarnersExample.java b/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/NavigationWarnersExample.java index 4d72c9fb5..2814f12b1 100644 --- a/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/NavigationWarnersExample.java +++ b/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/NavigationWarnersExample.java @@ -47,7 +47,6 @@ import com.here.sdk.navigation.CurrentSituationLaneAssistanceViewListener; import com.here.sdk.navigation.CurrentSituationLaneView; import com.here.sdk.navigation.DestinationReachedListener; -import com.here.sdk.navigation.DistanceType; import com.here.sdk.navigation.JunctionViewLaneAssistance; import com.here.sdk.navigation.JunctionViewLaneAssistanceListener; import com.here.sdk.navigation.Lane; diff --git a/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/WarnerEngineExample.java b/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/WarnerEngineExample.java index 33936ca6c..2d299e63b 100644 --- a/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/WarnerEngineExample.java +++ b/examples/latest/navigate/android/Java/NavigationWarners/app/src/main/java/com/here/navigationwarners/WarnerEngineExample.java @@ -186,7 +186,6 @@ private void configureEnabledWarnings() { } // Configures notification distances for specific warning types through the WarnerEngine. - // This replaces the individual setWarningNotificationDistances() calls on the VisualNavigator. private void configureNotificationDistances() { // Configure custom notification distances for road sign warnings. WarningNotificationDistances roadSignDistances = warnerEngine.getWarningNotificationDistances(WarningType.ROAD_SIGN); @@ -254,8 +253,9 @@ private void handleSafetyCameraWarning(WarningUpdate warningUpdate, WarningsRegi } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { + // The start indicates the SafetyCamera spot. Log.d(TAG, "SafetyCameraWarning " + safetyCameraWarning.type.name() - + " ahead in: " + safetyCameraWarning.distanceToCameraInMeters + " meters" + + " ahead in: " + warningUpdate.distanceTillStartInMeters + " meters" + ", speed limit = " + safetyCameraWarning.speedLimitInMetersPerSecond + " m/s."); } else if (warningUpdate.warningStatus == WarningStatus.PASSED) { Log.d(TAG, "SafetyCameraWarning " + safetyCameraWarning.type.name() + " passed."); @@ -278,7 +278,8 @@ private void handleTruckRestrictionWarning(WarningUpdate warningUpdate, Warnings } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { - Log.d(TAG, "TruckRestrictionWarning ahead in: " + truckRestrictionWarning.distanceInMeters + " meters."); + // The start indicates where the truck restriction becomes effective. + Log.d(TAG, "TruckRestrictionWarning ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); if (truckRestrictionWarning.timeRule != null && !truckRestrictionWarning.timeRule.appliesTo(new Date())) { Log.d(TAG, "Note that this truck restriction warning currently does not apply."); } @@ -312,8 +313,9 @@ private void handleRoadSignWarning(WarningUpdate warningUpdate, WarningsRegistry RoadSignType roadSignType = roadSignWarning.type; if (warningUpdate.warningStatus == WarningStatus.AHEAD) { + // The start indicates the RoadSign spot. Log.d(TAG, "RoadSignWarning of type: " + roadSignType.name() - + " ahead in (m): " + roadSignWarning.distanceToRoadSignInMeters); + + " ahead in (m): " + warningUpdate.distanceTillStartInMeters); } else if (warningUpdate.warningStatus == WarningStatus.PASSED) { Log.d(TAG, "RoadSignWarning of type: " + roadSignType.name() + " just passed."); } @@ -333,7 +335,8 @@ private void handleSchoolZoneWarning(WarningUpdate warningUpdate, WarningsRegist } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { - Log.d(TAG, "SchoolZoneWarning ahead in: " + schoolZoneWarning.distanceToSchoolZoneInMeters + " meters."); + // The start indicates where the school zone begins. + Log.d(TAG, "SchoolZoneWarning ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); Log.d(TAG, "Speed limit for this school zone: " + schoolZoneWarning.speedLimitInMetersPerSecond + " m/s."); if (schoolZoneWarning.timeRule != null && !schoolZoneWarning.timeRule.appliesTo(new Date())) { Log.d(TAG, "Note that this school zone warning currently does not apply."); @@ -356,7 +359,8 @@ private void handleBorderCrossingWarning(WarningUpdate warningUpdate, WarningsRe } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { - Log.d(TAG, "BorderCrossing ahead in: " + borderCrossingWarning.distanceToBorderCrossingInMeters + " meters."); + // The start indicates the border crossing spot. + Log.d(TAG, "BorderCrossing ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); Log.d(TAG, "BorderCrossing type: " + borderCrossingWarning.type.name()); Log.d(TAG, "BorderCrossing country code: " + borderCrossingWarning.administrativeRules.countryCode.name()); @@ -384,7 +388,8 @@ private void handleDangerZoneWarning(WarningUpdate warningUpdate, WarningsRegist } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { - Log.d(TAG, "DangerZone ahead in: " + dangerZoneWarning.distanceInMeters + " meters."); + // The start indicates where the danger zone begins. + Log.d(TAG, "DangerZone ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); Log.d(TAG, "isZoneStart: " + dangerZoneWarning.isZoneStart); } else if (warningUpdate.warningStatus == WarningStatus.REACHED) { Log.d(TAG, "A danger zone has been reached. isZoneStart: " + dangerZoneWarning.isZoneStart); @@ -403,7 +408,8 @@ private void handleLowSpeedZoneWarning(WarningUpdate warningUpdate, WarningsRegi } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { - Log.d(TAG, "LowSpeedZone ahead in: " + lowSpeedZoneWarning.distanceToLowSpeedZoneInMeters + " meters."); + // The start indicates where the low speed zone begins. + Log.d(TAG, "LowSpeedZone ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); Log.d(TAG, "Speed limit in low speed zone (m/s): " + lowSpeedZoneWarning.speedLimitInMetersPerSecond); } else if (warningUpdate.warningStatus == WarningStatus.REACHED) { Log.d(TAG, "A low speed zone has been reached."); @@ -423,7 +429,8 @@ private void handleRealisticViewWarning(WarningUpdate warningUpdate, WarningsReg return; } - double distance = realisticViewWarning.distanceToRealisticViewInMeters; + // The start indicates the RealisticView spot. + double distance = warningUpdate.distanceTillStartInMeters; if (warningUpdate.warningStatus == WarningStatus.AHEAD) { Log.d(TAG, "RealisticView ahead in: " + distance + " meters."); @@ -479,8 +486,9 @@ private void handleTrafficMergeWarning(WarningUpdate warningUpdate, WarningsRegi } if (warningUpdate.warningStatus == WarningStatus.AHEAD) { + // The start indicates the traffic merge spot. Log.d(TAG, "TrafficMerge: " + trafficMergeWarning.roadType.name() - + " ahead in: " + trafficMergeWarning.distanceToTrafficMergeInMeters + " meters" + + " ahead in: " + warningUpdate.distanceTillStartInMeters + " meters" + ", merging from the " + trafficMergeWarning.side.name() + " side" + ", with lanes = " + trafficMergeWarning.laneCount); } else if (warningUpdate.warningStatus == WarningStatus.PASSED) { diff --git a/examples/latest/navigate/android/Java/OfflineMaps/app/build.gradle b/examples/latest/navigate/android/Java/OfflineMaps/app/build.gradle index 9c9152148..239ce82a4 100644 --- a/examples/latest/navigate/android/Java/OfflineMaps/app/build.gradle +++ b/examples/latest/navigate/android/Java/OfflineMaps/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/OffscreenMapSurface/app/build.gradle b/examples/latest/navigate/android/Java/OffscreenMapSurface/app/build.gradle index e8ce20922..19cb49bfb 100644 --- a/examples/latest/navigate/android/Java/OffscreenMapSurface/app/build.gradle +++ b/examples/latest/navigate/android/Java/OffscreenMapSurface/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/PublicTransit/app/build.gradle b/examples/latest/navigate/android/Java/PublicTransit/app/build.gradle index a80f88f67..225179530 100644 --- a/examples/latest/navigate/android/Java/PublicTransit/app/build.gradle +++ b/examples/latest/navigate/android/Java/PublicTransit/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/Rerouting/app/build.gradle b/examples/latest/navigate/android/Java/Rerouting/app/build.gradle index 930ff6b69..8a5a17258 100644 --- a/examples/latest/navigate/android/Java/Rerouting/app/build.gradle +++ b/examples/latest/navigate/android/Java/Rerouting/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/Routing/app/build.gradle b/examples/latest/navigate/android/Java/Routing/app/build.gradle index 8864f81e4..ceb1f5941 100644 --- a/examples/latest/navigate/android/Java/Routing/app/build.gradle +++ b/examples/latest/navigate/android/Java/Routing/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/RoutingHybrid/app/build.gradle b/examples/latest/navigate/android/Java/RoutingHybrid/app/build.gradle index e23fc7ac0..6048694fd 100644 --- a/examples/latest/navigate/android/Java/RoutingHybrid/app/build.gradle +++ b/examples/latest/navigate/android/Java/RoutingHybrid/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/build.gradle b/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/build.gradle index 033a31c76..9974acb82 100644 --- a/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/build.gradle +++ b/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/src/main/java/com/here/routingwithavoidanceoptions/RoutingWithAvoidanceOptionExample.java b/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/src/main/java/com/here/routingwithavoidanceoptions/RoutingWithAvoidanceOptionExample.java index edfef193e..ae8dfce00 100644 --- a/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/src/main/java/com/here/routingwithavoidanceoptions/RoutingWithAvoidanceOptionExample.java +++ b/examples/latest/navigate/android/Java/RoutingWithAvoidanceOptions/app/src/main/java/com/here/routingwithavoidanceoptions/RoutingWithAvoidanceOptionExample.java @@ -20,6 +20,8 @@ package com.here.routingwithavoidanceoptions; import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; import android.util.Log; import android.widget.Toast; @@ -223,6 +225,7 @@ public void onPickMap(@Nullable MapPickResult mapPickResult) { } PickMapItemsResult pickMapItemsResult = mapPickResult.getMapItems(); + if (pickMapItemsResult == null) return; List markers = pickMapItemsResult.getMarkers(); if (!markers.isEmpty()) { MapMarker pickedMarker = markers.get(0); @@ -312,7 +315,7 @@ public void matchLocation(GeoCoordinates geoCoordinates) { Toast.makeText(context,"Map-matched location is highlighted with red dot on the map. Check logs for more information on matched location.", Toast.LENGTH_LONG).show(); // Show the map-matched location on the map. - MapMarker mapMatchedMapMarker = addMapMarker(mapMatchedLocation.coordinates, R.drawable.map_matched_location_dot); + MapMarker mapMatchedMapMarker = addScaledMapMarker(mapMatchedLocation.coordinates, R.drawable.map_matched_location_dot, 80, 0.7); mapMatchedMarkers.add(mapMatchedMapMarker); // Fetch IDs from mapMatchedLocation and convert them into OCMSegmentID required by loadSegmentData method. @@ -348,11 +351,17 @@ private void loadSegmentData(OCMSegmentId ocmSegmentId) { List segmentSpanDataList = segmentData.getSpans(); SegmentReference segmentReference = segmentData.getSegmentReference(); + GeoPolyline segmentPolyline = segmentData.getPolyline(); + if (segmentPolyline == null) { + Log.d(TAG, "Segment polyline is null for segment: " + segmentReference.segmentId + ". Skipping visualization."); + return; + } + Metadata metadata = new Metadata(); metadata.setString(METADATA_SEGMENT_ID_KEY, segmentReference.segmentId); metadata.setDouble(METADATA_TILE_PARTITION_ID_KEY, segmentReference.tilePartitionId); - MapPolyline segmentPolyLine = createMapPolyline(Color.valueOf(1, 0, 0, 1), segmentData.getPolyline()); + MapPolyline segmentPolyLine = createMapPolyline(Color.valueOf(1, 0, 0, 1), segmentPolyline); segmentPolyLine.setMetadata(metadata); mapView.getMapScene().addMapPolyline(segmentPolyLine); segmentPolyLines.add(segmentPolyLine); @@ -535,6 +544,18 @@ private MapMarker addMapMarker(GeoCoordinates geoCoordinates, int resourceId) { return mapMarker; } + private MapMarker addScaledMapMarker(GeoCoordinates geoCoordinates, int resourceId, int widthInPixels, double opacity) { + Bitmap original = BitmapFactory.decodeResource(context.getResources(), resourceId); + int height = (int) (original.getHeight() * (widthInPixels / (float) original.getWidth())); + Bitmap scaled = Bitmap.createScaledBitmap(original, widthInPixels, height, true); + MapImage mapImage = MapImageFactory.fromBitmap(scaled); + Anchor2D anchor2D = new Anchor2D(0.5F, 0.5F); + MapMarker mapMarker = new MapMarker(geoCoordinates, mapImage, anchor2D); + mapMarker.setOpacity(opacity); + mapView.getMapScene().addMapMarker(mapMarker); + return mapMarker; + } + private void showDialog(String title, String message) { AlertDialog.Builder builder = new AlertDialog.Builder(context); diff --git a/examples/latest/navigate/android/Java/Search/app/build.gradle b/examples/latest/navigate/android/Java/Search/app/build.gradle index 899b6b441..af985e39d 100644 --- a/examples/latest/navigate/android/Java/Search/app/build.gradle +++ b/examples/latest/navigate/android/Java/Search/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/SearchHybrid/app/build.gradle b/examples/latest/navigate/android/Java/SearchHybrid/app/build.gradle index 899b6b441..af985e39d 100644 --- a/examples/latest/navigate/android/Java/SearchHybrid/app/build.gradle +++ b/examples/latest/navigate/android/Java/SearchHybrid/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/SpatialAudioNavigation/app/build.gradle b/examples/latest/navigate/android/Java/SpatialAudioNavigation/app/build.gradle index 03c3eee1b..2546069f5 100644 --- a/examples/latest/navigate/android/Java/SpatialAudioNavigation/app/build.gradle +++ b/examples/latest/navigate/android/Java/SpatialAudioNavigation/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/Traffic/app/build.gradle b/examples/latest/navigate/android/Java/Traffic/app/build.gradle index d17603dc0..b2cbee8e2 100644 --- a/examples/latest/navigate/android/Java/Traffic/app/build.gradle +++ b/examples/latest/navigate/android/Java/Traffic/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/Traffic/build.gradle b/examples/latest/navigate/android/Java/Traffic/build.gradle index 441555412..9435ce012 100644 --- a/examples/latest/navigate/android/Java/Traffic/build.gradle +++ b/examples/latest/navigate/android/Java/Traffic/build.gradle @@ -26,7 +26,7 @@ allprojects { if (rootProject.ext.HERESDKBuildConfig == "COMPONENTS_FROM_ARTIFACTORY") { maven { name = 'HERE_SDK_Artifactory_Repository' - url = "https://repo.platform.here.com/artifactory/here-sdk-android" + url = project.findProperty('HERESDKArtifactoryURL') ?: "https://repo.platform.here.com/artifactory/here-sdk-android" credentials { // Use the username and token created on https://platform.here.com/access/access-tokens. username = project.findProperty('HERESDKArtifactoryUsername') ?: "YOUR_USER_NAME" diff --git a/examples/latest/navigate/android/Java/TruckGuidance/app/build.gradle b/examples/latest/navigate/android/Java/TruckGuidance/app/build.gradle index 0a9e6b526..74fd3a64f 100644 --- a/examples/latest/navigate/android/Java/TruckGuidance/app/build.gradle +++ b/examples/latest/navigate/android/Java/TruckGuidance/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/TruckGuidance/app/src/main/java/com/here/truckguidance/TruckGuidanceExample.java b/examples/latest/navigate/android/Java/TruckGuidance/app/src/main/java/com/here/truckguidance/TruckGuidanceExample.java index d340d376c..5123666f4 100644 --- a/examples/latest/navigate/android/Java/TruckGuidance/app/src/main/java/com/here/truckguidance/TruckGuidanceExample.java +++ b/examples/latest/navigate/android/Java/TruckGuidance/app/src/main/java/com/here/truckguidance/TruckGuidanceExample.java @@ -484,6 +484,7 @@ private void handleTruckRestrictionWarning(WarningUpdate warningUpdate, Warnings WarningStatus warningStatus = warningUpdate.warningStatus; if (warningStatus == WarningStatus.AHEAD || warningStatus == WarningStatus.APPROACHING) { + // The start indicates where the truck restriction becomes effective. Log.d(TAG, "A TruckRestriction ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); } else if (warningStatus == WarningStatus.REACHED || warningStatus == WarningStatus.INSIDE) { Log.d(TAG, "A TruckRestriction has been reached."); @@ -510,6 +511,7 @@ private void handleEnvironmentalZoneWarning(WarningUpdate warningUpdate, Warning WarningStatus warningStatus = warningUpdate.warningStatus; if (warningStatus == WarningStatus.AHEAD || warningStatus == WarningStatus.APPROACHING) { + // The start indicates where the environmental zone begins. Log.d(TAG, "A EnvironmentalZone ahead in: " + warningUpdate.distanceTillStartInMeters + " meters."); } else if (warningStatus == WarningStatus.REACHED || warningStatus == WarningStatus.INSIDE) { Log.d(TAG, "A EnvironmentalZone has been reached."); diff --git a/examples/latest/navigate/android/Java/UnitTesting/README.md b/examples/latest/navigate/android/Java/UnitTesting/README.md index a3ee34e42..afa324629 100644 --- a/examples/latest/navigate/android/Java/UnitTesting/README.md +++ b/examples/latest/navigate/android/Java/UnitTesting/README.md @@ -2,14 +2,15 @@ The UnitTesting example app shows how the HERE SDK can be mocked in unit tests. ![Map view backing the example app that is covered by mocked unit tests](images/unit_testing.png) -This example uses **HERE SDK Units** to support functionality such as permission handling or buttons that are not essential to the code snippets shown in this app, as the focus is on demonstrating how to use the APIs provided by the HERE SDK. The HERE SDK Units are included as AARs in the app’s `libs` folder. For more details, see the "HERESDKUnits" app to customize or create your own unit libraries. Note that this app is intended exclusively for the HERE SDK (Navigate). You can find it in the `navigate` folder. However, it can be easily adapted for the HERE SDK (Explore) by removing any code that is not supported there. At present, most components are compatible and will compile without issues. - Build instructions: ------------------- -1) Copy the AAR and "heresdk-xxx.jar" mock JAR file of the HERE SDK for Android to your app's `app/libs` folder. +1) Copy the AAR file of the HERE SDK for Android to your app's `app/libs` folder. + +2) Copy the "heresdk-xxx.jar" mock JAR file of the HERE SDK for Android to your app's `app/libs` folder. + +Note: If your AAR/JAR versions are different than the version shown in the _Developer Guide_, you may need to adapt the source code of the example app. -Note: If your AAR/JAR version are different than the version shown in the _Developer Guide_, you may need to adapt the source code of the example app. +3) Open Android Studio and sync the project. -2) Open Android Studio and sync the project. -3) Open file TestBasicTypes.java and run unit tests from it. +4) Open file `TestBasicTypes.java` and run unit tests from it. diff --git a/examples/latest/navigate/android/Java/UnitTesting/app/build.gradle b/examples/latest/navigate/android/Java/UnitTesting/app/build.gradle index 1d1522091..3dbf920e1 100644 --- a/examples/latest/navigate/android/Java/UnitTesting/app/build.gradle +++ b/examples/latest/navigate/android/Java/UnitTesting/app/build.gradle @@ -13,7 +13,7 @@ android { release { signingConfig signingConfigs.debug minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { diff --git a/examples/latest/navigate/android/Java/UnitTesting/app/libs/README.md b/examples/latest/navigate/android/Java/UnitTesting/app/libs/README.md index 7b2708307..04724d7bd 100644 --- a/examples/latest/navigate/android/Java/UnitTesting/app/libs/README.md +++ b/examples/latest/navigate/android/Java/UnitTesting/app/libs/README.md @@ -1 +1,3 @@ -Put the latest AAR file of the HERE SDK for Android and the "heresdk-xxx.jar" mock JAR file to this folder. \ No newline at end of file +This app requires the unit testing mock library for the HERE SDK: Put the latest AAR file of the HERE SDK for Android and the "heresdk-xxx.jar" mock JAR file to this folder. + +On top, you need to add the HERE SDK AAR here. diff --git a/examples/latest/navigate/android/Kotlin/NavigationKotlin/app/src/main/java/com/here/navigationkotlin/ElectronicHorizonHandler.kt b/examples/latest/navigate/android/Kotlin/NavigationKotlin/app/src/main/java/com/here/navigationkotlin/ElectronicHorizonHandler.kt index 1d848f693..df5c1c64d 100644 --- a/examples/latest/navigate/android/Kotlin/NavigationKotlin/app/src/main/java/com/here/navigationkotlin/ElectronicHorizonHandler.kt +++ b/examples/latest/navigate/android/Kotlin/NavigationKotlin/app/src/main/java/com/here/navigationkotlin/ElectronicHorizonHandler.kt @@ -68,6 +68,7 @@ import com.here.sdk.transport.TransportMode // it will asynchronously request the data from the HERE backend services. // It is recommended to use a prefetcher to prefetch region data along the route in advance (not shown in this class). class ElectronicHorizonHandler(private val mapView: MapView) { + private var electronicHorizon: ElectronicHorizonEngine? = null private val electronicHorizonDataLoader: ElectronicHorizonDataLoader private var electronicHorizonListener: ElectronicHorizonListener @@ -94,10 +95,12 @@ class ElectronicHorizonHandler(private val mapView: MapView) { segmentDataLoaderOptions.loadRoadSigns = true segmentDataLoaderOptions.loadSpeedLimits = true segmentDataLoaderOptions.loadRoadAttributes = true + segmentDataLoaderOptions.loadStreetNamesAndRoadNumbers = true // The cache size defines how many road segments are cached locally. A larger cache size // can reduce data usage, but requires more storage memory in the cache. - val segmentDataCacheSize = 10 + // A small cache can replace previously loaded segments too early. + val segmentDataCacheSize = 1000 try { electronicHorizonDataLoader = ElectronicHorizonDataLoader( this.sDKNativeEngine, @@ -255,6 +258,12 @@ class ElectronicHorizonHandler(private val mapView: MapView) { continue } + // Wait until first-level side-path data is fully loaded before logging side streets + // that branch directly from the active route. + if (loadedLevel == 1) { + notifySideStreetInfos(allPaths) + } + // For side-path levels (level > 0): walk all path segments and use // sidePathIndexes to find paths that branch off at each segment. // sidePathIndexes contains indexes into allPaths[], pointing to branching paths. @@ -364,6 +373,73 @@ class ElectronicHorizonHandler(private val mapView: MapView) { segmentPolylineMap.clear() } + // Finds first-level side streets whose parent is the currently followed navigation path. + private fun notifySideStreetInfos(allPaths: List) { + for ((pathIndex, path) in allPaths.withIndex()) { + if (path.level != 1 || path.parentPathIndex == null || path.parentPathIndex != 0) { + continue + } + + val sideStreetInfo = findSideStreetInfo(path, pathIndex) ?: continue + Log.d( + LOG_TAG, + "SideStreetName near active route: ${sideStreetInfo.streetName} at lat/lon: " + + "${sideStreetInfo.coordinateAtOffsetFromSegmentStart.latitude}/" + + "${sideStreetInfo.coordinateAtOffsetFromSegmentStart.longitude}, " + + "pathIndex=${sideStreetInfo.pathIndex}, segmentLocalId=${sideStreetInfo.segmentLocalId}" + ) + } + } + + private fun findSideStreetInfo( + branchingPath: com.here.sdk.electronichorizon.ElectronicHorizonPath, + pathIndex: Int + ): SideStreetInfo? { + for (segment in branchingPath.segments) { + val directedOCMSegmentId = segment.segmentId.ocmSegmentId ?: continue + val result = electronicHorizonDataLoader.getSegment(directedOCMSegmentId) + if (result.errorCode != null || result.segmentData == null) { + continue + } + + val segmentData = result.segmentData!! + val sideStreetName = getFirstStreetLabel(segmentData) ?: continue + val polyline = segmentData.polyline ?: continue + val sideStreetCoordinates = polyline.coordinatesAtOffsetInMeters( + SIDE_STREET_LOG_OFFSET_METERS, + GeoPolylineDirection.FROM_BEGINNING + ) + return SideStreetInfo( + sideStreetName, + sideStreetCoordinates, + pathIndex, + directedOCMSegmentId.id.localId + ) + } + + return null + } + + // Returns the first non-empty street label (street name or road number). + private fun getFirstStreetLabel(segmentData: SegmentData): String? { + val segmentSpans = segmentData.spans ?: return null + if (segmentSpans.isEmpty()) { + return null + } + + for (segmentSpanData in segmentSpans) { + var streetName: String? = segmentSpanData.streetNames?.getDefaultValue() + if (streetName.isNullOrBlank()) { + streetName = segmentSpanData.roadNumbers?.getDefaultValue() + } + if (!streetName.isNullOrBlank()) { + return streetName + } + } + + return null + } + // Log road sign information from a fully loaded segment. Demonstrates how to read // road attributes from SegmentData for MPP segments. private fun logRoadSigns(segmentData: SegmentData, directedOCMSegmentId: DirectedOCMSegmentId) { @@ -412,6 +488,16 @@ class ElectronicHorizonHandler(private val mapView: MapView) { } companion object { + // Optional: Using a small offset can help mark/log the side street more clearly for visualization. + private const val SIDE_STREET_LOG_OFFSET_METERS = 20.0 private val LOG_TAG: String = ElectronicHorizonHandler::class.java.name } + + private data class SideStreetInfo( + val streetName: String, + // Representative point on the matched side-street segment. + val coordinateAtOffsetFromSegmentStart: GeoCoordinates, + val pathIndex: Int, + val segmentLocalId: Int, + ) } diff --git a/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/NavigationWarnersExample.kt b/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/NavigationWarnersExample.kt index ddb7575ee..d3e12ae71 100644 --- a/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/NavigationWarnersExample.kt +++ b/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/NavigationWarnersExample.kt @@ -41,7 +41,6 @@ import com.here.sdk.navigation.CurrentSituationLaneAssistanceView import com.here.sdk.navigation.CurrentSituationLaneAssistanceViewListener import com.here.sdk.navigation.CurrentSituationLaneView import com.here.sdk.navigation.DestinationReachedListener -import com.here.sdk.navigation.DistanceType import com.here.sdk.navigation.JunctionViewLaneAssistance import com.here.sdk.navigation.JunctionViewLaneAssistanceListener import com.here.sdk.navigation.Lane diff --git a/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/WarnerEngineExample.kt b/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/WarnerEngineExample.kt index 4322b9e09..4f5396567 100644 --- a/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/WarnerEngineExample.kt +++ b/examples/latest/navigate/android/Kotlin/NavigationWarnersKotlin/app/src/main/java/com/here/navigationwarnerskotlin/WarnerEngineExample.kt @@ -133,7 +133,6 @@ class WarnerEngineExample { } // Configures notification distances for specific warning types through the WarnerEngine. - // This replaces the individual setWarningNotificationDistances() calls on the VisualNavigator. private fun configureNotificationDistances() { // Configure custom notification distances for road sign warnings. val roadSignDistances = warnerEngine.getWarningNotificationDistances(WarningType.ROAD_SIGN) @@ -214,8 +213,9 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> Log.d(TAG, + // The start indicates the SafetyCamera spot. "SafetyCameraWarning ${safetyCameraWarning.type.name} ahead in: " + - "${safetyCameraWarning.distanceToCameraInMeters} meters" + + "${warningUpdate.distanceTillStartInMeters} meters" + ", speed limit = ${safetyCameraWarning.speedLimitInMetersPerSecond} m/s.") WarningStatus.PASSED -> Log.d(TAG, "SafetyCameraWarning ${safetyCameraWarning.type.name} passed.") @@ -236,7 +236,8 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> { - Log.d(TAG, "TruckRestrictionWarning ahead in: ${truckRestrictionWarning.distanceInMeters} meters.") + // The start indicates where the truck restriction becomes effective. + Log.d(TAG, "TruckRestrictionWarning ahead in: ${warningUpdate.distanceTillStartInMeters} meters.") if (truckRestrictionWarning.timeRule != null && !truckRestrictionWarning.timeRule!!.appliesTo(Date())) { Log.d(TAG, "Note that this truck restriction warning currently does not apply.") } @@ -271,7 +272,8 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> Log.d(TAG, - "RoadSignWarning of type: ${roadSignWarning.type.name} ahead in (m): ${roadSignWarning.distanceToRoadSignInMeters}") + // The start indicates the RoadSign spot. + "RoadSignWarning of type: ${roadSignWarning.type.name} ahead in (m): ${warningUpdate.distanceTillStartInMeters}") WarningStatus.PASSED -> Log.d(TAG, "RoadSignWarning of type: ${roadSignWarning.type.name} just passed.") else -> {} @@ -292,7 +294,8 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> { - Log.d(TAG, "SchoolZoneWarning ahead in: ${schoolZoneWarning.distanceToSchoolZoneInMeters} meters.") + // The start indicates where the school zone begins. + Log.d(TAG, "SchoolZoneWarning ahead in: ${warningUpdate.distanceTillStartInMeters} meters.") Log.d(TAG, "Speed limit for this school zone: ${schoolZoneWarning.speedLimitInMetersPerSecond} m/s.") if (schoolZoneWarning.timeRule != null && !schoolZoneWarning.timeRule!!.appliesTo(Date())) { Log.d(TAG, "Note that this school zone warning currently does not apply.") @@ -315,7 +318,8 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> { - Log.d(TAG, "BorderCrossing ahead in: ${borderCrossingWarning.distanceToBorderCrossingInMeters} meters.") + // The start indicates the border crossing spot. + Log.d(TAG, "BorderCrossing ahead in: ${warningUpdate.distanceTillStartInMeters} meters.") Log.d(TAG, "BorderCrossing type: ${borderCrossingWarning.type.name}") Log.d(TAG, "BorderCrossing country code: ${borderCrossingWarning.administrativeRules.countryCode.name}") @@ -344,7 +348,8 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> { - Log.d(TAG, "DangerZone ahead in: ${dangerZoneWarning.distanceInMeters} meters.") + // The start indicates where the danger zone begins. + Log.d(TAG, "DangerZone ahead in: ${warningUpdate.distanceTillStartInMeters} meters.") Log.d(TAG, "isZoneStart: ${dangerZoneWarning.isZoneStart}") } WarningStatus.REACHED -> Log.d(TAG, "A danger zone has been reached. isZoneStart: ${dangerZoneWarning.isZoneStart}") @@ -363,7 +368,8 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> { - Log.d(TAG, "LowSpeedZone ahead in: ${lowSpeedZoneWarning.distanceToLowSpeedZoneInMeters} meters.") + // The start indicates where the low speed zone begins. + Log.d(TAG, "LowSpeedZone ahead in: ${warningUpdate.distanceTillStartInMeters} meters.") Log.d(TAG, "Speed limit in low speed zone (m/s): ${lowSpeedZoneWarning.speedLimitInMetersPerSecond}") } WarningStatus.REACHED -> { @@ -384,7 +390,8 @@ class WarnerEngineExample { return } - val distance = realisticViewWarning.distanceToRealisticViewInMeters + // The start indicates the RealisticView spot. + val distance = warningUpdate.distanceTillStartInMeters when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> Log.d(TAG, "RealisticView ahead in: $distance meters.") @@ -434,8 +441,9 @@ class WarnerEngineExample { when (warningUpdate.warningStatus) { WarningStatus.AHEAD -> Log.d(TAG, + // The start indicates the traffic merge spot. "TrafficMerge: ${trafficMergeWarning.roadType.name} ahead in: " + - "${trafficMergeWarning.distanceToTrafficMergeInMeters} meters" + + "${warningUpdate.distanceTillStartInMeters} meters" + ", merging from the ${trafficMergeWarning.side.name} side" + ", with lanes = ${trafficMergeWarning.laneCount}") WarningStatus.PASSED -> Log.d(TAG, diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/.gitignore b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/.gitignore new file mode 100644 index 000000000..02cf6d123 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/.gitignore @@ -0,0 +1,10 @@ +*.iml +.gradle +/local.properties +.idea/* +.DS_Store +/build +/captures +.externalNativeBuild +.cxx +local.properties diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/README.md b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/README.md new file mode 100644 index 000000000..5400818a7 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/README.md @@ -0,0 +1,16 @@ +The UnitTestingKotlin example app shows how the HERE SDK can be mocked in unit tests. + +![Map view backing the example app that is covered by mocked unit tests](images/unit_testing.png) + +Build instructions: +------------------- + +1) Copy the AAR file of the HERE SDK for Android to your app's `app/libs` folder. + +2) Copy the "heresdk-xxx.jar" mock JAR file of the HERE SDK for Android to your app's `app/libs` folder. This mock library was compiled for Java, but will also support most use cases for Kotlin. + +Note: If your AAR/JAR versions are different than the version shown in the _Developer Guide_, you may need to adapt the source code of the example app. + +3) Open Android Studio and sync the project. + +4) Open file `TestBasicTypes.kt` and run unit tests from it. diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/.gitignore b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/.gitignore new file mode 100644 index 000000000..35580e84f --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/.gitignore @@ -0,0 +1,7 @@ +/build + +# Ignore all AARs in libs. +/libs/*.aar + +# But NOT those that contain 'here-sdk-units' in the filename. +!libs/*here-sdk-units*.aar diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/build.gradle.kts b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/build.gradle.kts new file mode 100644 index 000000000..98ac12d72 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/build.gradle.kts @@ -0,0 +1,133 @@ +plugins { + alias(libs.plugins.android.application) + alias(libs.plugins.kotlin.android) + alias(libs.plugins.kotlin.compose) +} + +repositories { + google() + mavenCentral() + + flatDir { + dirs("libs") + } +} + +// Find the real HERE SDK AARs. +// We need their names because the AARs must be added as named dependencies. +// Adding them through fileTree() would make it impossible to exclude them +// from the unit test configuration later. +val hereSdkArtifactNames = fileTree("libs") { + include("heresdk-*.aar") +}.files.map { file -> + file.nameWithoutExtension +} + +// Unit tests must not use the real HERE SDK AAR. +// Instead, they use the HERE SDK mock JAR added further below. +configurations.named("testImplementation") { + hereSdkArtifactNames.forEach { artifactName -> + exclude(module = artifactName) + } +} + +android { + namespace = "com.here.unittesting" + compileSdk = 35 + + defaultConfig { + applicationId = "com.here.unittesting" + minSdk = 24 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + signingConfig = signingConfigs.getByName("debug") + } + + buildTypes { + release { + isMinifyEnabled = false + + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = "11" + } + + buildFeatures { + compose = true + } +} + +dependencies { + + // ------------------------------------------------------------------------- + // HERE SDK + // ------------------------------------------------------------------------- + + // Use the real HERE SDK AAR when building/running the application. + // + // Important: + // Do not add the HERE SDK using: + // + // implementation(fileTree(...)) + // + // because file dependencies cannot be excluded from the unit test + // dependency configuration. + hereSdkArtifactNames.forEach { artifactName -> + implementation( + mapOf( + "name" to artifactName, + "ext" to "aar" + ) + ) + } + + // Use the HERE SDK mock library for local JVM unit tests. + testImplementation( + fileTree("libs") { + include("heresdk-*-mock-*.jar") + } + ) + + // ------------------------------------------------------------------------- + // Android + // ------------------------------------------------------------------------- + + implementation(libs.androidx.core.ktx) + implementation(libs.androidx.appcompat) + implementation(libs.androidx.lifecycle.runtime.ktx) + implementation(libs.androidx.activity.compose) + + // ------------------------------------------------------------------------- + // Compose + // ------------------------------------------------------------------------- + + implementation(platform(libs.androidx.compose.bom)) + implementation(libs.androidx.ui) + implementation(libs.androidx.ui.graphics) + implementation(libs.androidx.ui.tooling.preview) + implementation(libs.androidx.material3) + + debugImplementation(libs.androidx.ui.tooling) + debugImplementation(libs.androidx.ui.test.manifest) + + // ------------------------------------------------------------------------- + // Unit testing + // ------------------------------------------------------------------------- + + testImplementation(kotlin("test")) + testImplementation("junit:junit:4.13.2") + testImplementation("org.mockito:mockito-core:5.23.0") +} \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/libs/README.md b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/libs/README.md new file mode 100644 index 000000000..24cb4eff7 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/libs/README.md @@ -0,0 +1,3 @@ +This app requires the unit testing mock library for the HERE SDK: Put the latest AAR file of the HERE SDK for Android and the "heresdk-xxx.jar" mock JAR file to this folder. + +On top, you need to add the HERE SDK AAR here. \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/proguard-rules.pro b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/AndroidManifest.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/AndroidManifest.xml new file mode 100644 index 000000000..5a382811b --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/AndroidManifest.xml @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/MainActivity.kt b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/MainActivity.kt new file mode 100644 index 000000000..a8fb61f57 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/MainActivity.kt @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2019-2026 HERE Europe B.V. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * License-Filename: LICENSE + */ +package com.here.unittesting + +import android.os.Bundle +import android.util.Log +import androidx.activity.ComponentActivity +import androidx.activity.compose.setContent +import androidx.activity.enableEdgeToEdge +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.Scaffold +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.viewinterop.AndroidView +import com.here.sdk.core.engine.AuthenticationMode +import com.here.sdk.core.engine.SDKNativeEngine +import com.here.sdk.core.engine.SDKOptions +import com.here.sdk.core.errors.InstantiationErrorException +import com.here.sdk.mapview.MapScheme +import com.here.sdk.mapview.MapView +import com.here.unittesting.ui.theme.UnitTestingTheme + +class MainActivity : ComponentActivity() { + + private var mapView: MapView? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + // Needs to be called before the activity is started. + + // Usually, you need to initialize the HERE SDK only once during the lifetime of an application. + // Before creating a MapView instance please make sure that the HERE SDK is initialized. + initializeHERESDK() + + enableEdgeToEdge() + + setContent { + UnitTestingTheme { + Scaffold( + modifier = Modifier.fillMaxSize() + ) { paddingValues -> + Box(modifier = Modifier.padding(paddingValues)) { + HereMapView(savedInstanceState) + } + } + } + } + } + + // Wrap the MapView into a Composable in order to use it with Jetpack Compose. + @Composable + private fun HereMapView(savedInstanceState: Bundle?) { + AndroidView(factory = { context -> + MapView(context).apply { + mapView = this + mapView?.onCreate(savedInstanceState) + loadMapScene() + } + }) + } + + private fun initializeHERESDK() { + // Set your credentials for the HERE SDK. + val accessKeyID = "YOUR_ACCESS_KEY_ID" + val accessKeySecret = "YOUR_ACCESS_KEY_SECRET" + val authenticationMode = AuthenticationMode.withKeySecret(accessKeyID, accessKeySecret) + val options = SDKOptions(authenticationMode) + try { + val context = this + SDKNativeEngine.makeSharedInstance(context, options) + } catch (e: InstantiationErrorException) { + throw RuntimeException("Initialization of HERE SDK failed: " + e.error.name) + } + } + + private fun loadMapScene() { + val mapViewNonNull = mapView ?: run { + Log.e(TAG, "mapView is null. Cannot load map scene.") + return + } + + // Load a scene from the HERE SDK to render the map with a map scheme. + mapViewNonNull.mapScene.loadScene(MapScheme.NORMAL_DAY) { mapError -> + if (mapError != null) { + Log.d(TAG, "Loading of map failed: mapError: ${mapError.name}") + } + } + } + + override fun onPause() { + mapView?.onPause() + super.onPause() + } + + override fun onResume() { + mapView?.onResume() + super.onResume() + } + + override fun onDestroy() { + mapView?.onDestroy() + disposeHERESDK() + super.onDestroy() + } + + override fun onSaveInstanceState(outState: Bundle) { + mapView?.onSaveInstanceState(outState) + super.onSaveInstanceState(outState) + } + + private fun disposeHERESDK() { + // Free HERE SDK resources before the application shuts down. + // Usually, this should be called only on application termination. + // Afterward, the HERE SDK is no longer usable unless it is initialized again. + SDKNativeEngine.getSharedInstance()?.dispose() + // For safety reasons, we explicitly set the shared instance to null to avoid situations, + // where a disposed instance is accidentally reused. + SDKNativeEngine.setSharedInstance(null) + } + + private companion object { + private val TAG = MainActivity::class.java.simpleName + } +} diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Color.kt b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Color.kt new file mode 100644 index 000000000..f0a5d11bc --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Color.kt @@ -0,0 +1,11 @@ +package com.here.unittesting.ui.theme + +import androidx.compose.ui.graphics.Color + +val Purple80 = Color(0xFFD0BCFF) +val PurpleGrey80 = Color(0xFFCCC2DC) +val Pink80 = Color(0xFFEFB8C8) + +val Purple40 = Color(0xFF6650a4) +val PurpleGrey40 = Color(0xFF625b71) +val Pink40 = Color(0xFF7D5260) diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Theme.kt b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Theme.kt new file mode 100644 index 000000000..f2186ab49 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Theme.kt @@ -0,0 +1,57 @@ +package com.here.unittesting.ui.theme + +import android.os.Build +import androidx.compose.foundation.isSystemInDarkTheme +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.darkColorScheme +import androidx.compose.material3.dynamicDarkColorScheme +import androidx.compose.material3.dynamicLightColorScheme +import androidx.compose.material3.lightColorScheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.platform.LocalContext + +private val DarkColorScheme = darkColorScheme( + primary = Purple80, + secondary = PurpleGrey80, + tertiary = Pink80 +) + +private val LightColorScheme = lightColorScheme( + primary = Purple40, + secondary = PurpleGrey40, + tertiary = Pink40 + + /* Other default colors to override + background = Color(0xFFFFFBFE), + surface = Color(0xFFFFFBFE), + onPrimary = Color.White, + onSecondary = Color.White, + onTertiary = Color.White, + onBackground = Color(0xFF1C1B1F), + onSurface = Color(0xFF1C1B1F), + */ +) + +@Composable +fun UnitTestingTheme( + darkTheme: Boolean = isSystemInDarkTheme(), + // Dynamic color is available on Android 12+ + dynamicColor: Boolean = true, + content: @Composable () -> Unit +) { + val colorScheme = when { + dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> { + val context = LocalContext.current + if (darkTheme) dynamicDarkColorScheme(context) else dynamicLightColorScheme(context) + } + + darkTheme -> DarkColorScheme + else -> LightColorScheme + } + + MaterialTheme( + colorScheme = colorScheme, + typography = Typography, + content = content + ) +} diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Type.kt b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Type.kt new file mode 100644 index 000000000..80420e2bd --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/java/com/here/unittesting/ui/theme/Type.kt @@ -0,0 +1,34 @@ +package com.here.unittesting.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +// Set of Material typography styles to start with +val Typography = Typography( + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ) + /* Other default text styles to override + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) + */ +) diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/drawable/ic_launcher_background.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 000000000..07d5da9cb --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/drawable/ic_launcher_foreground.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 000000000..2b068d114 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 000000000..6f3b755bf --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml new file mode 100644 index 000000000..6f3b755bf --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-hdpi/ic_launcher.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-hdpi/ic_launcher.webp new file mode 100644 index 000000000..c209e78ec Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-hdpi/ic_launcher.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp new file mode 100644 index 000000000..b2dfe3d1b Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-hdpi/ic_launcher_round.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-mdpi/ic_launcher.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-mdpi/ic_launcher.webp new file mode 100644 index 000000000..4f0f1d64e Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-mdpi/ic_launcher.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp new file mode 100644 index 000000000..62b611da0 Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-mdpi/ic_launcher_round.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.webp new file mode 100644 index 000000000..948a3070f Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..1b9a6956b Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xhdpi/ic_launcher_round.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp new file mode 100644 index 000000000..28d4b77f9 Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9287f5083 Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp new file mode 100644 index 000000000..aa7d6427e Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp new file mode 100644 index 000000000..9126ae37c Binary files /dev/null and b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp differ diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/colors.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/colors.xml new file mode 100644 index 000000000..f8c6127d3 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/colors.xml @@ -0,0 +1,10 @@ + + + #FFBB86FC + #FF6200EE + #FF3700B3 + #FF03DAC5 + #FF018786 + #FF000000 + #FFFFFFFF + \ No newline at end of file diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/strings.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/strings.xml new file mode 100644 index 000000000..becd41739 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Unit Testing Example + diff --git a/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/themes.xml b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/themes.xml new file mode 100644 index 000000000..f662a6a39 --- /dev/null +++ b/examples/latest/navigate/android/Kotlin/UnitTestingKotlin/app/src/main/res/values/themes.xml @@ -0,0 +1,5 @@ + + + +