LogoLogo
CMSGitHubSupportBook a demo
  • Documentation
  • Academy
  • Help Center
  • Welcome
  • SDKS & Frameworks
    • Web
      • Getting Started
        • Prerequisites
          • MapsIndoors
          • Map Engine Provider
            • Option 1: Get your Mapbox Access Token
            • Option 2: Get your Google Maps API Keys​
          • Map Engine Setup
        • Getting Started: MapsIndoors
      • Map Visualization
        • Highlight, Hover and Select
        • Remove Labels from Buildings and Venues
        • Change Building Outline
        • Managing Collisions Based on Zoom Level
        • 3D Maps
          • Managing your 3D Maps
        • Base Map Styling - Google Maps
        • Managing feature visibility for Mapbox
      • Wayfinding
        • Directions
        • Directions Service
          • Tailoring the directions to your specific needs
        • Directions Renderer
          • Customizing the Route Animation
        • Multi-stop navigation
          • Custom Icons
        • User's Location as Point of Origin
      • Search
        • Search Operations
        • Searching
        • Using External ID, Geospatial Joins
        • Utilizing MapsIndoors Web Components and Other Searches
      • Map Management
      • Data Visualization
        • Display Heatmap Overlay
      • Other guides
        • Authentication
          • Single Sign-On
            • SSO Configuration
            • SSO Authorisation
          • 2-Factor Authentication
          • Password Reset
        • Application User Roles
        • Custom Properties
        • Display Language
        • Language
        • User Positioning
          • Show User's Location aka. Blue Dot
          • Using Cisco DNA Spaces
        • Working with Events
        • Turn Off Collisions Based on Zoom Level
        • Remove Labels from Buildings and Venues for Web
        • Synchronizing data for a subset of venues
        • Custom Floor Selector
      • Display Rules in Practice
      • Offline Data
      • Managing map visibility
    • Android
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
        • Enable Live Data
        • Integrating MapsIndoors into your own App
        • Migrating from V3 to V4
          • Migrating to Mapbox V11
      • Directions
        • Directions Service
        • Directions Renderer
          • User's Location as Point of Origin
        • Wayfinding Instructions
          • See Route Element Details
        • Using multi-stop navigation
      • Searching
        • Searching on a Map
        • Creating a Search Experience
      • Switching Solutions
      • Caching & Offline Data
      • Display Language
      • Displaying Objects
        • Application User Roles
        • Getting a Polygon from a Location
        • Location Clustering
        • Location Data Sources
        • Location Details
        • Turn Off Collisions Based on Zoom Level
        • Enabling and Disabling features on the map
      • Change Building Outline Color
      • Event Logging
      • Configuring a menu with AppConfig
      • Display Heatmap Overlay
      • Custom Properties
      • Custom Floor Selector
      • External IDs
      • User Positioning
        • Show User's Location aka. Blue Dot
        • Using Cisco DNA Spaces
        • Using Google Fused Location Provider
        • Using Indoor Atlas
        • Using CrowdConnected
      • Authentication
        • Single Sign-On
          • SSO Configuration
          • SSO Authorisation
        • 2-Factor Authentication
        • Password Reset
      • Display Rules in Practice
        • Label styling through Display Rules
      • Highlight and Select
    • iOS
      • Getting Started
        • Prerequisites
        • Set Up Your Environment
        • Display a Map
        • Search
        • Getting Directions
        • Migrating from v3 to v4
      • Directions
        • Directions Renderer
          • User's Location as Point of Origin
        • Wayfinding Instructions
          • See Route Element Details
        • Directions Service
        • Using multi-stop navigation
      • Searching
        • Searching on a Map
        • Creating a Search Experience
      • Caching & Offline Data
      • Displaying Objects
        • Application User Roles
        • Getting a Polygon from a Location
        • Location Details
        • Turn Off Collisions Based on Zoom Level
        • Enabling and Disabling features on the map
      • Custom Floor Selector
      • Change Building Outline Color
      • Custom Map Padding
      • Custom Properties
      • Display Rules in Practice
        • Label styling through Display Rules
      • Switching Solutions
      • Show User's Location aka. Blue Dot
        • Using Indoor Atlas
        • Using Cisco DNA Spaces
        • Using CrowdConnected
      • Highlight and Select
      • Display Language
    • React Native
      • Getting Started
        • Prerequisites
        • Project Setup
        • Displaying a Map
        • Creating a Search Experience
        • Getting Directions
        • Enabling Live Data
      • Showing Blue Dot
    • Flutter
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
      • Migration Guide
    • Integration API
      • Integration API Access
        • Access with Swagger
        • Access with Postman
        • Access with Python
        • Client credentials flow
      • Data Description
      • Reverse Geocoding
      • Route Access
      • OpenAPI Specification
    • Built-In Map Edits
      • Getting started
      • Authentication
      • Release notes
      • Reference docs
  • Products
    • Product Overview
    • CMS
      • Interface Overview
      • Display Rules
      • Location Types
      • Categories
      • Media Library
        • 2D Models and Icons
        • 3D Models
      • Editing Data
      • Solution Settings
      • Settings
      • Data Concepts
      • User Roles
      • Route Network
        • Barrier Route Element
        • Door Route Element
      • Additional Location Details
    • Map Template
      • Getting Started
        • Web Component
        • React Component
      • Configuration
        • Query Parameters
        • Categories
      • Customization
      • Deploying Map Template to a cloud storage provider
      • 2D/3D Visibility Switch
      • External customization of the Map Template
      • Location Details configuration
      • Kiosk
        • QR code configuration
    • Web App
  • Other
    • Map Design
      • Map Design System
      • Using a Custom Mapbox MapStyle
      • 2D Models
    • Changelog
      • Web SDK
        • V4
        • V3
      • Android SDK
        • V4
        • V3
      • iOS SDK
        • V4
        • V3
      • React Native SDK
      • Flutter SDK
      • MI Components
      • Map Template
    • Glossary
  • Legacy Docs
    • Android SDK V3
      • Getting Started
        • Prerequisites
        • Create a New Project
        • Show a Map
        • Create a Search Experience
        • Getting Directions
        • Enable Live Data
        • Integrating MapsIndoors into your own App
    • iOS SDK V3
      • Getting Started
        • Prerequisites
        • Set Up Your Environment
        • Display a Map
        • Search
        • Directions
        • Live Data
        • Integrating MapsIndoors into your own App
      • Inspect Route Element for iOS v3
      • Using Cisco DNA Spaces
      • Using Indoor Atlas
      • Switching Solutions
      • Show User's Location aka. Blue Dot
      • Application User Roles
      • Getting a Polygon from a Location
      • Location Details
  • MapsIndoors SDK Firewall
  • Google Analytics & Logging
  • Reference Docs
    • Web SDK
    • Android SDK
    • iOS SDK
    • React Native SDK
    • Flutter SDK
Powered by GitBook
On this page
  • Download maven package
  • Get Android permissions
  • Callback
  • Set up MPCrowdConnectedManager
  • Show it on the map
  • Lifecycle

Was this helpful?

Export as PDF
  1. SDKS & Frameworks
  2. Android
  3. User Positioning

Using CrowdConnected

To get started with CrowdConnected positioning, you can either create your own implementation by using the MPPositionProvider interface from the MapsIndoors SDK to visualize position updates from CrowdConnected or you can use the MapsIndoors CrowdConnected Positioning Provider, which handles this work for you, requiring minimal setup. This guide shows how to make use of it.

This guide assumes you already have an app with MapsIndoors.

Download maven package

First, add the CrowdConnected maven url to your dependency resolution:

settings.gradle.kts
dependencyResolutionManagement {
    repositories {
        google()
        mavenCentral()
        gradlePluginPortal()
        maven { url = uri("https://maven.mapsindoors.com/") }
        maven { url = uri("https://maven2.crowdconnected.net/") }
    }
}

Then download the Maven package and the CrowdConnected IPS:

build.gradle.kts
dependencies {
  implementation("com.mapspeople.mapsindoors:mapsindoors-crowdconnected-positioning-provider:1.0.0")
  implementation("net.crowdconnected.android.core:android-core:2.0.2")
  implementation("net.crowdconnected.android.ips:android-ips:2.0.2")
}

Get Android permissions

Before positioning can be enabled, you must ask the user for permissions. The required permissions are: ACCESS_FINE_LOCATION, BLUETOOTH_SCAN, and BLUETOOTH_CONNECT. Apps below API level 31 should not request BLUETOOTH_SCAN and BLUETOOTH_CONNECT as these were added in 31.

You can decide where to request these permissions, it should be naturally integrated into the flow of opening the map or when the user interacts with the app to enable positioning themselves.

To request the permissions, it is easiest to use ActivityCompat. In this example, we request the permissions in our MainActivity's onCreate method:

MainActivity.kt
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.BLUETOOTH_CONNECT
import android.Manifest.permission.BLUETOOTH_SCAN
import android.os.Build
import android.os.Bundle

class MainActivity : FragmentActivity() {
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
      ActivityCompat.requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION, BLUETOOTH_SCAN, BLUETOOTH_CONNECT ), 0)
    } else {
      ActivityCompat.requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION), 0)
    }
  }
}

Callback

If you want to await the user granting permissions, you must implement the OnRequestPermissionsResultCallback interface, as shown below:

MainActivity.kt
import androidx.core.app.ActivityCompat
import androidx.fragment.app.FragmentActivity
import android.content.pm.PackageManager.PERMISSION_GRANTED
import android.Manifest.permission.ACCESS_FINE_LOCATION
import android.Manifest.permission.BLUETOOTH_CONNECT
import android.Manifest.permission.BLUETOOTH_SCAN
import android.os.Build
import android.os.Bundle

class MainActivity : FragmentActivity(), ActivityCompat.OnRequestPermissionsResultCallback {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
      ActivityCompat.requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION, BLUETOOTH_SCAN, BLUETOOTH_CONNECT ), 0)
    } else {
      ActivityCompat.requestPermissions(this, arrayOf(ACCESS_FINE_LOCATION), 0)
    }
  }

  override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String?>, grantResults: IntArray) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults)

    if (grantResults.all { it == PERMISSION_GRANTED }) {
        // startPositioning()
    }
  }
}

Set up MPCrowdConnectedManager

The positioning manager should only be initialized when positioning is required. It depends on the necessary permissions (mentioned above) and MapsIndoors being initialized.

MainActivity.kt
import android.util.Log
import android.widget.Toast
import androidx.fragment.app.FragmentActivity
import com.mapsindoors.positioning.crowdconnected.MPCrowdConnectedManager
import com.mapsindoors.positioning.crowdconnected.MPCrowdConnectedConfig
import net.crowdconnected.android.core.StatusCallback

class MainActivity : FragmentActivity() {
  private var positionManager: MPCrowdConnectedManager? = null

  fun startPositioning() {
    positionManager = MPCrowdConnectedManager(
      getApplication(),
      MPCrowdConnectedConfig("your_app_key", "your_token", "your_secret"), // you should not input your secrets directly, fetch them from somewhere secure
      object : StatusCallback {
        override fun onStartUpSuccess() {
          Log.i("IPS", "CrowdConnected started successfully")
          runOnUiThread {
            Toast.makeText(getApplicationContext(), "CrowdConnected started successfully", Toast.LENGTH_LONG).show()
          }
        }

        override fun onRuntimeError(error: String?) {
          Log.i("IPS", "CrowdConnected runtime error: $error")
          runOnUiThread {
            Toast.makeText(getApplicationContext(), "CrowdConnected runtime error: $error", Toast.LENGTH_LONG).show()
          }
        }

        override fun onStartUpFailure(failure: String?) {
          Log.i("IPS", "CrowdConnected startup failure: $failure")
          runOnUiThread {
            Toast.makeText(getApplicationContext(), "CrowdConnected startup failure: $failure", Toast.LENGTH_LONG).show()
          }
        }
      }
    )
    MapsIndoors.setPositionProvider(positionManager!!)
  }
}

With this, positioning is up and running, and can be tested out in your app. The only thing we are missing is lifecycle handling.

Show it on the map

The last step to get the positioning shown on the map is to enable it in MapControl. This is typically done when creating the MapControl, but it can be turned on at any time. In the following example we turn on positioning when creating our MapControl, by adding it to the MPMapConfig. The example is based on using Mapbox, but this can be done for any supported map.

MainActivity.kt
import android.os.Bundle
import androidx.fragment.app.FragmentActivity
import com.mapsindoors.core.MapControl
import com.mapsindoors.mapbox.MPMapConfig
import com.mapsindoors.core.errors.MIError
import com.mapbox.maps.MapView
import com.mapbox.maps.MapboxMap

class MainActivity : FragmentActivity() {
  private var mMapControl: MapControl? = null
  private var mMap: MapBoxMap? = null
  private var mMapView: MapBoxMapView? = null

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
    // initialize Map
    mMapView = requireActivity().findViewById(R.id.mapView)
    mMap = mMapView.mapboxMap
    // start building MapControl
    initMapControl()
  }

  private fun initMapControl() {
    val mapConfig = MPMapConfig.Builder(this, mMap ?: return, mMapView ?: return, "your_mapbox_api_key", true)
      .setShowUserPosition(true) // setShowUserPosition to true to show the latest position given to MapsIndoors on the map
      .build()
    MapControl.create(mapConfig) { mapControl: MapControl?, miError: MIError? ->
      if (miError == null) {
        mMapControl = mapControl
      }
    }
  }
}

Positioning can also be enabled or disabled on MapControl at any time by calling showUserPosition on MapControl:

MainActivity.kt
import androidx.fragment.app.FragmentActivity
import com.mapsindoors.core.MapControl

class MainActivity : FragmentActivity() {
  private var mMapControl: MapControl? = null

  private fun showPosition(show: Boolean) {
    // positioning can be enabled at any time mapcontrol is accessible
    mMapControl?.showUserPosition(show)
  }
}

Lifecycle

It is important to ensure that your positioning implementation respects the Android Lifecycle. The position manager should be properly started, paused, and resumed according to the activity lifecycle to prevent memory leaks or unexpected behavior.

How you integrate lifecycle management may vary based on your app’s architecture (e.g., using LifecycleObservers, ViewModel, or manual lifecycle management). Make sure to consider your app’s structure and user experience when deciding how to manage the lifecycle of your position manager.

Example

Here's a basic example of how you can manage lifecycle manually:

MainActivity.kt
import androidx.fragment.app.FragmentActivity
import com.mapsindoors.positioning.crowdconnected.MPCrowdConnectedManager

class MainActivity : FragmentActivity() {
  private var positionManager: MPCrowdConnectedManager? = null

  override fun onStop() {
    super.onStop()
    positionManager?.stop()
  }

  override fun onResume() {
    super.onResume()
    positionManager?.restart()
  }
}

Last updated 6 days ago

Was this helpful?

In the above example we initialized the positionManager using a set of CrowdConnected secrets that we got from their CMS, you can follow the CrowdConnected guide on how to generate them . It is optional to add a StatusCallback, in this example we added it for debug purposes, it will print to the log and create a Toast informing the status of initialization.

here