Skip to content

Custom Places

It is possible to add custom Points of Interest (POIs). We call them Places. Places can be used for example to show the user's favorite places or places that are not available in the Sygic database. To be able to show custom places on the map, it is necessary to inject a skin definition for them.

In the next chapters, we will see how to import custom places from a JSON file, how to install them from the server or how to use them without downloading them.

Enabling Custom Places and modes

To enable custom places at startup, it is necessary to set Custom Places as the startupPoiProvider in the JSON Config:

config.mapReaderSettings()
    .startupPoiProvider(MapReaderSettings.StartupPoiProvider.CUSTOM_PLACES)

By setting the Custom Places POI provider at startup, both map places and custom places will be visible in the map.

Setting the mode

There are two modes in which custom places can be used:

  • Offline
  • Online

Online mode means that the places are downloaded from the server while browsing the map or along the calculated route. This mode is suitable for places that are frequently updated. This is automatically managed by the SDK.

Offline mode means that the places are downloaded using the methods described below and stored in the app's database. They are not continually downloaded from the server.

Important

Before using the online or offline mode, it is necessary to set it like this: CustomPlacesManagerProvider.getInstance().get().setMode(CustomPlacesManager.Mode.OFFLINE)

Tip

Depending on your preferences, it might be a good idea to download the offline places upon downloading a map as the places are tied to iso codes (and you get them via MapInstaller). Then, you can update them according to your needs.

Injecting a skin for Custom Places

To be able to see custom places on the map, you need to inject a skin definition for them. The skin definition is a JSON file that contains the style of the custom places, basically for groups and categories. Below is a sample of the skin definition:

Important

If not defined in the skin_default.xml file, it will be necessary to inject the skin at each mapView creation.

{
  "skin": {
    "poi_categories": {
      "custom": {
        "groups": {
          "CustomPOIGroup": {
            "enabled": true,
            "priority": 0,
            "showWithoutText": true,
            "zoomLevel": 12,
            "importance": "Major"
          }
        },
        "categories": {
          "custom_category": {
            "groupId": "CustomPOIGroup",
            "icon": "0xe30b",
            "color": "0x651FFFFF"
          },
          "another_custom_category": {
            "groupId": "CustomPOIGroup",
            "icon": "0xE327",
            "color": "0xFFAA00FF",
            "priority": 0,
            "zoomLevel": 14,
            "importance": "Major"
          }
        }
      }
    }
  }
}

Then, you can inject it using this code in kotlin:

// just a function to get json from assets, you may use your own
fun getJsonDataFromAsset(context: Context, fileName: String): String? {
    val jsonString: String
    try {
        jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
    } catch (ioException: IOException) {
        ioException.printStackTrace()
        return null
    }
    return jsonString
}

val skin = getJsonDataFromAsset(
    applicationContext,
    "skin_poi_custom.json"
)

mapView.injectSkinDefinition(skin!!) { injectSkinResult ->
    Toast.makeText(
        applicationContext,
        "Skin injected: $injectSkinResult",
        Toast.LENGTH_SHORT
    ).show()
}

Importing Custom Places from a JSON file

After having a JSON file with custom places ready, it is possible to import it using the following code:

// just a function to get json from assets, you may use your own
fun getJsonDataFromAsset(context: Context, fileName: String): String? {
    val jsonString: String
    try {
        jsonString = context.assets.open(fileName).bufferedReader().use { it.readText() }
    } catch (ioException: IOException) {
        ioException.printStackTrace()
        return null
    }
    return jsonString
}

val customPlacesJsonFile = getJsonDataFromAsset(applicationContext, "svk_svk.json")
CustomPlacesManagerProvider.getInstance().get().installOfflinePlacesFromJson (
  customPlacesJsonFile!!,
  object : CustomPlacesManager.InstallResultListener {
      override fun onResult(
          result: CustomPlacesManager.InstallResult,
          message: String
      ) {
          Toast.makeText(
              applicationContext,
              "Custom Places sideloaded $result",
              Toast.LENGTH_SHORT
          ).show()
      }
  })

If you do not define a "dataset", the places wil be imported into the default dataset. The ID of the default dataset is "bf19e514-487b-43c4-b0df-9073b2397dd1".

Deleting Custom Places using a JSON file

It is also possible to delete custom places using a JSON file. For example, if you want to remove the custom place from custom places article, your JSON file would look like this:

{
  "to_remove": [
    "3047426d-849b-de0b-e82a-24c699c0b9a4"
  ]
}

Then, just call the same method as above to install the places. The place will be removed from the database. Removing is specified by the "to_remove" key in the JSON file. You can add/update and remove places in the same JSON file.

Installing custom places from server

After having the custom places uploaded to the server, it is possible to install them in your app. For further information about uploading the places to the server, please see the Custom Places API and the the Custom Places article

Installing

To install custom places from the server, you need to call the following method:

CustomPlacesManagerProvider.getInstance().get().installOfflineDatasets(
    listOf("dataset1", "dataset2"), 
    "sk", 
    object: CustomPlacesManager.InstallResultListener {
        override fun onResult(
            result: CustomPlacesManager.InstallResult,
            message: String
        ) {
            Toast.makeText(
                applicationContext,
                "Datasets downloaded: $result",
                Toast.LENGTH_SHORT
            ).show()
        }
    }, object : CustomPlacesManager.InstallProgressListener {
        override fun onProgress(progress: CustomPlacesManager.InstallProgress) {
            Toast.makeText(
                applicationContext,
                "Progress: ${progress.loadedRecords}/${progress.totalRecords}",
                Toast.LENGTH_SHORT
            ).show()
        }
    }
)

Uninstalling

To uninstall custom places that you downloaded from the server, you can either use the uninstallOfflineDatasets method:

CustomPlacesManagerProvider.getInstance().get().uninstallOfflineDatasets(
    listOf("dataset1", "dataset2"), "sk", object: CustomPlacesManager.InstallResultListener {
        override fun onResult(
            result: CustomPlacesManager.InstallResult,
            message: String
        ) {
            Toast.makeText(
                applicationContext,
                "Datasets uninstalled: $result",
                Toast.LENGTH_SHORT
            ).show()
        }
    }
)

Note

You can leave the country code empty to uninstall whole datasets.

Or you can use the uninstallOfflineDatasetsFromCountry method which uninstalls all datasets from the specified country:

CustomPlacesManagerProvider.getInstance().get().uninstallOfflineDatasetsFromCountry(
    "sk", object: CustomPlacesManager.InstallResultListener {
        override fun onResult(
            result: CustomPlacesManager.InstallResult,
            message: String
        ) {
            Toast.makeText(
                applicationContext,
                "Datasets uninstalled: $result",
                Toast.LENGTH_SHORT
            ).show()
        }
    }
)

Updating

To update custom places from the server, you need to call the following method:

Note

Please note that this method updates all of the installed places, not just the ones from the specified country.

CustomPlacesManagerProvider.getInstance().get().updateInstalledDatasets(
  object: CustomPlacesManager.InstallResultListener {
    override fun onResult(
        result: CustomPlacesManager.InstallResult,
        message: String
    ) {
        Toast.makeText(
            applicationContext,
            "Datasets updated: $result",
            Toast.LENGTH_SHORT
        ).show()
    }
  },
  object : CustomPlacesManager.InstallProgressListener {
    override fun onProgress(progress: CustomPlacesManager.InstallProgress) {
        Toast.makeText(
            applicationContext,
            "Progress: ${progress.loadedRecords}/${progress.totalRecords}",
            Toast.LENGTH_SHORT
        ).show()
    }
})

You can read more about the Custom Places Search in the Custom Places Search article.