Skip to main content
GuidesAPI ReferenceExamples

Download A Map

|

This example demonstrates how to list the road maps available on the server for download, how to download a map while indicating the download progress, and how to display the download’s finished status.

Downloadable Maps list

Download Progress Implementation

This is the progressListener used to monitor the progress of obtaining the list of maps available for download from the online content store server.

The callback onStarted is called when the map list download starts, and onCompleted is called when the map list download is complete.

Once the map list is downloaded, the array of roadmaps is obtained from the downloaded local copy of the map list: val models = contentStore.getStoreContentList(EContentType.RoadMap)?.first

If the array is not empty, the first item (at index 0) is obtained: val mapItem = models[0]

The progress listener is created using: val progressListener = ProgressListener.create.

Then the download is started, and the progress listener just defined is used to monitor the progress of downloading the map at index 0 in the list of maps.

The downloaded map is stored on the device in a directory such as this: /sdcard/Android/data/com.magiclane.examplename/files/Data/Maps/.

The progress listener also calls displayList(models) which uses a CustomAdapter to display a scrollable list of the maps available on the server. The list displayed is the local copy that was downloaded above.

MainActivity.kt
private val progressListener = ProgressListener.create(
onStarted = {
progressBar.visibility = View.VISIBLE
showStatusMessage("Started content store service.")
},
onCompleted = { errorCode, _ ->
progressBar.visibility = View.GONE
showStatusMessage("Content store service completed with error code: $errorCode")

when (errorCode)
{
GemError.NoError ->
{
SdkCall.execute {
// No error encountered, we can handle the results.
val models = contentStore.getStoreContentList(EContentType.RoadMap)?.first

if (!models.isNullOrEmpty())
{
// The map items list is not empty or null.
val mapItem = models[0]
val itemName = mapItem.name

// Define a listener to the progress of the map download action.
val downloadProgressListener = ProgressListener.create(onStarted = {
showStatusMessage("Started downloading $itemName.")
},
onProgress = {
listView.adapter?.notifyItemChanged(0)
},
onCompleted = { errorCode, _ ->
listView.adapter?.notifyItemChanged(0)
if (errorCode == GemError.NoError)
showStatusMessage("$itemName was downloaded.")
else
showDialog(
"Download item error: ${
GemError.getMessage(
errorCode
)
}"
)
EspressoIdlingResource.decrement()
})

// Start downloading the first map item.
SdkCall.execute {
mapItem.asyncDownload(
downloadProgressListener,
GemSdk.EDataSavePolicy.UseDefault,
true
)
}
}

displayList(models)
}
}

GemError.Cancel ->
{
// The action was cancelled.
EspressoIdlingResource.decrement()
}

else ->
{
// There was a problem at retrieving the content store items.
showDialog("Content store service error: ${GemError.getMessage(errorCode)}")
EspressoIdlingResource.decrement()
}
}
}
)

UI and Map Integration

MainActivity overrides onCreate() which checks that internet access is available, and explicitly initializes the SDK, which is required for enabling use of the SDK without a map: GemSdk.initSdkWithDefaults(this)

When the internet connection is detected, or when the SDK reports that map data is ready, the loadMaps() function is called to request the list of maps from the content store server contentStore.asyncGetStoreContentList(EContentType.RoadMap, progressListener)

The list of maps is requested, and the progressListener shown above is passed in, to get notified when the list of maps has finished downloading. At that point, as we have already seen above, the progress listener automatically selects the first map (unless the list is empty) and downloads it automatically.

In a real world use case, the user would select which map to download.

MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)

EspressoIdlingResource.increment()

progressBar = findViewById(R.id.progress_bar)
statusText = findViewById(R.id.status_text)

listView = findViewById<RecyclerView?>(R.id.list_view).apply {
layoutManager = LinearLayoutManager(this@MainActivity)

val separator = DividerItemDecoration(
applicationContext,
(layoutManager as LinearLayoutManager).orientation
)
addItemDecoration(separator)

val lateralPadding = resources.getDimension(R.dimen.bigPadding).toInt()
setPadding(lateralPadding, 0, lateralPadding, 0)

itemAnimator = null
}

val loadMaps = {
val loadMapsCatalog = {
SdkCall.execute {
// Call to the content store to asynchronously retrieve the list of maps.
contentStore.asyncGetStoreContentList(EContentType.RoadMap, progressListener)
}
}

val token = GemSdk.getTokenFromManifest(this)

if (!token.isNullOrEmpty() && (token != kDefaultToken))
{
loadMapsCatalog()
} else // if token is not present try to avoid content server requests limitation by delaying the maps catalog request
{
Handler(Looper.getMainLooper()).postDelayed({
loadMapsCatalog()
}, 3000)
}
}

SdkSettings.onMapDataReady = { mapReady ->
if (mapReady)
{
loadMaps()
}
}

...
}

Also, the method showStatusMessage() will show the progress status message in a TextView below the list.