{"project":"54e5ed7fd3ab670d00f3afec","version":"57e3bcc1378b341700c8208f","category":"57e3bcc2378b341700c82090","_id":"5800aab6922f8f3700a9c178","user":"54e5a4a0d3ab670d00f3af54","updates":[],"createdAt":"2016-10-14T09:51:50.096Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":999,"body":"* Fix a problem where the orientation is not calculated for some iPhones\n* Improve stability of recording uploads\n* Fix layout issue in Account Manager on Application overview\n* The SDK uses internal storage only\n* Improve sensor usage on phone for better accuracy\n* Fix problem where overlays are blurry\n* Trial apps will expire after 30 days\n* Make iOS SDK compatible with Cocoapods v1.0.0\n* Add a setting to the SDK to disable all internet communication\n* Routing can now wait until all waypoints are loaded","excerpt":"","slug":"430","type":"basic","title":"4.3.0","__v":0,"childrenPages":[]}

4.3.0


* Fix a problem where the orientation is not calculated for some iPhones * Improve stability of recording uploads * Fix layout issue in Account Manager on Application overview * The SDK uses internal storage only * Improve sensor usage on phone for better accuracy * Fix problem where overlays are blurry * Trial apps will expire after 30 days * Make iOS SDK compatible with Cocoapods v1.0.0 * Add a setting to the SDK to disable all internet communication * Routing can now wait until all waypoints are loaded
* Fix a problem where the orientation is not calculated for some iPhones * Improve stability of recording uploads * Fix layout issue in Account Manager on Application overview * The SDK uses internal storage only * Improve sensor usage on phone for better accuracy * Fix problem where overlays are blurry * Trial apps will expire after 30 days * Make iOS SDK compatible with Cocoapods v1.0.0 * Add a setting to the SDK to disable all internet communication * Routing can now wait until all waypoints are loaded
{"__v":0,"_id":"57e3bcc2378b341700c820a1","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Integrating indoo.rs localization is now easier than ever. It’s just a matter of a few lines of code to integrate our SDK into your project.\n\n**NOTE:** The SDK requires **API level 18** to function correctly - we use the BLE support that Google introduced in Android version 4.3. Behavior when using lower API levels and/or Android versions is undefined.","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-17T08:11:15.974Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":0,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"getting-started-with-indoors-android-guide","sync_unique":"","title":"Getting Started with the indoo.rs Android-SDK","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Getting Started with the indoo.rs Android-SDK


Integrating indoo.rs localization is now easier than ever. It’s just a matter of a few lines of code to integrate our SDK into your project. **NOTE:** The SDK requires **API level 18** to function correctly - we use the BLE support that Google introduced in Android version 4.3. Behavior when using lower API levels and/or Android versions is undefined.
Integrating indoo.rs localization is now easier than ever. It’s just a matter of a few lines of code to integrate our SDK into your project. **NOTE:** The SDK requires **API level 18** to function correctly - we use the BLE support that Google introduced in Android version 4.3. Behavior when using lower API levels and/or Android versions is undefined.
{"__v":0,"_id":"57e3bcc2378b341700c820a2","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"To get your first indoo.rs-powered app up and running as fast as possible you can download a sample project from [here](https://my.indoo.rs). This project includes everything you need to load and display a map, as well as locate yourself (you have to create a map first, of course).","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:24:57.419Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":1,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"sample-project","sync_unique":"","title":"Sample Project","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Sample Project


To get your first indoo.rs-powered app up and running as fast as possible you can download a sample project from [here](https://my.indoo.rs). This project includes everything you need to load and display a map, as well as locate yourself (you have to create a map first, of course).
To get your first indoo.rs-powered app up and running as fast as possible you can download a sample project from [here](https://my.indoo.rs). This project includes everything you need to load and display a map, as well as locate yourself (you have to create a map first, of course).
{"__v":0,"_id":"57e3bcc2378b341700c820a3","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Starting version 4.2.0 indoors SDK is supplied as aar not as jar anymore\"\n}\n[/block]\n## Integrating SDK in gradle\nOn Android, the SDK consists of an aar file.\n\nMake sure you add it to *app/libs* folder of the module, otherwise indoors sdk won't work properly.\n\nPlease add the following to your 'project build.gradle' (the outer most 'build.gradle' file in you project) file. **Be careful there are multiple 'gradle' files with Android Studio** :\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"allprojects {\\n  ...\\n    repositories {\\n        jcenter()\\n        flatDir {\\n            dirs 'libs'\\n             \\n        }\\n      ...\\n    }\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIn your module 'build.gradle' file you need to add the following dependencies.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"android {\\npackagingOptions {\\n        exclude 'META-INF/ASL2.0'// this is needed because of jackson mapper please add this to avoid dupilicate META-INF/ASL2.0 with gradle build\\n    }\\n}\\ndependencies{    \\n    compile(name: 'indoors-library-surface-versionnumber*', ext: 'aar')\\n    compile 'org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final'\\n    compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.0'\\n    compile 'com.google.guava:guava:14.0.1'\\n    compile 'com.google.protobuf:protobuf-java:2.4.1'\\n    compile 'org.slf4j:slf4j-api:1.7.0'\\n}\\ni.e versionnumber = 4.2.0\",\n      \"language\": \"groovy\"\n    }\n  ]\n}\n[/block]\nAlso make sure that the targetSdkVersion is set to 22 or below in your app/build.gradle file, if you want to set it to over **23 **please read about runtime permissions https://developer.android.com/training/permissions/requesting.html  and read about how to handle indoors SDK runtime permissions [Indoors SDK Manifest Permissions](doc:indoors-sdk-manifest-permissions) \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"android {\\n    ...// Other entries\\n    defaultConfig {\\n        ...// Other entries\\n        targetSdkVersion 22\\n    }\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n## Integrating in Manifest :  \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"    <uses-permission android:name=\\\"android.permission.ACCESS_COARSE_LOCATION\\\" />\\n    <uses-permission android:name=\\\"android.permission.ACCESS_NETWORK_STATE\\\" />\\n    <uses-permission android:name=\\\"android.permission.ACCESS_WIFI_STATE\\\" />\\n    <uses-permission android:name=\\\"android.permission.CHANGE_WIFI_STATE\\\" />\\n    <uses-permission android:name=\\\"android.permission.BLUETOOTH\\\" />\\n    <uses-permission android:name=\\\"android.permission.BLUETOOTH_ADMIN\\\" /> \\n    <uses-permission-sdk-23 android:name=\\\"android.permission.ACCESS_COARSE_LOCATION\\\"/>\\n\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n## Integrating SDK in code\n\nOne more thing you have to include yourself into your project is the Android Support Library. All other dependencies are baked right into our SDK. This shouldn't be a problem for most users of our SDK, but if you experience any problems due to duplicate class-files, please talk to us.\n\nLoading a map, displaying it and calculating a position is as easy as that now:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"package com.mycompany.myfirstindoorsapp;\\n \\nimport android.os.Bundle;\\nimport android.support.v4.app.FragmentActivity;\\nimport android.support.v4.app.FragmentTransaction;\\n \\nimport com.customlbs.surface.library.IndoorsSurfaceFactory;\\nimport com.customlbs.surface.library.IndoorsSurfaceFragment;\\n \\npublic class MainActivity extends FragmentActivity {\\n  @Override\\n  protected void onCreate(Bundle savedInstanceState) {\\n    super.onCreate(savedInstanceState);\\n\\n    IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\\n    IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\\n\\n    indoorsBuilder.setContext(this);\\n\\n    // TODO: replace this with your API-key\\n    indoorsBuilder.setApiKey(\\\"YOUR-API-KEY\\\");\\n\\n    // TODO: replace 12345 with the id of the building you uploaded to\\n    // our cloud using the MMT\\n    indoorsBuilder.setBuildingId((long) 12345);\\n\\n    surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\\n\\n    IndoorsSurfaceFragment indoorsFragment = surfaceBuilder.build();\\n\\n    FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\\n    transaction.add(android.R.id.content, indoorsFragment, \\\"indoors\\\");\\n    transaction.commit();\\n  }\\n} \",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nFor most apps, this is already enough. If you want to react to position changes, you might want to do something like this: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import com.customlbs.coordinates.GeoCoordinate;\\nimport com.customlbs.library.IndoorsException;\\nimport com.customlbs.library.IndoorsLocationListener;\\nimport com.customlbs.library.model.Building;\\nimport com.customlbs.library.model.Zone;\\nimport com.customlbs.shared.Coordinate;\\n\\npublic class MainActivity extends FragmentActivity implements IndoorsLocationListener {\\n\\n    @Override\\n    protected void onCreate(Bundle savedInstanceState) {\\n      // ...\\n\\n      IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\\n      IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\\n\\n      // ...\\n\\n      indoorsBuilder.setUserInteractionListener(this);\\n\\n      surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\\n\\n      indoorsFragment = surfaceBuilder.build();\\n\\n      // ...\\n    }\\n\\n    public void positionUpdated(Coordinate userPosition, int accuracy) {\\n      // new position calculated\\n    }\\n\\n    public void buildingLoaded(Building building) {\\n      // indoo.rs SDK successfully loaded the building you requested and\\n      // calculates a position now\\n    }\\n\\n    public void onError(IndoorsException indoorsException) {\\n    }\\n\\n    public void changedFloor(int floorLevel, String name) {\\n      // user changed the floor\\n    }\\n\\n    public void leftBuilding(Building building) {\\n      // user left the building\\n    }\\n\\n    public void loadingBuilding(LoadingBuildingStatus status) {\\n      // indoo.rs is still downloading or parsing the requested building\\n      int progress = status.getProgress();\\n    }\\n\\n    public void orientationUpdated(float orientation) {\\n      // user changed the direction he's heading to\\n    }\\n    \\n    public void enteredZones(List<Zone> zones) {\\n      // user entered one or more zones\\n    }\\n \\n\\t  public void buildingLoadingCanceled() {\\n\\n\\t }\\n\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"loadingBuilding\",\n  \"body\": \"Starting from v3.2 the method loadingBuilding has LoadingBuildingStatus as parameter. Please take care when you implement the IndoorsLocationListener.\\n\\nLoadingBuildingStatus has 'getProgress()' method which returns the progress.\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"buildingLoadingCanceled\",\n  \"body\": \"Starting from v3.8 IndoorsLocationListener should override the method \\n***buildingLoadingCanceled***, which is used to cancel building download.\"\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:24:25.470Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":2,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"integrating-indoors-into-an-existing-app","sync_unique":"","title":"Integrating indoo.rs into an existing App","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Integrating indoo.rs into an existing App


[block:callout] { "type": "danger", "title": "Starting version 4.2.0 indoors SDK is supplied as aar not as jar anymore" } [/block] ## Integrating SDK in gradle On Android, the SDK consists of an aar file. Make sure you add it to *app/libs* folder of the module, otherwise indoors sdk won't work properly. Please add the following to your 'project build.gradle' (the outer most 'build.gradle' file in you project) file. **Be careful there are multiple 'gradle' files with Android Studio** : [block:code] { "codes": [ { "code": "allprojects {\n ...\n repositories {\n jcenter()\n flatDir {\n dirs 'libs'\n \n }\n ...\n }\n}", "language": "java" } ] } [/block] In your module 'build.gradle' file you need to add the following dependencies. [block:code] { "codes": [ { "code": "android {\npackagingOptions {\n exclude 'META-INF/ASL2.0'// this is needed because of jackson mapper please add this to avoid dupilicate META-INF/ASL2.0 with gradle build\n }\n}\ndependencies{ \n compile(name: 'indoors-library-surface-versionnumber*', ext: 'aar')\n compile 'org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final'\n compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.0'\n compile 'com.google.guava:guava:14.0.1'\n compile 'com.google.protobuf:protobuf-java:2.4.1'\n compile 'org.slf4j:slf4j-api:1.7.0'\n}\ni.e versionnumber = 4.2.0", "language": "groovy" } ] } [/block] Also make sure that the targetSdkVersion is set to 22 or below in your app/build.gradle file, if you want to set it to over **23 **please read about runtime permissions https://developer.android.com/training/permissions/requesting.html and read about how to handle indoors SDK runtime permissions [Indoors SDK Manifest Permissions](doc:indoors-sdk-manifest-permissions) [block:code] { "codes": [ { "code": "android {\n ...// Other entries\n defaultConfig {\n ...// Other entries\n targetSdkVersion 22\n }\n}", "language": "java" } ] } [/block] ## Integrating in Manifest : [block:code] { "codes": [ { "code": " <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" /> \n <uses-permission-sdk-23 android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n", "language": "xml" } ] } [/block] ## Integrating SDK in code One more thing you have to include yourself into your project is the Android Support Library. All other dependencies are baked right into our SDK. This shouldn't be a problem for most users of our SDK, but if you experience any problems due to duplicate class-files, please talk to us. Loading a map, displaying it and calculating a position is as easy as that now: [block:code] { "codes": [ { "code": "package com.mycompany.myfirstindoorsapp;\n \nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentTransaction;\n \nimport com.customlbs.surface.library.IndoorsSurfaceFactory;\nimport com.customlbs.surface.library.IndoorsSurfaceFragment;\n \npublic class MainActivity extends FragmentActivity {\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\n\n indoorsBuilder.setContext(this);\n\n // TODO: replace this with your API-key\n indoorsBuilder.setApiKey(\"YOUR-API-KEY\");\n\n // TODO: replace 12345 with the id of the building you uploaded to\n // our cloud using the MMT\n indoorsBuilder.setBuildingId((long) 12345);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n IndoorsSurfaceFragment indoorsFragment = surfaceBuilder.build();\n\n FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n transaction.add(android.R.id.content, indoorsFragment, \"indoors\");\n transaction.commit();\n }\n} ", "language": "java" } ] } [/block] For most apps, this is already enough. If you want to react to position changes, you might want to do something like this: [block:code] { "codes": [ { "code": "import com.customlbs.coordinates.GeoCoordinate;\nimport com.customlbs.library.IndoorsException;\nimport com.customlbs.library.IndoorsLocationListener;\nimport com.customlbs.library.model.Building;\nimport com.customlbs.library.model.Zone;\nimport com.customlbs.shared.Coordinate;\n\npublic class MainActivity extends FragmentActivity implements IndoorsLocationListener {\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n // ...\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\n\n // ...\n\n indoorsBuilder.setUserInteractionListener(this);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n indoorsFragment = surfaceBuilder.build();\n\n // ...\n }\n\n public void positionUpdated(Coordinate userPosition, int accuracy) {\n // new position calculated\n }\n\n public void buildingLoaded(Building building) {\n // indoo.rs SDK successfully loaded the building you requested and\n // calculates a position now\n }\n\n public void onError(IndoorsException indoorsException) {\n }\n\n public void changedFloor(int floorLevel, String name) {\n // user changed the floor\n }\n\n public void leftBuilding(Building building) {\n // user left the building\n }\n\n public void loadingBuilding(LoadingBuildingStatus status) {\n // indoo.rs is still downloading or parsing the requested building\n int progress = status.getProgress();\n }\n\n public void orientationUpdated(float orientation) {\n // user changed the direction he's heading to\n }\n \n public void enteredZones(List<Zone> zones) {\n // user entered one or more zones\n }\n \n\t public void buildingLoadingCanceled() {\n\n\t }\n\n}", "language": "java" } ] } [/block] [block:callout] { "type": "danger", "title": "loadingBuilding", "body": "Starting from v3.2 the method loadingBuilding has LoadingBuildingStatus as parameter. Please take care when you implement the IndoorsLocationListener.\n\nLoadingBuildingStatus has 'getProgress()' method which returns the progress." } [/block] [block:callout] { "type": "danger", "title": "buildingLoadingCanceled", "body": "Starting from v3.8 IndoorsLocationListener should override the method \n***buildingLoadingCanceled***, which is used to cancel building download." } [/block]
[block:callout] { "type": "danger", "title": "Starting version 4.2.0 indoors SDK is supplied as aar not as jar anymore" } [/block] ## Integrating SDK in gradle On Android, the SDK consists of an aar file. Make sure you add it to *app/libs* folder of the module, otherwise indoors sdk won't work properly. Please add the following to your 'project build.gradle' (the outer most 'build.gradle' file in you project) file. **Be careful there are multiple 'gradle' files with Android Studio** : [block:code] { "codes": [ { "code": "allprojects {\n ...\n repositories {\n jcenter()\n flatDir {\n dirs 'libs'\n \n }\n ...\n }\n}", "language": "java" } ] } [/block] In your module 'build.gradle' file you need to add the following dependencies. [block:code] { "codes": [ { "code": "android {\npackagingOptions {\n exclude 'META-INF/ASL2.0'// this is needed because of jackson mapper please add this to avoid dupilicate META-INF/ASL2.0 with gradle build\n }\n}\ndependencies{ \n compile(name: 'indoors-library-surface-versionnumber*', ext: 'aar')\n compile 'org.hibernate.javax.persistence:hibernate-jpa-2.0-api:1.0.1.Final'\n compile 'org.codehaus.jackson:jackson-mapper-asl:1.9.0'\n compile 'com.google.guava:guava:14.0.1'\n compile 'com.google.protobuf:protobuf-java:2.4.1'\n compile 'org.slf4j:slf4j-api:1.7.0'\n}\ni.e versionnumber = 4.2.0", "language": "groovy" } ] } [/block] Also make sure that the targetSdkVersion is set to 22 or below in your app/build.gradle file, if you want to set it to over **23 **please read about runtime permissions https://developer.android.com/training/permissions/requesting.html and read about how to handle indoors SDK runtime permissions [Indoors SDK Manifest Permissions](doc:indoors-sdk-manifest-permissions) [block:code] { "codes": [ { "code": "android {\n ...// Other entries\n defaultConfig {\n ...// Other entries\n targetSdkVersion 22\n }\n}", "language": "java" } ] } [/block] ## Integrating in Manifest : [block:code] { "codes": [ { "code": " <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\" />\n <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n <uses-permission android:name=\"android.permission.BLUETOOTH\" />\n <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" /> \n <uses-permission-sdk-23 android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n", "language": "xml" } ] } [/block] ## Integrating SDK in code One more thing you have to include yourself into your project is the Android Support Library. All other dependencies are baked right into our SDK. This shouldn't be a problem for most users of our SDK, but if you experience any problems due to duplicate class-files, please talk to us. Loading a map, displaying it and calculating a position is as easy as that now: [block:code] { "codes": [ { "code": "package com.mycompany.myfirstindoorsapp;\n \nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentTransaction;\n \nimport com.customlbs.surface.library.IndoorsSurfaceFactory;\nimport com.customlbs.surface.library.IndoorsSurfaceFragment;\n \npublic class MainActivity extends FragmentActivity {\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\n\n indoorsBuilder.setContext(this);\n\n // TODO: replace this with your API-key\n indoorsBuilder.setApiKey(\"YOUR-API-KEY\");\n\n // TODO: replace 12345 with the id of the building you uploaded to\n // our cloud using the MMT\n indoorsBuilder.setBuildingId((long) 12345);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n IndoorsSurfaceFragment indoorsFragment = surfaceBuilder.build();\n\n FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n transaction.add(android.R.id.content, indoorsFragment, \"indoors\");\n transaction.commit();\n }\n} ", "language": "java" } ] } [/block] For most apps, this is already enough. If you want to react to position changes, you might want to do something like this: [block:code] { "codes": [ { "code": "import com.customlbs.coordinates.GeoCoordinate;\nimport com.customlbs.library.IndoorsException;\nimport com.customlbs.library.IndoorsLocationListener;\nimport com.customlbs.library.model.Building;\nimport com.customlbs.library.model.Zone;\nimport com.customlbs.shared.Coordinate;\n\npublic class MainActivity extends FragmentActivity implements IndoorsLocationListener {\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n // ...\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\n\n // ...\n\n indoorsBuilder.setUserInteractionListener(this);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n indoorsFragment = surfaceBuilder.build();\n\n // ...\n }\n\n public void positionUpdated(Coordinate userPosition, int accuracy) {\n // new position calculated\n }\n\n public void buildingLoaded(Building building) {\n // indoo.rs SDK successfully loaded the building you requested and\n // calculates a position now\n }\n\n public void onError(IndoorsException indoorsException) {\n }\n\n public void changedFloor(int floorLevel, String name) {\n // user changed the floor\n }\n\n public void leftBuilding(Building building) {\n // user left the building\n }\n\n public void loadingBuilding(LoadingBuildingStatus status) {\n // indoo.rs is still downloading or parsing the requested building\n int progress = status.getProgress();\n }\n\n public void orientationUpdated(float orientation) {\n // user changed the direction he's heading to\n }\n \n public void enteredZones(List<Zone> zones) {\n // user entered one or more zones\n }\n \n\t public void buildingLoadingCanceled() {\n\n\t }\n\n}", "language": "java" } ] } [/block] [block:callout] { "type": "danger", "title": "loadingBuilding", "body": "Starting from v3.2 the method loadingBuilding has LoadingBuildingStatus as parameter. Please take care when you implement the IndoorsLocationListener.\n\nLoadingBuildingStatus has 'getProgress()' method which returns the progress." } [/block] [block:callout] { "type": "danger", "title": "buildingLoadingCanceled", "body": "Starting from v3.8 IndoorsLocationListener should override the method \n***buildingLoadingCanceled***, which is used to cancel building download." } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820a4","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"This is useful if you're working on an app for a remote venue (e.g. a shopping mal, event venue, etc) but still want to have some position displayed on the map:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsBuilder.setEvaluationMode(true);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:32:00.975Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":3,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"evaluation-mode","sync_unique":"","title":"Evaluation Mode","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Evaluation Mode


This is useful if you're working on an app for a remote venue (e.g. a shopping mal, event venue, etc) but still want to have some position displayed on the map: [block:code] { "codes": [ { "code": "indoorsBuilder.setEvaluationMode(true);", "language": "java" } ] } [/block]
This is useful if you're working on an app for a remote venue (e.g. a shopping mal, event venue, etc) but still want to have some position displayed on the map: [block:code] { "codes": [ { "code": "indoorsBuilder.setEvaluationMode(true);", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820a5","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Calculating and displaying a route on the map is a matter of a few lines too:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"import com.customlbs.shared.Coordinate;\\n \\nimport com.customlbs.library.callbacks.RoutingCallback;\\n \\n// ...\\n \\nCoordinate start = new Coordinate(1234, 1234, 0);\\nCoordinate end = new Coordinate(12345, 12345, 0);\\n \\nindoorsFragment.getIndoors().getRouteAToB(start, end, new RoutingCallback() {\\n  @Override\\n  public void onError(IndoorsException arg0) {\\n    // TODO Auto-generated method stub\\n  }\\n  \\n  @Override\\n  public void setRoute(ArrayList<Coordinate> route) {\\n    indoorsFragment.getSurfaceState().setRoutingPath(route);\\n    // this is how to enable route snapping starting with version 3.8\\n    IndoorsFactory.getInstance().enableRouteSnapping(route);\\n    indoorsFragment.updateSurface();\\n  }\\n}); \",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nFor example, you could update the route everytime a new position is calculated by calling the calculateRoute-method in the code shown above.\n\nIf you're fairly certain that a user is going to walk the route that is being displayed right now, we recommend to activate what we call \"route snapping\" the calculated position snaps to the shown route if it is within a certain area of the route. This is done using the method  enableSnapToRoute\n\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Route snapping\",\n  \"body\": \"Starting from v3.8:\\n***setRoutingPath*** method does not require the enable/disable parameter for snapping. The path snapping is done using the method ***enableSnapToRoute(ArrayList<Coordinate> pathToSnap)***\"\n}\n[/block]\nTo cancel the displayed route is quite easy. Just call the same method you used to display a route with a null route. Like this:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"void cancelRoute(){\\n  indoorsFragment.getSurfaceState().setRoutingPath(null);\\n  indoorsFragment.updateSurface();\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:33:35.578Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":4,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"routing","sync_unique":"","title":"Routing","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Routing


Calculating and displaying a route on the map is a matter of a few lines too: [block:code] { "codes": [ { "code": "import com.customlbs.shared.Coordinate;\n \nimport com.customlbs.library.callbacks.RoutingCallback;\n \n// ...\n \nCoordinate start = new Coordinate(1234, 1234, 0);\nCoordinate end = new Coordinate(12345, 12345, 0);\n \nindoorsFragment.getIndoors().getRouteAToB(start, end, new RoutingCallback() {\n @Override\n public void onError(IndoorsException arg0) {\n // TODO Auto-generated method stub\n }\n \n @Override\n public void setRoute(ArrayList<Coordinate> route) {\n indoorsFragment.getSurfaceState().setRoutingPath(route);\n // this is how to enable route snapping starting with version 3.8\n IndoorsFactory.getInstance().enableRouteSnapping(route);\n indoorsFragment.updateSurface();\n }\n}); ", "language": "java" } ] } [/block] For example, you could update the route everytime a new position is calculated by calling the calculateRoute-method in the code shown above. If you're fairly certain that a user is going to walk the route that is being displayed right now, we recommend to activate what we call "route snapping" the calculated position snaps to the shown route if it is within a certain area of the route. This is done using the method enableSnapToRoute [block:callout] { "type": "danger", "title": "Route snapping", "body": "Starting from v3.8:\n***setRoutingPath*** method does not require the enable/disable parameter for snapping. The path snapping is done using the method ***enableSnapToRoute(ArrayList<Coordinate> pathToSnap)***" } [/block] To cancel the displayed route is quite easy. Just call the same method you used to display a route with a null route. Like this: [block:code] { "codes": [ { "code": "void cancelRoute(){\n indoorsFragment.getSurfaceState().setRoutingPath(null);\n indoorsFragment.updateSurface();\n}", "language": "java" } ] } [/block]
Calculating and displaying a route on the map is a matter of a few lines too: [block:code] { "codes": [ { "code": "import com.customlbs.shared.Coordinate;\n \nimport com.customlbs.library.callbacks.RoutingCallback;\n \n// ...\n \nCoordinate start = new Coordinate(1234, 1234, 0);\nCoordinate end = new Coordinate(12345, 12345, 0);\n \nindoorsFragment.getIndoors().getRouteAToB(start, end, new RoutingCallback() {\n @Override\n public void onError(IndoorsException arg0) {\n // TODO Auto-generated method stub\n }\n \n @Override\n public void setRoute(ArrayList<Coordinate> route) {\n indoorsFragment.getSurfaceState().setRoutingPath(route);\n // this is how to enable route snapping starting with version 3.8\n IndoorsFactory.getInstance().enableRouteSnapping(route);\n indoorsFragment.updateSurface();\n }\n}); ", "language": "java" } ] } [/block] For example, you could update the route everytime a new position is calculated by calling the calculateRoute-method in the code shown above. If you're fairly certain that a user is going to walk the route that is being displayed right now, we recommend to activate what we call "route snapping" the calculated position snaps to the shown route if it is within a certain area of the route. This is done using the method enableSnapToRoute [block:callout] { "type": "danger", "title": "Route snapping", "body": "Starting from v3.8:\n***setRoutingPath*** method does not require the enable/disable parameter for snapping. The path snapping is done using the method ***enableSnapToRoute(ArrayList<Coordinate> pathToSnap)***" } [/block] To cancel the displayed route is quite easy. Just call the same method you used to display a route with a null route. Like this: [block:code] { "codes": [ { "code": "void cancelRoute(){\n indoorsFragment.getSurfaceState().setRoutingPath(null);\n indoorsFragment.updateSurface();\n}", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820a6","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"### Path Snapping for routing\nAs described in section [Routing], it is possible to enable path snapping, for further control also you can disable path snapping and set the threshold (maximum distance) for snapping.\nAfter being connected to the indoors service you can use the following sdk methods:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"ArrayList<Coordinate> pathToSnap = new ArrayList<Coordinate>() // your route as a list of coordinates \\nIndoorsFactory.getInstance().enableRouteSnapping(pathToSnap);\\nIndoorsFactory.getInstance().setRouteSnappingMaxDistance(5000); // in millimeters\\nIndoorsFactory.getInstance().disabelRouteSnapping();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### Path Snapping for PredefinedRoutes\n\nTo draw predefined routes use MMT tool (https://my.indoo.rs/javadoc/mmt_guide/). After you create a predefined route, you can enable or disable \"path snapping\". \nAfter being connected to the indoors service you can use the following sdk methods\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tIndoorsFactory.getInstance().enablePredefinedRouteSnapping();\\n\\tIndoorsFactory.getInstance().disablePredefinedRouteSnapping();\\n\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nBy default route snapping for predefined routes is disabled.\n\nWhen predefined route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"double threshold = 5000\\t// in milimeters\\nIndoorsFactory.getInstance().setPredefinedRouteSnappingMaxDistance(threshold);\\n\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-09-28T14:19:00.302Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":5,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"path-snapping-1","sync_unique":"","title":"Path Snapping","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Path Snapping


### Path Snapping for routing As described in section [Routing], it is possible to enable path snapping, for further control also you can disable path snapping and set the threshold (maximum distance) for snapping. After being connected to the indoors service you can use the following sdk methods: [block:code] { "codes": [ { "code": "ArrayList<Coordinate> pathToSnap = new ArrayList<Coordinate>() // your route as a list of coordinates \nIndoorsFactory.getInstance().enableRouteSnapping(pathToSnap);\nIndoorsFactory.getInstance().setRouteSnappingMaxDistance(5000); // in millimeters\nIndoorsFactory.getInstance().disabelRouteSnapping();", "language": "java" } ] } [/block] ### Path Snapping for PredefinedRoutes To draw predefined routes use MMT tool (https://my.indoo.rs/javadoc/mmt_guide/). After you create a predefined route, you can enable or disable "path snapping". After being connected to the indoors service you can use the following sdk methods [block:code] { "codes": [ { "code": "\tIndoorsFactory.getInstance().enablePredefinedRouteSnapping();\n\tIndoorsFactory.getInstance().disablePredefinedRouteSnapping();\n", "language": "java" } ] } [/block] By default route snapping for predefined routes is disabled. When predefined route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. [block:code] { "codes": [ { "code": "double threshold = 5000\t// in milimeters\nIndoorsFactory.getInstance().setPredefinedRouteSnappingMaxDistance(threshold);\n", "language": "java" } ] } [/block]
### Path Snapping for routing As described in section [Routing], it is possible to enable path snapping, for further control also you can disable path snapping and set the threshold (maximum distance) for snapping. After being connected to the indoors service you can use the following sdk methods: [block:code] { "codes": [ { "code": "ArrayList<Coordinate> pathToSnap = new ArrayList<Coordinate>() // your route as a list of coordinates \nIndoorsFactory.getInstance().enableRouteSnapping(pathToSnap);\nIndoorsFactory.getInstance().setRouteSnappingMaxDistance(5000); // in millimeters\nIndoorsFactory.getInstance().disabelRouteSnapping();", "language": "java" } ] } [/block] ### Path Snapping for PredefinedRoutes To draw predefined routes use MMT tool (https://my.indoo.rs/javadoc/mmt_guide/). After you create a predefined route, you can enable or disable "path snapping". After being connected to the indoors service you can use the following sdk methods [block:code] { "codes": [ { "code": "\tIndoorsFactory.getInstance().enablePredefinedRouteSnapping();\n\tIndoorsFactory.getInstance().disablePredefinedRouteSnapping();\n", "language": "java" } ] } [/block] By default route snapping for predefined routes is disabled. When predefined route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. [block:code] { "codes": [ { "code": "double threshold = 5000\t// in milimeters\nIndoorsFactory.getInstance().setPredefinedRouteSnappingMaxDistance(threshold);\n", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820a7","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"Dot on rails is used to animate every position change like the dot is a train and the path is the rails. By enabling Dot on rails, it enhances user experience of the dot movement. Dot will always stay on the predefined path, and will not jump trough walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif), you can see how this actually works \n\n### Enabling Dot on Rails :\nTo enable dot on rails you need to have *** path Snapping enabled***  please take a look at [Path Snapping](doc:path-snapping-1)\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"....\\nIndoorsSurfaceFactory.Builder surfaceBuilder = new indoorsSurfaceFactory.Builder()  \\t\\t\\t\\nsurfaceBuilder.setDotOnRailsEnabled(SharedPreferencesUtil.getEnableDotOnRails(this));\\n....\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### Jumping Distance:\nLike path snapping, Dot on Rails feature has it's maximum distance in which it can jump to a predefined path. Value is in millimeters. The default value is 10.000, and recommended values are between 1.000 and 30.000 mm. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \".....\\nsurfaceBuilder.setDotOnRailsJumpingDistance(10000);\\n....\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2016-01-22T09:37:51.544Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":6,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"dot-on-rails-1","sync_unique":"","title":"Dot on rails","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Dot on rails


Dot on rails is used to animate every position change like the dot is a train and the path is the rails. By enabling Dot on rails, it enhances user experience of the dot movement. Dot will always stay on the predefined path, and will not jump trough walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif), you can see how this actually works ### Enabling Dot on Rails : To enable dot on rails you need to have *** path Snapping enabled*** please take a look at [Path Snapping](doc:path-snapping-1) [block:code] { "codes": [ { "code": "....\nIndoorsSurfaceFactory.Builder surfaceBuilder = new indoorsSurfaceFactory.Builder() \t\t\t\nsurfaceBuilder.setDotOnRailsEnabled(SharedPreferencesUtil.getEnableDotOnRails(this));\n....", "language": "java" } ] } [/block] ### Jumping Distance: Like path snapping, Dot on Rails feature has it's maximum distance in which it can jump to a predefined path. Value is in millimeters. The default value is 10.000, and recommended values are between 1.000 and 30.000 mm. [block:code] { "codes": [ { "code": ".....\nsurfaceBuilder.setDotOnRailsJumpingDistance(10000);\n....", "language": "java" } ] } [/block]
Dot on rails is used to animate every position change like the dot is a train and the path is the rails. By enabling Dot on rails, it enhances user experience of the dot movement. Dot will always stay on the predefined path, and will not jump trough walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif), you can see how this actually works ### Enabling Dot on Rails : To enable dot on rails you need to have *** path Snapping enabled*** please take a look at [Path Snapping](doc:path-snapping-1) [block:code] { "codes": [ { "code": "....\nIndoorsSurfaceFactory.Builder surfaceBuilder = new indoorsSurfaceFactory.Builder() \t\t\t\nsurfaceBuilder.setDotOnRailsEnabled(SharedPreferencesUtil.getEnableDotOnRails(this));\n....", "language": "java" } ] } [/block] ### Jumping Distance: Like path snapping, Dot on Rails feature has it's maximum distance in which it can jump to a predefined path. Value is in millimeters. The default value is 10.000, and recommended values are between 1.000 and 30.000 mm. [block:code] { "codes": [ { "code": ".....\nsurfaceBuilder.setDotOnRailsJumpingDistance(10000);\n....", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820a8","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example.\n\nAnother way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route them to where they want to go.","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:44:50.368Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":7,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"zones","sync_unique":"","title":"Zones","type":"basic","updates":["57895460f55bf80e00d0c2e1"],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Zones


You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route them to where they want to go.
You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route them to where they want to go.
{"__v":0,"_id":"57e3bcc2378b341700c820a9","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"Depending on your specific usecase, the user might only be interested to know in which room / shop he's currently located. If that's the case in your app, you should use something like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsFragment.setViewMode(ViewMode.HIGHLIGHT_CURRENT_ZONE);\\nindoorsFragment.setViewMode(ViewMode.HIDE_USER_POSITION);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIf you want to show the exact position of the user (\"Expert Mode\", aka \"Fingerprinting\") you could change the icon of the current user position like this: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// TODO: load bitmaps\\nBitmap navigationArrow = null;\\nBitmap navigationPoint = null;\\n\\nSurfacePainterConfiguration configuration = DefaultSurfacePainterConfiguration.getConfiguration();\\nconfiguration.setNavigationArrow(navigationArrow);\\nconfiguration.setNavigationPoint(navigationPoint);\\n\\nsurfaceBuilder.setSurfacePainterConfiguration(configuration);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nAnother usecase might require you to simply show all available zones, which is possible too of course: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsFragment.setViewMode(ViewMode.HIGHLIGHT_ALL_ZONES);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIt is now also possible to set the PaintConfiguration of various map display items, as seen below: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"SurfacePainterConfiguration configuration = DefaultSurfacePainterConfiguration\\n\\t\\t.getConfiguration();\\n\\nconfiguration.getUserPositionCircleInlinePaintConfiguration().setColor(Color.RED);\\nconfiguration.getLargeCircleOutlinePaintConfiguration().setColor(Color.RED);\\tconfiguration.configuration.getRoutingPathPaintConfiguration().setColor(Color.RED);\\nconfiguration.configuration.getRoutingPathPaintConfiguration().setColor(Color.RED);\\n\\nsurfaceBuilder.setSurfacePainterConfiguration(configuration);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:35:57.884Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":8,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"styling","sync_unique":"","title":"Styling","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Styling


Depending on your specific usecase, the user might only be interested to know in which room / shop he's currently located. If that's the case in your app, you should use something like this: [block:code] { "codes": [ { "code": "indoorsFragment.setViewMode(ViewMode.HIGHLIGHT_CURRENT_ZONE);\nindoorsFragment.setViewMode(ViewMode.HIDE_USER_POSITION);", "language": "java" } ] } [/block] If you want to show the exact position of the user ("Expert Mode", aka "Fingerprinting") you could change the icon of the current user position like this: [block:code] { "codes": [ { "code": "// TODO: load bitmaps\nBitmap navigationArrow = null;\nBitmap navigationPoint = null;\n\nSurfacePainterConfiguration configuration = DefaultSurfacePainterConfiguration.getConfiguration();\nconfiguration.setNavigationArrow(navigationArrow);\nconfiguration.setNavigationPoint(navigationPoint);\n\nsurfaceBuilder.setSurfacePainterConfiguration(configuration);", "language": "java" } ] } [/block] Another usecase might require you to simply show all available zones, which is possible too of course: [block:code] { "codes": [ { "code": "indoorsFragment.setViewMode(ViewMode.HIGHLIGHT_ALL_ZONES);", "language": "java" } ] } [/block] It is now also possible to set the PaintConfiguration of various map display items, as seen below: [block:code] { "codes": [ { "code": "SurfacePainterConfiguration configuration = DefaultSurfacePainterConfiguration\n\t\t.getConfiguration();\n\nconfiguration.getUserPositionCircleInlinePaintConfiguration().setColor(Color.RED);\nconfiguration.getLargeCircleOutlinePaintConfiguration().setColor(Color.RED);\tconfiguration.configuration.getRoutingPathPaintConfiguration().setColor(Color.RED);\nconfiguration.configuration.getRoutingPathPaintConfiguration().setColor(Color.RED);\n\nsurfaceBuilder.setSurfacePainterConfiguration(configuration);", "language": "java" } ] } [/block]
Depending on your specific usecase, the user might only be interested to know in which room / shop he's currently located. If that's the case in your app, you should use something like this: [block:code] { "codes": [ { "code": "indoorsFragment.setViewMode(ViewMode.HIGHLIGHT_CURRENT_ZONE);\nindoorsFragment.setViewMode(ViewMode.HIDE_USER_POSITION);", "language": "java" } ] } [/block] If you want to show the exact position of the user ("Expert Mode", aka "Fingerprinting") you could change the icon of the current user position like this: [block:code] { "codes": [ { "code": "// TODO: load bitmaps\nBitmap navigationArrow = null;\nBitmap navigationPoint = null;\n\nSurfacePainterConfiguration configuration = DefaultSurfacePainterConfiguration.getConfiguration();\nconfiguration.setNavigationArrow(navigationArrow);\nconfiguration.setNavigationPoint(navigationPoint);\n\nsurfaceBuilder.setSurfacePainterConfiguration(configuration);", "language": "java" } ] } [/block] Another usecase might require you to simply show all available zones, which is possible too of course: [block:code] { "codes": [ { "code": "indoorsFragment.setViewMode(ViewMode.HIGHLIGHT_ALL_ZONES);", "language": "java" } ] } [/block] It is now also possible to set the PaintConfiguration of various map display items, as seen below: [block:code] { "codes": [ { "code": "SurfacePainterConfiguration configuration = DefaultSurfacePainterConfiguration\n\t\t.getConfiguration();\n\nconfiguration.getUserPositionCircleInlinePaintConfiguration().setColor(Color.RED);\nconfiguration.getLargeCircleOutlinePaintConfiguration().setColor(Color.RED);\tconfiguration.configuration.getRoutingPathPaintConfiguration().setColor(Color.RED);\nconfiguration.configuration.getRoutingPathPaintConfiguration().setColor(Color.RED);\n\nsurfaceBuilder.setSurfacePainterConfiguration(configuration);", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820aa","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"Starting from SDK version 2.1.0 you are able to add overlays on top of our map:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsFragment.addOverlay(new SampleSurfaceOverlay());\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"package com.mycompany.myfirstindoorsapp;\\n \\nimport android.graphics.Canvas;\\nimport android.graphics.Color;\\nimport android.graphics.Paint;\\n \\nimport com.customlbs.surface.library.IndoorsSurfaceOverlay;\\nimport com.customlbs.surface.library.IndoorsSurfaceOverlayUtil;\\nimport com.customlbs.surface.library.IndoorsSurfaceOverlayUtil.CanvasCoordinate;\\nimport com.customlbs.surface.library.SurfacePainterConfiguration;\\nimport com.customlbs.surface.library.SurfaceState;\\n \\npublic class SampleSurfaceOverlay implements IndoorsSurfaceOverlay {\\n \\n  private Paint paint;\\n\\n  @Override\\n  public void initialize(SurfacePainterConfiguration arg0) {\\n    paint = new Paint();\\n    paint.setColor(Color.YELLOW);\\n  }\\n\\n  @Override\\n  public void paint(Canvas canvas, SurfaceState state) {\\n    if (state.lastFloorLevelSelectedByLibrary == state.currentFloor.getLevel()) {\\n      CanvasCoordinate coordinate = IndoorsSurfaceOverlayUtil\\n      .buildingCoordinateToCanvasAbsolute(state, state.userPositionX,\\n      state.userPositionY);\\n\\n      canvas.drawText(\\\"whereami\\\", coordinate.x, coordinate.y, paint);\\n    }\\n  }\\n\\n  @Override\\n  public void destroy() {\\n  }\\n} \",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:46:57.060Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":9,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"overlays","sync_unique":"","title":"Overlays","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Overlays


Starting from SDK version 2.1.0 you are able to add overlays on top of our map: [block:code] { "codes": [ { "code": "indoorsFragment.addOverlay(new SampleSurfaceOverlay());", "language": "java" } ] } [/block] [block:code] { "codes": [ { "code": "package com.mycompany.myfirstindoorsapp;\n \nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\n \nimport com.customlbs.surface.library.IndoorsSurfaceOverlay;\nimport com.customlbs.surface.library.IndoorsSurfaceOverlayUtil;\nimport com.customlbs.surface.library.IndoorsSurfaceOverlayUtil.CanvasCoordinate;\nimport com.customlbs.surface.library.SurfacePainterConfiguration;\nimport com.customlbs.surface.library.SurfaceState;\n \npublic class SampleSurfaceOverlay implements IndoorsSurfaceOverlay {\n \n private Paint paint;\n\n @Override\n public void initialize(SurfacePainterConfiguration arg0) {\n paint = new Paint();\n paint.setColor(Color.YELLOW);\n }\n\n @Override\n public void paint(Canvas canvas, SurfaceState state) {\n if (state.lastFloorLevelSelectedByLibrary == state.currentFloor.getLevel()) {\n CanvasCoordinate coordinate = IndoorsSurfaceOverlayUtil\n .buildingCoordinateToCanvasAbsolute(state, state.userPositionX,\n state.userPositionY);\n\n canvas.drawText(\"whereami\", coordinate.x, coordinate.y, paint);\n }\n }\n\n @Override\n public void destroy() {\n }\n} ", "language": "java" } ] } [/block]
Starting from SDK version 2.1.0 you are able to add overlays on top of our map: [block:code] { "codes": [ { "code": "indoorsFragment.addOverlay(new SampleSurfaceOverlay());", "language": "java" } ] } [/block] [block:code] { "codes": [ { "code": "package com.mycompany.myfirstindoorsapp;\n \nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.Paint;\n \nimport com.customlbs.surface.library.IndoorsSurfaceOverlay;\nimport com.customlbs.surface.library.IndoorsSurfaceOverlayUtil;\nimport com.customlbs.surface.library.IndoorsSurfaceOverlayUtil.CanvasCoordinate;\nimport com.customlbs.surface.library.SurfacePainterConfiguration;\nimport com.customlbs.surface.library.SurfaceState;\n \npublic class SampleSurfaceOverlay implements IndoorsSurfaceOverlay {\n \n private Paint paint;\n\n @Override\n public void initialize(SurfacePainterConfiguration arg0) {\n paint = new Paint();\n paint.setColor(Color.YELLOW);\n }\n\n @Override\n public void paint(Canvas canvas, SurfaceState state) {\n if (state.lastFloorLevelSelectedByLibrary == state.currentFloor.getLevel()) {\n CanvasCoordinate coordinate = IndoorsSurfaceOverlayUtil\n .buildingCoordinateToCanvasAbsolute(state, state.userPositionX,\n state.userPositionY);\n\n canvas.drawText(\"whereami\", coordinate.x, coordinate.y, paint);\n }\n }\n\n @Override\n public void destroy() {\n }\n} ", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820ab","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Our SDK allows you to bundle maps directly with your app, so that users won't have to download them separately when opening the app for the first time. This is especially useful if you expect your users to have no internet connectivity when they launch your app for the first time.\n\nFirst you have to download the map file directly from the server. Here is a [curl](http://curl.haxx.se/) command to do that (you have to replace \"API_KEY\" and \"BUILDING_ID\" with the proper values):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X GET -H \\\"x-indoors-api-key: API_KEY\\\" -H \\\"Accept: application/x-com.customlbs.indoorsphonemap+zip\\\" https://api.indoo.rs/indoors/rest/buildings/BUILDING_ID/mapfile -o building.idp\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\nThe SDK will now check if there is a matching map included in your app everytime you request to load a building. Please note, that the SDK will only load the map from inside the app if the building IDs match exactly. In order to find out what the building ID of your map is, open the MMT and find your building under \"File\" - \"My buildings...\".\n\nUpdates to your map will be downloaded automatically, as the SDK checks for new versions of the map in the background (when the app is running). Localization is restarted automatically after the updated map has been downloaded\n\nNote: In order to get the map downloaded, the SDK has to be running. If the SDK is turned off (or the map is not in the foreground) no downloads will be initiated.\n\nFor the map bundling to work and for the SDK to find the buildings.idp that you have just downloaded it need to be placed in the assets/maps/ folder of the app. To see how this is done in Android Studio look at this screenshot.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Dd9tRaKVR5GfJQnGJlsG_android-studio-map-asset-location.png\",\n        \"android-studio-map-asset-location.png\",\n        \"413\",\n        \"422\",\n        \"#be965e\",\n        \"\"\n      ],\n      \"caption\": \"placement of the building.idp file in the androd studio project\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:50:37.313Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":10,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"map-with-app","sync_unique":"","title":"Map with App","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Map with App


Our SDK allows you to bundle maps directly with your app, so that users won't have to download them separately when opening the app for the first time. This is especially useful if you expect your users to have no internet connectivity when they launch your app for the first time. First you have to download the map file directly from the server. Here is a [curl](http://curl.haxx.se/) command to do that (you have to replace "API_KEY" and "BUILDING_ID" with the proper values): [block:code] { "codes": [ { "code": "curl -X GET -H \"x-indoors-api-key: API_KEY\" -H \"Accept: application/x-com.customlbs.indoorsphonemap+zip\" https://api.indoo.rs/indoors/rest/buildings/BUILDING_ID/mapfile -o building.idp", "language": "shell" } ] } [/block] The SDK will now check if there is a matching map included in your app everytime you request to load a building. Please note, that the SDK will only load the map from inside the app if the building IDs match exactly. In order to find out what the building ID of your map is, open the MMT and find your building under "File" - "My buildings...". Updates to your map will be downloaded automatically, as the SDK checks for new versions of the map in the background (when the app is running). Localization is restarted automatically after the updated map has been downloaded Note: In order to get the map downloaded, the SDK has to be running. If the SDK is turned off (or the map is not in the foreground) no downloads will be initiated. For the map bundling to work and for the SDK to find the buildings.idp that you have just downloaded it need to be placed in the assets/maps/ folder of the app. To see how this is done in Android Studio look at this screenshot. [block:image] { "images": [ { "image": [ "https://files.readme.io/Dd9tRaKVR5GfJQnGJlsG_android-studio-map-asset-location.png", "android-studio-map-asset-location.png", "413", "422", "#be965e", "" ], "caption": "placement of the building.idp file in the androd studio project" } ] } [/block]
Our SDK allows you to bundle maps directly with your app, so that users won't have to download them separately when opening the app for the first time. This is especially useful if you expect your users to have no internet connectivity when they launch your app for the first time. First you have to download the map file directly from the server. Here is a [curl](http://curl.haxx.se/) command to do that (you have to replace "API_KEY" and "BUILDING_ID" with the proper values): [block:code] { "codes": [ { "code": "curl -X GET -H \"x-indoors-api-key: API_KEY\" -H \"Accept: application/x-com.customlbs.indoorsphonemap+zip\" https://api.indoo.rs/indoors/rest/buildings/BUILDING_ID/mapfile -o building.idp", "language": "shell" } ] } [/block] The SDK will now check if there is a matching map included in your app everytime you request to load a building. Please note, that the SDK will only load the map from inside the app if the building IDs match exactly. In order to find out what the building ID of your map is, open the MMT and find your building under "File" - "My buildings...". Updates to your map will be downloaded automatically, as the SDK checks for new versions of the map in the background (when the app is running). Localization is restarted automatically after the updated map has been downloaded Note: In order to get the map downloaded, the SDK has to be running. If the SDK is turned off (or the map is not in the foreground) no downloads will be initiated. For the map bundling to work and for the SDK to find the buildings.idp that you have just downloaded it need to be placed in the assets/maps/ folder of the app. To see how this is done in Android Studio look at this screenshot. [block:image] { "images": [ { "image": [ "https://files.readme.io/Dd9tRaKVR5GfJQnGJlsG_android-studio-map-asset-location.png", "android-studio-map-asset-location.png", "413", "422", "#be965e", "" ], "caption": "placement of the building.idp file in the androd studio project" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820ac","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public class MainActivity extends FragmentActivity implements IndoorsServiceCallback,\\n  IndoorsLocationListener {\\n\\n  private Indoors indoors;\\n\\n  @Override\\n  protected void onCreate(Bundle savedInstanceState) {\\n    super.onCreate(savedInstanceState);\\n\\n    // TODO: replace with your API key\\n    IndoorsFactory.createInstance(this, \\\"YOUR-API-KEY\\\", this, false);\\n  }\\n\\n  @Override\\n  public void connected() {\\n    indoors = IndoorsFactory.getInstance();\\n\\n    indoors.registerLocationListener(this);\\n\\n    // TODO: replace building id\\n    indoors.setLocatedCloudBuilding(12345, new LocalizationParameters());\\n  }\\n\\n  @Override\\n  public void onError(IndoorsException indoorsException) {\\n    // TODO Auto-generated method stub\\n  }\\n\\n  @Override\\n  protected void onStop() {\\n    super.onStop();\\n\\n    indoors.removeLocationListener(this);\\n\\n    IndoorsFactory.releaseInstance(this);\\n  }\\n\\n  @Override\\n  public void buildingLoaded(Building building) {\\n    // TODO Auto-generated method stub\\n    // Building was loaded successfuly\\n  }\\n\\n  @Override\\n  public void changedFloor(int floorLevel, String name) {\\n    // TODO Auto-generated method stub\\n    // User changed the floor\\n  }\\n\\n  @Override\\n  public void enteredZones(List<Zone> arg0) {\\n    // TODO Auto-generated method stub\\n    // List of zones that the user is inside currently\\n  }\\n\\n  @Override\\n  public void leftBuilding(Building building) {\\n    // Deprecated, do not use\\n  }\\n\\n\\t@Override\\n  public void buildingReleased(Building building) {\\n    // another building was loaded, sdk has released building resources.\\n    // Your code can now also release resouces from the old building \\n    // (ie. List of zones)\\n  }\\n\\n  @Override\\n  public void loadingBuilding(LoadingBuildingStatus status) {\\n    // TODO Auto-generated method stub\\n    // Status on the progress of loading the given building\\n  }\\n\\n  @Override\\n  public void orientationUpdated(float orientation) {\\n    // TODO Auto-generated method stub\\n  }\\n\\n  @Override\\n  public void positionUpdated(Coordinate userPosition, int accuracy) {\\n    // TODO Auto-generated method stub\\n    // User position changed.\\n  }\\n} \",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThis is useful for apps which already have their own map rendering in place.","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:51:38.690Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":11,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"localisation-without-ui","sync_unique":"","title":"Localization without UI","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Localization without UI


[block:code] { "codes": [ { "code": "public class MainActivity extends FragmentActivity implements IndoorsServiceCallback,\n IndoorsLocationListener {\n\n private Indoors indoors;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n // TODO: replace with your API key\n IndoorsFactory.createInstance(this, \"YOUR-API-KEY\", this, false);\n }\n\n @Override\n public void connected() {\n indoors = IndoorsFactory.getInstance();\n\n indoors.registerLocationListener(this);\n\n // TODO: replace building id\n indoors.setLocatedCloudBuilding(12345, new LocalizationParameters());\n }\n\n @Override\n public void onError(IndoorsException indoorsException) {\n // TODO Auto-generated method stub\n }\n\n @Override\n protected void onStop() {\n super.onStop();\n\n indoors.removeLocationListener(this);\n\n IndoorsFactory.releaseInstance(this);\n }\n\n @Override\n public void buildingLoaded(Building building) {\n // TODO Auto-generated method stub\n // Building was loaded successfuly\n }\n\n @Override\n public void changedFloor(int floorLevel, String name) {\n // TODO Auto-generated method stub\n // User changed the floor\n }\n\n @Override\n public void enteredZones(List<Zone> arg0) {\n // TODO Auto-generated method stub\n // List of zones that the user is inside currently\n }\n\n @Override\n public void leftBuilding(Building building) {\n // Deprecated, do not use\n }\n\n\t@Override\n public void buildingReleased(Building building) {\n // another building was loaded, sdk has released building resources.\n // Your code can now also release resouces from the old building \n // (ie. List of zones)\n }\n\n @Override\n public void loadingBuilding(LoadingBuildingStatus status) {\n // TODO Auto-generated method stub\n // Status on the progress of loading the given building\n }\n\n @Override\n public void orientationUpdated(float orientation) {\n // TODO Auto-generated method stub\n }\n\n @Override\n public void positionUpdated(Coordinate userPosition, int accuracy) {\n // TODO Auto-generated method stub\n // User position changed.\n }\n} ", "language": "java" } ] } [/block] This is useful for apps which already have their own map rendering in place.
[block:code] { "codes": [ { "code": "public class MainActivity extends FragmentActivity implements IndoorsServiceCallback,\n IndoorsLocationListener {\n\n private Indoors indoors;\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n // TODO: replace with your API key\n IndoorsFactory.createInstance(this, \"YOUR-API-KEY\", this, false);\n }\n\n @Override\n public void connected() {\n indoors = IndoorsFactory.getInstance();\n\n indoors.registerLocationListener(this);\n\n // TODO: replace building id\n indoors.setLocatedCloudBuilding(12345, new LocalizationParameters());\n }\n\n @Override\n public void onError(IndoorsException indoorsException) {\n // TODO Auto-generated method stub\n }\n\n @Override\n protected void onStop() {\n super.onStop();\n\n indoors.removeLocationListener(this);\n\n IndoorsFactory.releaseInstance(this);\n }\n\n @Override\n public void buildingLoaded(Building building) {\n // TODO Auto-generated method stub\n // Building was loaded successfuly\n }\n\n @Override\n public void changedFloor(int floorLevel, String name) {\n // TODO Auto-generated method stub\n // User changed the floor\n }\n\n @Override\n public void enteredZones(List<Zone> arg0) {\n // TODO Auto-generated method stub\n // List of zones that the user is inside currently\n }\n\n @Override\n public void leftBuilding(Building building) {\n // Deprecated, do not use\n }\n\n\t@Override\n public void buildingReleased(Building building) {\n // another building was loaded, sdk has released building resources.\n // Your code can now also release resouces from the old building \n // (ie. List of zones)\n }\n\n @Override\n public void loadingBuilding(LoadingBuildingStatus status) {\n // TODO Auto-generated method stub\n // Status on the progress of loading the given building\n }\n\n @Override\n public void orientationUpdated(float orientation) {\n // TODO Auto-generated method stub\n }\n\n @Override\n public void positionUpdated(Coordinate userPosition, int accuracy) {\n // TODO Auto-generated method stub\n // User position changed.\n }\n} ", "language": "java" } ] } [/block] This is useful for apps which already have their own map rendering in place.
{"__v":0,"_id":"57e3bcc2378b341700c820ad","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"Most people prefer GPS coordinates over our internal coordinates:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void buildingLoaded(Building building) {\\n  this.building = building;\\n}\\n\\n@Override\\npublic void positionUpdated(Coordinate userPosition, int accuracy) {\\n  Location geoLocation = IndoorsCoordinateUtil.toGeoLocation(userPosition, building);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nPlease keep in mind that this won't work if\n * you didn't set a origin for your building in the MMT \n * if you set no / a wrong rotation for your building in the MMT!","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:53:42.505Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":12,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"gps-coordinates","sync_unique":"","title":"GPS-Coordinates","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

GPS-Coordinates


Most people prefer GPS coordinates over our internal coordinates: [block:code] { "codes": [ { "code": "@Override\npublic void buildingLoaded(Building building) {\n this.building = building;\n}\n\n@Override\npublic void positionUpdated(Coordinate userPosition, int accuracy) {\n Location geoLocation = IndoorsCoordinateUtil.toGeoLocation(userPosition, building);\n}", "language": "java" } ] } [/block] Please keep in mind that this won't work if * you didn't set a origin for your building in the MMT * if you set no / a wrong rotation for your building in the MMT!
Most people prefer GPS coordinates over our internal coordinates: [block:code] { "codes": [ { "code": "@Override\npublic void buildingLoaded(Building building) {\n this.building = building;\n}\n\n@Override\npublic void positionUpdated(Coordinate userPosition, int accuracy) {\n Location geoLocation = IndoorsCoordinateUtil.toGeoLocation(userPosition, building);\n}", "language": "java" } ] } [/block] Please keep in mind that this won't work if * you didn't set a origin for your building in the MMT * if you set no / a wrong rotation for your building in the MMT!
{"__v":0,"_id":"57e3bcc2378b341700c820ae","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"Android allows you to run your service in the foreground if needed, this will bring a notification icon in your status bar with your ticker text. Our sdk allows you to enable or disbale using the method **setForegroundService**\n\nplease visit android guidlines [Getting Started with indoo.rs Android Guide Services](http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29)\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\t\\tindoors = IndoorsFactory.getInstance();\\n\\t\\tindoors.setForegroundService(true,\\\"your ticker text\\\"));\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-03-13T08:56:56.562Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":13,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"enabledisable-soreground-service","sync_unique":"","title":"Enable/Disable Foreground Service","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Enable/Disable Foreground Service


Android allows you to run your service in the foreground if needed, this will bring a notification icon in your status bar with your ticker text. Our sdk allows you to enable or disbale using the method **setForegroundService** please visit android guidlines [Getting Started with indoo.rs Android Guide Services](http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29) [block:code] { "codes": [ { "code": "\t\tindoors = IndoorsFactory.getInstance();\n\t\tindoors.setForegroundService(true,\"your ticker text\"));", "language": "java" } ] } [/block]
Android allows you to run your service in the foreground if needed, this will bring a notification icon in your status bar with your ticker text. Our sdk allows you to enable or disbale using the method **setForegroundService** please visit android guidlines [Getting Started with indoo.rs Android Guide Services](http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29) [block:code] { "codes": [ { "code": "\t\tindoors = IndoorsFactory.getInstance();\n\t\tindoors.setForegroundService(true,\"your ticker text\"));", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820af","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Indoors SDK requires the following permissions:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<uses-permission android:name=\\\"android.permission.ACCESS_NETWORK_STATE\\\" />\\n<uses-permission android:name=\\\"android.permission.ACCESS_WIFI_STATE\\\" />\\n<uses-permission android:name=\\\"android.permission.CHANGE_WIFI_STATE\\\" />\\n<uses-permission android:name=\\\"android.permission.INTERNET\\\" />\\n<uses-permission android:name=\\\"android.permission.BLUETOOTH\\\" />\\n<uses-permission android:name=\\\"android.permission.BLUETOOTH_ADMIN\\\"/> \\n<uses-permission-sdk-23 android:name=\\\"android.permission.ACCESS_COARSE_LOCATION\\\"/>\\n\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"As of version 4.3.0 the permission ***WRITE_EXTERNAL_STORAGE*** is not needed anymore. All the data downloaded by the SDK will be stored in the App directory.\"\n}\n[/block]\n### ACCESS_NETWORK_STATE (REQUIRED):\nAllows applications to access information about networks. This used by our SDK to check if the device is connected before we start downloading.\n\n### ACCESS_WIFI_STATE (REQUIRED): \nThis is used by SDK to start the wifi scan and get list of nearby WiFi networks for localization.\n\n### CHANGE_WIFI_STATE(REQUIRED):\nThis is used to turn on WiFi. \n\n### INTERNET (REQUIRED):\nAllows applications to open network sockets. \nis required:\n* to download our building data \n* to connect to our server and get the list of building \n\n### BLUETOOTH_ADMIN (REQUIRED):\nThis needed for the scan of IBeacons and get the IBeacons Names and to turn Bluethooth on.\n\n### BLUETOOTH (REQUIRED):\nTo perform any Bluetooth communication, such as requesting a connection, accepting a connection.\nThis is needed by our SDK to start iBeacon localisation.\n\n### ACCESS_COARSE_LOCATION (OPTIONAL, REQUIRED FOR Target API 23):\nUsed in cases of need to access GPS, this used by our SDK in case of enabling the GPS parameters settings in  MMT (please take a look at our MMT guide for more information).\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"if you are targeting api 23 or above it is required to use ACCESS_FINE_LOCATION permissions or ACCESS_COARSE_LOCATION permissions for BLE scanning.\"\n}\n[/block]\n### Services:\nYou have to add this call to our worker service in the manifest:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<service\\n            android:name=\\\"com.customlbs.service.Worker\\\"\\n            android:process=\\\":remote\\\">\\n</service>\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"RestBatchService and ConnectivityReceiver Removed\",\n  \"body\": \"<service android:name=\\\"com.customlbs.service.rest.batch.RestBatchService\\\" >\\t\\t     \\n</service>\\t\\t\\n\\t\\t\\n<receiver\\t\\t\\n\\tandroid:name=\\\"com.customlbs.service.rest.batch.ConnectivityReceiver\\\"\\t\\t\\n\\tandroid:enabled=\\\"false\\\" >\\t\\t\\n\\t<intent-filter>\\t\\t\\n\\t\\t<action android:name=\\\"android.net.conn.CONNECTIVITY_CHANGE\\\" />\\t\\t\\n\\t</intent-filter>\\t\\t\\n</receiver>\\n\\nIt was required to have this batch service in the manifest file, starting from v3.5 that is not required anymore.\"\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-07-02T11:38:45.472Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":14,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"indoors-sdk-manifest-permissions","sync_unique":"","title":"Indoors SDK Manifest Permissions","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Indoors SDK Manifest Permissions


Indoors SDK requires the following permissions: [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n<uses-permission android:name=\"android.permission.INTERNET\" />\n<uses-permission android:name=\"android.permission.BLUETOOTH\" />\n<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/> \n<uses-permission-sdk-23 android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n", "language": "xml" } ] } [/block] [block:callout] { "type": "warning", "body": "As of version 4.3.0 the permission ***WRITE_EXTERNAL_STORAGE*** is not needed anymore. All the data downloaded by the SDK will be stored in the App directory." } [/block] ### ACCESS_NETWORK_STATE (REQUIRED): Allows applications to access information about networks. This used by our SDK to check if the device is connected before we start downloading. ### ACCESS_WIFI_STATE (REQUIRED): This is used by SDK to start the wifi scan and get list of nearby WiFi networks for localization. ### CHANGE_WIFI_STATE(REQUIRED): This is used to turn on WiFi. ### INTERNET (REQUIRED): Allows applications to open network sockets. is required: * to download our building data * to connect to our server and get the list of building ### BLUETOOTH_ADMIN (REQUIRED): This needed for the scan of IBeacons and get the IBeacons Names and to turn Bluethooth on. ### BLUETOOTH (REQUIRED): To perform any Bluetooth communication, such as requesting a connection, accepting a connection. This is needed by our SDK to start iBeacon localisation. ### ACCESS_COARSE_LOCATION (OPTIONAL, REQUIRED FOR Target API 23): Used in cases of need to access GPS, this used by our SDK in case of enabling the GPS parameters settings in MMT (please take a look at our MMT guide for more information). [block:callout] { "type": "warning", "body": "if you are targeting api 23 or above it is required to use ACCESS_FINE_LOCATION permissions or ACCESS_COARSE_LOCATION permissions for BLE scanning." } [/block] ### Services: You have to add this call to our worker service in the manifest: [block:code] { "codes": [ { "code": "<service\n android:name=\"com.customlbs.service.Worker\"\n android:process=\":remote\">\n</service>", "language": "xml" } ] } [/block] [block:callout] { "type": "danger", "title": "RestBatchService and ConnectivityReceiver Removed", "body": "<service android:name=\"com.customlbs.service.rest.batch.RestBatchService\" >\t\t \n</service>\t\t\n\t\t\n<receiver\t\t\n\tandroid:name=\"com.customlbs.service.rest.batch.ConnectivityReceiver\"\t\t\n\tandroid:enabled=\"false\" >\t\t\n\t<intent-filter>\t\t\n\t\t<action android:name=\"android.net.conn.CONNECTIVITY_CHANGE\" />\t\t\n\t</intent-filter>\t\t\n</receiver>\n\nIt was required to have this batch service in the manifest file, starting from v3.5 that is not required anymore." } [/block]
Indoors SDK requires the following permissions: [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n<uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n<uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n<uses-permission android:name=\"android.permission.INTERNET\" />\n<uses-permission android:name=\"android.permission.BLUETOOTH\" />\n<uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\"/> \n<uses-permission-sdk-23 android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n", "language": "xml" } ] } [/block] [block:callout] { "type": "warning", "body": "As of version 4.3.0 the permission ***WRITE_EXTERNAL_STORAGE*** is not needed anymore. All the data downloaded by the SDK will be stored in the App directory." } [/block] ### ACCESS_NETWORK_STATE (REQUIRED): Allows applications to access information about networks. This used by our SDK to check if the device is connected before we start downloading. ### ACCESS_WIFI_STATE (REQUIRED): This is used by SDK to start the wifi scan and get list of nearby WiFi networks for localization. ### CHANGE_WIFI_STATE(REQUIRED): This is used to turn on WiFi. ### INTERNET (REQUIRED): Allows applications to open network sockets. is required: * to download our building data * to connect to our server and get the list of building ### BLUETOOTH_ADMIN (REQUIRED): This needed for the scan of IBeacons and get the IBeacons Names and to turn Bluethooth on. ### BLUETOOTH (REQUIRED): To perform any Bluetooth communication, such as requesting a connection, accepting a connection. This is needed by our SDK to start iBeacon localisation. ### ACCESS_COARSE_LOCATION (OPTIONAL, REQUIRED FOR Target API 23): Used in cases of need to access GPS, this used by our SDK in case of enabling the GPS parameters settings in MMT (please take a look at our MMT guide for more information). [block:callout] { "type": "warning", "body": "if you are targeting api 23 or above it is required to use ACCESS_FINE_LOCATION permissions or ACCESS_COARSE_LOCATION permissions for BLE scanning." } [/block] ### Services: You have to add this call to our worker service in the manifest: [block:code] { "codes": [ { "code": "<service\n android:name=\"com.customlbs.service.Worker\"\n android:process=\":remote\">\n</service>", "language": "xml" } ] } [/block] [block:callout] { "type": "danger", "title": "RestBatchService and ConnectivityReceiver Removed", "body": "<service android:name=\"com.customlbs.service.rest.batch.RestBatchService\" >\t\t \n</service>\t\t\n\t\t\n<receiver\t\t\n\tandroid:name=\"com.customlbs.service.rest.batch.ConnectivityReceiver\"\t\t\n\tandroid:enabled=\"false\" >\t\t\n\t<intent-filter>\t\t\n\t\t<action android:name=\"android.net.conn.CONNECTIVITY_CHANGE\" />\t\t\n\t</intent-filter>\t\t\n</receiver>\n\nIt was required to have this batch service in the manifest file, starting from v3.5 that is not required anymore." } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b0","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"Beginning with Android 6.0 (API level 23, Marshmallow), users grant certain permissions to apps while the app is running. If you have the target api of your app build set to 23 or your minimum api is set to 23,your app must ask for these run time permissions. You will need to implement proper permission requests for your users who in turn need to grant permission for these so called dangerous permissions. \n\nThe dangerous permissions in the indoors SDK are: \n* **ACCESS_COARSE_LOCATION**\n* **WRITE_EXTERNAL_STORAGE**\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Location Service must be enabled\",\n  \"body\": \"Beware that it is not enough to have the permission for Location access but also the SDK needs to have the location services enabled by the user. Otherwise our SDK cannot search for bluetooth beacons.\"\n}\n[/block]\nBelow you see example code for requesting these permissions from your users:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tprivate void requestPermissionsFromUser() {\\n\\t\\t/**\\n\\t\\t * Since API level 23 we need to request permissions \\n     * for so called dangerous permissions from the user.\\n\\t\\t *\\n\\t\\t * You can see a full list of needed permissions in the Manifest File.\\n\\t\\t */\\n\\t\\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\\n\\t\\t\\tint permissionCheckForStorage = ContextCompat.checkSelfPermission(\\n\\t\\t\\t\\t\\tMainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);\\n\\t\\t\\tint permissionCheckForLocation = ContextCompat.checkSelfPermission(\\n\\t\\t\\t\\t\\tMainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);\\n\\n\\t\\t\\tif (permissionCheckForStorage != PackageManager.PERMISSION_GRANTED\\n\\t\\t\\t\\t\\t|| permissionCheckForLocation != PackageManager.PERMISSION_GRANTED) {\\n\\t\\t\\t\\trequestPermissions(\\n\\t\\t\\t\\t\\t\\tnew String[] {\\n\\t\\t\\t\\t\\t\\t\\t\\tManifest.permission.ACCESS_COARSE_LOCATION,\\n\\t\\t\\t\\t\\t\\t\\t\\tManifest.permission.WRITE_EXTERNAL_STORAGE},\\n\\t\\t\\t\\t\\t\\tREQUEST_CODE_PERMISSIONS);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\t//If permissions were already granted,\\n\\t\\t\\t\\t// we can go on to check if Location Services are enabled.\\n\\t\\t\\t\\tcheckLocationIsEnabled();\\n\\t\\t\\t}\\n\\t\\t} else {\\n\\t\\t\\t//Continue loading Indoors if we don't need user-settable-permissions.\\n\\t\\t\\t// In this case we are pre-Marshmallow.\\n\\t\\t\\tcontinueLoading();\\n\\t\\t}\\n\\t}\\n\\n\\t/**\\n\\t * The Android system calls us back \\n\\t * after the user has granted permissions (or denied them)\\n\\t */\\n\\t@TargetApi(Build.VERSION_CODES.M)\\n\\t@Override\\n\\tpublic void onRequestPermissionsResult(int requestCode, \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t   @NonNull String[] permissions, \\n\\t\\t\\t\\t\\t\\t\\t\\t\\t\\t   @NonNull int[] grantResults) {\\n\\t\\tif (requestCode == REQUEST_CODE_PERMISSIONS) {\\n\\t\\t\\t// Since we have requested multiple permissions, \\n\\t\\t\\t// we need to check if any were denied\\n\\t\\t\\t\\n\\t\\t\\tfor (int grant : grantResults) {\\n\\t\\t\\t\\t\\n\\t\\t\\t\\tif (grant == PackageManager.PERMISSION_DENIED) {\\n\\t\\t\\t\\t\\tif (shouldShowRequestPermissionRationale(\\n\\t\\t\\t\\t\\t\\t\\tManifest.permission.WRITE_EXTERNAL_STORAGE)) {\\n\\t\\t\\t\\t\\t\\t// User has *NOT* allowed us to use WRITE_EXTERNAL_STORAGE\\n\\t\\t\\t\\t\\t\\t// permission on first try. This is the last chance we get \\n\\t\\t\\t\\t\\t\\t// to ask the user, so we explain why we want this permission\\n\\t\\t\\t\\t\\t\\tToast.makeText(this,\\n\\t\\t\\t\\t\\t\\t\\t\\t\\\"External Storage is used for storing map data\\\", \\n\\t\\t\\t\\t\\t\\t\\t\\tToast.LENGTH_SHORT).show();\\n\\t\\t\\t\\t\\t\\t// Re-ask for permission\\n\\t\\t\\t\\t\\t\\trequestPermissionsFromUser();\\n\\t\\t\\t\\t\\t\\treturn;\\n\\t\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\t\\tif (shouldShowRequestPermissionRationale(\\n\\t\\t\\t\\t\\t\\t\\tManifest.permission.ACCESS_COARSE_LOCATION)) {\\n\\t\\t\\t\\t\\t\\t// User has *NOT* allowed us to use ACCESS_COARSE_LOCATION \\n\\t\\t\\t\\t\\t\\t// permission on first try. This is the last chance we get \\n\\t\\t\\t\\t\\t\\t// to ask the user, so we explain why we want this permission\\n\\t\\t\\t\\t\\t\\tToast.makeText(this,\\n\\t\\t\\t\\t\\t\\t\\t\\t\\\"Location is used for Bluetooth location\\\", \\n\\t\\t\\t\\t\\t\\t\\t\\tToast.LENGTH_SHORT).show();\\n\\t\\t\\t\\t\\t\\t// Re-ask for permission\\n\\t\\t\\t\\t\\t\\trequestPermissionsFromUser();\\n\\t\\t\\t\\t\\t\\treturn;\\n\\t\\t\\t\\t\\t}\\n\\n\\t\\t\\t\\t\\t// The user has finally denied us permissions.\\n\\t\\t\\t\\t\\tToast.makeText(this, \\n\\t\\t\\t\\t\\t\\t\\t\\\"Cannot continue without permissions.\\\", \\n\\t\\t\\t\\t\\t\\t\\tToast.LENGTH_SHORT).show();\\n\\t\\t\\t\\t\\tthis.finishAffinity();\\n\\t\\t\\t\\t\\treturn;\\n\\t\\t\\t\\t}\\n\\t\\t\\t}\\n\\t\\t\\tcheckLocationIsEnabled();\\n\\t\\t}\\n\\t}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nHere follows example code which shows how you can tell your users to enable location services.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\tprivate void checkLocationIsEnabled() {\\n\\t\\t// On android Marshmallow we also need to have active Location Services (GPS or Network based)\\n\\t\\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\\n\\t\\t\\tLocationManager locationManager = \\n        (LocationManager) getSystemService(LOCATION_SERVICE);\\n\\t\\t\\tboolean isNetworkLocationProviderEnabled =\\n        locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);\\n\\t\\t\\tboolean isGPSLocationProviderEnabled =\\n        locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);\\n\\n\\t\\t\\tif (!isGPSLocationProviderEnabled && \\n          !isNetworkLocationProviderEnabled) {\\n\\t\\t\\t\\t// Only if both providers are disabled \\n        // we need to ask the user to do something\\n\\t\\t\\t\\tToast.makeText(this, \\n                       \\\"Location is off, enable it in system settings.\\\",\\n                       Toast.LENGTH_LONG).show();\\n\\t\\t\\t\\tIntent locationInSettingsIntent = \\n          new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);\\n\\t\\t\\t\\tthis.startActivityForResult(\\n          locationInSettingsIntent, REQUEST_CODE_LOCATION);\\n\\t\\t\\t} else {\\n\\t\\t\\t\\tcontinueLoading();\\n\\t\\t\\t}\\n\\t\\t} else {\\n\\t\\t\\tcontinueLoading();\\n\\t\\t}\\n\\t}\\n\\n\\t@Override\\n\\tprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\\n\\t\\tif (requestCode == REQUEST_CODE_LOCATION) {\\n\\t\\t\\t// Check if the user has really enabled Location services.\\n\\t\\t\\tcheckLocationIsEnabled();\\n\\t\\t}\\n\\t}\\n\\n// At this point we can continue to load \\n// the Indoo.rs SDK as we did with previous\\n// android versions\\n\\tprivate void continueLoading() {\\n\\t\\tIndoorsFactory.Builder indoorsBuilder = initializeIndoorsLibrary();\\n\\t\\tindoorsSurfaceFragment = initializeIndoorsSurface(indoorsBuilder);\\n\\t\\tsetSurfaceFragment(indoorsSurfaceFragment);\\n\\t}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nFor the rest of the code consult the sample app [which you can find in the Downloads and Documentation section on my.indoo.rs](https://my.indoo.rs/#/tools)","category":"57e3bcc2378b341700c82091","createdAt":"2016-06-06T16:46:54.831Z","excerpt":"for Android 6, API 23, Marshmallow","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":15,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"runtime-permissions","sync_unique":"","title":"Runtime Permissions","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Runtime Permissions

for Android 6, API 23, Marshmallow

Beginning with Android 6.0 (API level 23, Marshmallow), users grant certain permissions to apps while the app is running. If you have the target api of your app build set to 23 or your minimum api is set to 23,your app must ask for these run time permissions. You will need to implement proper permission requests for your users who in turn need to grant permission for these so called dangerous permissions. The dangerous permissions in the indoors SDK are: * **ACCESS_COARSE_LOCATION** * **WRITE_EXTERNAL_STORAGE** [block:callout] { "type": "warning", "title": "Location Service must be enabled", "body": "Beware that it is not enough to have the permission for Location access but also the SDK needs to have the location services enabled by the user. Otherwise our SDK cannot search for bluetooth beacons." } [/block] Below you see example code for requesting these permissions from your users: [block:code] { "codes": [ { "code": "\tprivate void requestPermissionsFromUser() {\n\t\t/**\n\t\t * Since API level 23 we need to request permissions \n * for so called dangerous permissions from the user.\n\t\t *\n\t\t * You can see a full list of needed permissions in the Manifest File.\n\t\t */\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n\t\t\tint permissionCheckForStorage = ContextCompat.checkSelfPermission(\n\t\t\t\t\tMainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);\n\t\t\tint permissionCheckForLocation = ContextCompat.checkSelfPermission(\n\t\t\t\t\tMainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);\n\n\t\t\tif (permissionCheckForStorage != PackageManager.PERMISSION_GRANTED\n\t\t\t\t\t|| permissionCheckForLocation != PackageManager.PERMISSION_GRANTED) {\n\t\t\t\trequestPermissions(\n\t\t\t\t\t\tnew String[] {\n\t\t\t\t\t\t\t\tManifest.permission.ACCESS_COARSE_LOCATION,\n\t\t\t\t\t\t\t\tManifest.permission.WRITE_EXTERNAL_STORAGE},\n\t\t\t\t\t\tREQUEST_CODE_PERMISSIONS);\n\t\t\t} else {\n\t\t\t\t//If permissions were already granted,\n\t\t\t\t// we can go on to check if Location Services are enabled.\n\t\t\t\tcheckLocationIsEnabled();\n\t\t\t}\n\t\t} else {\n\t\t\t//Continue loading Indoors if we don't need user-settable-permissions.\n\t\t\t// In this case we are pre-Marshmallow.\n\t\t\tcontinueLoading();\n\t\t}\n\t}\n\n\t/**\n\t * The Android system calls us back \n\t * after the user has granted permissions (or denied them)\n\t */\n\t@TargetApi(Build.VERSION_CODES.M)\n\t@Override\n\tpublic void onRequestPermissionsResult(int requestCode, \n\t\t\t\t\t\t\t\t\t\t @NonNull String[] permissions, \n\t\t\t\t\t\t\t\t\t\t @NonNull int[] grantResults) {\n\t\tif (requestCode == REQUEST_CODE_PERMISSIONS) {\n\t\t\t// Since we have requested multiple permissions, \n\t\t\t// we need to check if any were denied\n\t\t\t\n\t\t\tfor (int grant : grantResults) {\n\t\t\t\t\n\t\t\t\tif (grant == PackageManager.PERMISSION_DENIED) {\n\t\t\t\t\tif (shouldShowRequestPermissionRationale(\n\t\t\t\t\t\t\tManifest.permission.WRITE_EXTERNAL_STORAGE)) {\n\t\t\t\t\t\t// User has *NOT* allowed us to use WRITE_EXTERNAL_STORAGE\n\t\t\t\t\t\t// permission on first try. This is the last chance we get \n\t\t\t\t\t\t// to ask the user, so we explain why we want this permission\n\t\t\t\t\t\tToast.makeText(this,\n\t\t\t\t\t\t\t\t\"External Storage is used for storing map data\", \n\t\t\t\t\t\t\t\tToast.LENGTH_SHORT).show();\n\t\t\t\t\t\t// Re-ask for permission\n\t\t\t\t\t\trequestPermissionsFromUser();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shouldShowRequestPermissionRationale(\n\t\t\t\t\t\t\tManifest.permission.ACCESS_COARSE_LOCATION)) {\n\t\t\t\t\t\t// User has *NOT* allowed us to use ACCESS_COARSE_LOCATION \n\t\t\t\t\t\t// permission on first try. This is the last chance we get \n\t\t\t\t\t\t// to ask the user, so we explain why we want this permission\n\t\t\t\t\t\tToast.makeText(this,\n\t\t\t\t\t\t\t\t\"Location is used for Bluetooth location\", \n\t\t\t\t\t\t\t\tToast.LENGTH_SHORT).show();\n\t\t\t\t\t\t// Re-ask for permission\n\t\t\t\t\t\trequestPermissionsFromUser();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// The user has finally denied us permissions.\n\t\t\t\t\tToast.makeText(this, \n\t\t\t\t\t\t\t\"Cannot continue without permissions.\", \n\t\t\t\t\t\t\tToast.LENGTH_SHORT).show();\n\t\t\t\t\tthis.finishAffinity();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcheckLocationIsEnabled();\n\t\t}\n\t}", "language": "java" } ] } [/block] Here follows example code which shows how you can tell your users to enable location services. [block:code] { "codes": [ { "code": "\tprivate void checkLocationIsEnabled() {\n\t\t// On android Marshmallow we also need to have active Location Services (GPS or Network based)\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n\t\t\tLocationManager locationManager = \n (LocationManager) getSystemService(LOCATION_SERVICE);\n\t\t\tboolean isNetworkLocationProviderEnabled =\n locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);\n\t\t\tboolean isGPSLocationProviderEnabled =\n locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);\n\n\t\t\tif (!isGPSLocationProviderEnabled && \n !isNetworkLocationProviderEnabled) {\n\t\t\t\t// Only if both providers are disabled \n // we need to ask the user to do something\n\t\t\t\tToast.makeText(this, \n \"Location is off, enable it in system settings.\",\n Toast.LENGTH_LONG).show();\n\t\t\t\tIntent locationInSettingsIntent = \n new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);\n\t\t\t\tthis.startActivityForResult(\n locationInSettingsIntent, REQUEST_CODE_LOCATION);\n\t\t\t} else {\n\t\t\t\tcontinueLoading();\n\t\t\t}\n\t\t} else {\n\t\t\tcontinueLoading();\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\n\t\tif (requestCode == REQUEST_CODE_LOCATION) {\n\t\t\t// Check if the user has really enabled Location services.\n\t\t\tcheckLocationIsEnabled();\n\t\t}\n\t}\n\n// At this point we can continue to load \n// the Indoo.rs SDK as we did with previous\n// android versions\n\tprivate void continueLoading() {\n\t\tIndoorsFactory.Builder indoorsBuilder = initializeIndoorsLibrary();\n\t\tindoorsSurfaceFragment = initializeIndoorsSurface(indoorsBuilder);\n\t\tsetSurfaceFragment(indoorsSurfaceFragment);\n\t}", "language": "java" } ] } [/block] For the rest of the code consult the sample app [which you can find in the Downloads and Documentation section on my.indoo.rs](https://my.indoo.rs/#/tools)
Beginning with Android 6.0 (API level 23, Marshmallow), users grant certain permissions to apps while the app is running. If you have the target api of your app build set to 23 or your minimum api is set to 23,your app must ask for these run time permissions. You will need to implement proper permission requests for your users who in turn need to grant permission for these so called dangerous permissions. The dangerous permissions in the indoors SDK are: * **ACCESS_COARSE_LOCATION** * **WRITE_EXTERNAL_STORAGE** [block:callout] { "type": "warning", "title": "Location Service must be enabled", "body": "Beware that it is not enough to have the permission for Location access but also the SDK needs to have the location services enabled by the user. Otherwise our SDK cannot search for bluetooth beacons." } [/block] Below you see example code for requesting these permissions from your users: [block:code] { "codes": [ { "code": "\tprivate void requestPermissionsFromUser() {\n\t\t/**\n\t\t * Since API level 23 we need to request permissions \n * for so called dangerous permissions from the user.\n\t\t *\n\t\t * You can see a full list of needed permissions in the Manifest File.\n\t\t */\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n\t\t\tint permissionCheckForStorage = ContextCompat.checkSelfPermission(\n\t\t\t\t\tMainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE);\n\t\t\tint permissionCheckForLocation = ContextCompat.checkSelfPermission(\n\t\t\t\t\tMainActivity.this, Manifest.permission.ACCESS_COARSE_LOCATION);\n\n\t\t\tif (permissionCheckForStorage != PackageManager.PERMISSION_GRANTED\n\t\t\t\t\t|| permissionCheckForLocation != PackageManager.PERMISSION_GRANTED) {\n\t\t\t\trequestPermissions(\n\t\t\t\t\t\tnew String[] {\n\t\t\t\t\t\t\t\tManifest.permission.ACCESS_COARSE_LOCATION,\n\t\t\t\t\t\t\t\tManifest.permission.WRITE_EXTERNAL_STORAGE},\n\t\t\t\t\t\tREQUEST_CODE_PERMISSIONS);\n\t\t\t} else {\n\t\t\t\t//If permissions were already granted,\n\t\t\t\t// we can go on to check if Location Services are enabled.\n\t\t\t\tcheckLocationIsEnabled();\n\t\t\t}\n\t\t} else {\n\t\t\t//Continue loading Indoors if we don't need user-settable-permissions.\n\t\t\t// In this case we are pre-Marshmallow.\n\t\t\tcontinueLoading();\n\t\t}\n\t}\n\n\t/**\n\t * The Android system calls us back \n\t * after the user has granted permissions (or denied them)\n\t */\n\t@TargetApi(Build.VERSION_CODES.M)\n\t@Override\n\tpublic void onRequestPermissionsResult(int requestCode, \n\t\t\t\t\t\t\t\t\t\t @NonNull String[] permissions, \n\t\t\t\t\t\t\t\t\t\t @NonNull int[] grantResults) {\n\t\tif (requestCode == REQUEST_CODE_PERMISSIONS) {\n\t\t\t// Since we have requested multiple permissions, \n\t\t\t// we need to check if any were denied\n\t\t\t\n\t\t\tfor (int grant : grantResults) {\n\t\t\t\t\n\t\t\t\tif (grant == PackageManager.PERMISSION_DENIED) {\n\t\t\t\t\tif (shouldShowRequestPermissionRationale(\n\t\t\t\t\t\t\tManifest.permission.WRITE_EXTERNAL_STORAGE)) {\n\t\t\t\t\t\t// User has *NOT* allowed us to use WRITE_EXTERNAL_STORAGE\n\t\t\t\t\t\t// permission on first try. This is the last chance we get \n\t\t\t\t\t\t// to ask the user, so we explain why we want this permission\n\t\t\t\t\t\tToast.makeText(this,\n\t\t\t\t\t\t\t\t\"External Storage is used for storing map data\", \n\t\t\t\t\t\t\t\tToast.LENGTH_SHORT).show();\n\t\t\t\t\t\t// Re-ask for permission\n\t\t\t\t\t\trequestPermissionsFromUser();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif (shouldShowRequestPermissionRationale(\n\t\t\t\t\t\t\tManifest.permission.ACCESS_COARSE_LOCATION)) {\n\t\t\t\t\t\t// User has *NOT* allowed us to use ACCESS_COARSE_LOCATION \n\t\t\t\t\t\t// permission on first try. This is the last chance we get \n\t\t\t\t\t\t// to ask the user, so we explain why we want this permission\n\t\t\t\t\t\tToast.makeText(this,\n\t\t\t\t\t\t\t\t\"Location is used for Bluetooth location\", \n\t\t\t\t\t\t\t\tToast.LENGTH_SHORT).show();\n\t\t\t\t\t\t// Re-ask for permission\n\t\t\t\t\t\trequestPermissionsFromUser();\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\t// The user has finally denied us permissions.\n\t\t\t\t\tToast.makeText(this, \n\t\t\t\t\t\t\t\"Cannot continue without permissions.\", \n\t\t\t\t\t\t\tToast.LENGTH_SHORT).show();\n\t\t\t\t\tthis.finishAffinity();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcheckLocationIsEnabled();\n\t\t}\n\t}", "language": "java" } ] } [/block] Here follows example code which shows how you can tell your users to enable location services. [block:code] { "codes": [ { "code": "\tprivate void checkLocationIsEnabled() {\n\t\t// On android Marshmallow we also need to have active Location Services (GPS or Network based)\n\t\tif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n\t\t\tLocationManager locationManager = \n (LocationManager) getSystemService(LOCATION_SERVICE);\n\t\t\tboolean isNetworkLocationProviderEnabled =\n locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);\n\t\t\tboolean isGPSLocationProviderEnabled =\n locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);\n\n\t\t\tif (!isGPSLocationProviderEnabled && \n !isNetworkLocationProviderEnabled) {\n\t\t\t\t// Only if both providers are disabled \n // we need to ask the user to do something\n\t\t\t\tToast.makeText(this, \n \"Location is off, enable it in system settings.\",\n Toast.LENGTH_LONG).show();\n\t\t\t\tIntent locationInSettingsIntent = \n new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);\n\t\t\t\tthis.startActivityForResult(\n locationInSettingsIntent, REQUEST_CODE_LOCATION);\n\t\t\t} else {\n\t\t\t\tcontinueLoading();\n\t\t\t}\n\t\t} else {\n\t\t\tcontinueLoading();\n\t\t}\n\t}\n\n\t@Override\n\tprotected void onActivityResult(int requestCode, int resultCode, Intent data) {\n\t\tif (requestCode == REQUEST_CODE_LOCATION) {\n\t\t\t// Check if the user has really enabled Location services.\n\t\t\tcheckLocationIsEnabled();\n\t\t}\n\t}\n\n// At this point we can continue to load \n// the Indoo.rs SDK as we did with previous\n// android versions\n\tprivate void continueLoading() {\n\t\tIndoorsFactory.Builder indoorsBuilder = initializeIndoorsLibrary();\n\t\tindoorsSurfaceFragment = initializeIndoorsSurface(indoorsBuilder);\n\t\tsetSurfaceFragment(indoorsSurfaceFragment);\n\t}", "language": "java" } ] } [/block] For the rest of the code consult the sample app [which you can find in the Downloads and Documentation section on my.indoo.rs](https://my.indoo.rs/#/tools)
{"__v":0,"_id":"57e3bcc2378b341700c820b1","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"This is useful in case you don't want to start localization, but you want to show the Indoors Fragment.\n\n  \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsBuilder.setRunLocalization(false);\\n\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nBy calling **setRunLocalization**  with **false** parameter  method you can still get the Indoors Fragment with your map displayed on it, but without showing your position on the map, in this case you don't need to use the Bluetooth and WIFI permissions (mentioned in the previous section).\n\n\nHere is a full example for **onCreate** method: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"package com.mycompany.myfirstindoorsapp;\\n \\nimport android.os.Bundle;\\nimport android.support.v4.app.FragmentActivity;\\nimport android.support.v4.app.FragmentTransaction;\\n \\nimport com.customlbs.surface.library.IndoorsSurfaceFactory;\\nimport com.customlbs.surface.library.IndoorsSurfaceFragment;\\n \\npublic class MainActivity extends FragmentActivity implements IndoorsLocationListener{\\n  @Override\\n  protected void onCreate(Bundle savedInstanceState) {\\n    super.onCreate(savedInstanceState);\\n\\n    IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\\n    IndoorsSurfaceFactory.Builder surfaceBuilder = new    \\t\\t IndoorsSurfaceFactory.Builder();\\n    indoorsBuilder.setContext(this);\\n    // TODO: replace this with your API-key\\n    indoorsBuilder.setApiKey(\\\"YOUR-API-KEY\\\");\\n    // TODO: replace 12345 with the id of the building you uploaded to\\n    // our cloud using the MMT\\n    indoorsBuilder.setBuildingId((long) 12345);\\n    // stop localisation in this case you don't the wifi and bluethooth  permissions in manifest.\\n    indoorsBuilder.setRunLocalization(false);\\n\\n    surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\\n\\n    IndoorsSurfaceFragment indoorsFragment = surfaceBuilder.build();\\n\\n    FragmentTransaction transaction =    getSupportFragmentManager().beginTransaction();\\n    transaction.add(android.R.id.content, indoorsFragment, \\\"indoors\\\");\\n    transaction.commit();\\n  }\\n} \\n......\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n\n\n##Manifest:\nIn this case the Manifest permissions you need are: \n**you don t need to add those if you are using aar** \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<uses-permission android:name=\\\"android.permission.WRITE_EXTERNAL_STORAGE\\\" />\\n<uses-permission android:name=\\\"android.permission.INTERNET\\\" />\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"By default localization is turned on, calling the method **IndoorsFactory.createInstance** (to connect to our service) before the **setRunLocalization** with false parameter  will still require the manifest permissions as described in the previous section.\\n\\n**the only way to stop localization is using the  method indoorsBuilder.setRunLocalization(false);\\n**\",\n  \"title\": \"Stopping Localisation\"\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-07-14T17:21:36.504Z","excerpt":"This section describes the usage of Indoors Fragment without starting localization","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":16,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"ui-without-localisation","sync_unique":"","title":"UI Without Localization","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

UI Without Localization

This section describes the usage of Indoors Fragment without starting localization

This is useful in case you don't want to start localization, but you want to show the Indoors Fragment. [block:code] { "codes": [ { "code": "indoorsBuilder.setRunLocalization(false);\n", "language": "java" } ] } [/block] By calling **setRunLocalization** with **false** parameter method you can still get the Indoors Fragment with your map displayed on it, but without showing your position on the map, in this case you don't need to use the Bluetooth and WIFI permissions (mentioned in the previous section). Here is a full example for **onCreate** method: [block:code] { "codes": [ { "code": "package com.mycompany.myfirstindoorsapp;\n \nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentTransaction;\n \nimport com.customlbs.surface.library.IndoorsSurfaceFactory;\nimport com.customlbs.surface.library.IndoorsSurfaceFragment;\n \npublic class MainActivity extends FragmentActivity implements IndoorsLocationListener{\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new \t\t IndoorsSurfaceFactory.Builder();\n indoorsBuilder.setContext(this);\n // TODO: replace this with your API-key\n indoorsBuilder.setApiKey(\"YOUR-API-KEY\");\n // TODO: replace 12345 with the id of the building you uploaded to\n // our cloud using the MMT\n indoorsBuilder.setBuildingId((long) 12345);\n // stop localisation in this case you don't the wifi and bluethooth permissions in manifest.\n indoorsBuilder.setRunLocalization(false);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n IndoorsSurfaceFragment indoorsFragment = surfaceBuilder.build();\n\n FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n transaction.add(android.R.id.content, indoorsFragment, \"indoors\");\n transaction.commit();\n }\n} \n......", "language": "java" } ] } [/block] ##Manifest: In this case the Manifest permissions you need are: **you don t need to add those if you are using aar** [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n<uses-permission android:name=\"android.permission.INTERNET\" />", "language": "xml" } ] } [/block] [block:callout] { "type": "warning", "body": "By default localization is turned on, calling the method **IndoorsFactory.createInstance** (to connect to our service) before the **setRunLocalization** with false parameter will still require the manifest permissions as described in the previous section.\n\n**the only way to stop localization is using the method indoorsBuilder.setRunLocalization(false);\n**", "title": "Stopping Localisation" } [/block]
This is useful in case you don't want to start localization, but you want to show the Indoors Fragment. [block:code] { "codes": [ { "code": "indoorsBuilder.setRunLocalization(false);\n", "language": "java" } ] } [/block] By calling **setRunLocalization** with **false** parameter method you can still get the Indoors Fragment with your map displayed on it, but without showing your position on the map, in this case you don't need to use the Bluetooth and WIFI permissions (mentioned in the previous section). Here is a full example for **onCreate** method: [block:code] { "codes": [ { "code": "package com.mycompany.myfirstindoorsapp;\n \nimport android.os.Bundle;\nimport android.support.v4.app.FragmentActivity;\nimport android.support.v4.app.FragmentTransaction;\n \nimport com.customlbs.surface.library.IndoorsSurfaceFactory;\nimport com.customlbs.surface.library.IndoorsSurfaceFragment;\n \npublic class MainActivity extends FragmentActivity implements IndoorsLocationListener{\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n super.onCreate(savedInstanceState);\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new \t\t IndoorsSurfaceFactory.Builder();\n indoorsBuilder.setContext(this);\n // TODO: replace this with your API-key\n indoorsBuilder.setApiKey(\"YOUR-API-KEY\");\n // TODO: replace 12345 with the id of the building you uploaded to\n // our cloud using the MMT\n indoorsBuilder.setBuildingId((long) 12345);\n // stop localisation in this case you don't the wifi and bluethooth permissions in manifest.\n indoorsBuilder.setRunLocalization(false);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n IndoorsSurfaceFragment indoorsFragment = surfaceBuilder.build();\n\n FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n transaction.add(android.R.id.content, indoorsFragment, \"indoors\");\n transaction.commit();\n }\n} \n......", "language": "java" } ] } [/block] ##Manifest: In this case the Manifest permissions you need are: **you don t need to add those if you are using aar** [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n<uses-permission android:name=\"android.permission.INTERNET\" />", "language": "xml" } ] } [/block] [block:callout] { "type": "warning", "body": "By default localization is turned on, calling the method **IndoorsFactory.createInstance** (to connect to our service) before the **setRunLocalization** with false parameter will still require the manifest permissions as described in the previous section.\n\n**the only way to stop localization is using the method indoorsBuilder.setRunLocalization(false);\n**", "title": "Stopping Localisation" } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b2","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"1. Start Localisation\"\n}\n[/block]\nTo start the localisation calculations on the localisation engine and GPS. \nif you need GPS please don t forget to add the **ACCESS_FINE_LOCATION** permission in Manifest and adding GPS fallback parameters in MMT. \n\nTo register location listener you can call: \n\n # registerLocationListener method:\nAs described in   [Localization without UI](doc:localisation-without-ui)\n\n**After being connected to indoors service you  can start or stop localiastion** \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class MainActivity implements IndoorsLocationListener {\\n  // this should only be called after being connected to indoors service \\n  .....\\n  void addLocationListner(){\\n    \\n  Indoors indoors = IndoorsFactory.getInstance()  \\n  indoors.registerLocationListener(this);\\n    \\n  } \\n  .....\\n  \\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n# setUserInteractionListener method: \n\nAs in the example [Integrating indoo.rs into an existing App](doc:integrating-indoors-into-an-existing-app).\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"public class MainActivity extends FragmentActivity implements IndoorsLocationListener {\\n\\n    @Override\\n    protected void onCreate(Bundle savedInstanceState) {\\n      // ...\\n\\n      IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\\n      IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\\n\\n      // ...\\n\\n      indoorsBuilder.setUserInteractionListener(this);\\n\\n      surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\\n\\n      indoorsFragment = surfaceBuilder.build();\\n     \\n\\t\\tFragmentTransaction transaction =    getSupportFragmentManager().beginTransaction();\\n\\t\\ttransaction.add(android.R.id.content, indoorsFragment, \\\"indoors\\\");\\n\\t\\ttransaction.commit(\\n\\n      // ...\\n    }\\n......\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"2. Stop localisation\"\n}\n[/block]\nTo disable all calculations on the localisation engine and GPS, you must deregister all registered location listeners.\n\nTo unregister locationListner you can call: \n\n # removeLocationListener method:\n\n**After being connected to indoors service you  can start or stop localiastion** \n\nin case you used registerLocationListener \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \" class MainActivity implements IndoorsLocationListener {\\n    // this should only be called after being connected to indoors     service \\n \\n  protected void onStop() {\\n    super.onStop();\\n    stopLocationListner()\\n    IndoorsFactory.releaseInstance(this);\\n  }\\n  void stopLocationListner(){\\n   Indoors indoors = IndoorsFactory.getInstance()  \\n   indoors.removeLocationListner(this);\\n    } \\n  \\n  }\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n# setUserInteractionListener method: \nwhen you kill the app the location Listener is unregistered automatically.\n\n\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"IndoorsLocationListener\",\n  \"body\": \"please note that the method setUserInteractionListener  does the registerLocationListener call automatically (after connecting to the service), use registerLocationListener only if you to add or remove location listener manually,\\nor in case of Localisation without UI.\"\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-08-10T15:10:34.700Z","excerpt":"This describes the method to use when you wish the indoors localisation engine to pause calculations, and cease using GPS if you use GPS in your map.","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":17,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"stopping-and-starting-localisation","sync_unique":"","title":"Stopping and starting localisation","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Stopping and starting localisation

This describes the method to use when you wish the indoors localisation engine to pause calculations, and cease using GPS if you use GPS in your map.

[block:api-header] { "type": "basic", "title": "1. Start Localisation" } [/block] To start the localisation calculations on the localisation engine and GPS. if you need GPS please don t forget to add the **ACCESS_FINE_LOCATION** permission in Manifest and adding GPS fallback parameters in MMT. To register location listener you can call: # registerLocationListener method: As described in [Localization without UI](doc:localisation-without-ui) **After being connected to indoors service you can start or stop localiastion** [block:code] { "codes": [ { "code": "class MainActivity implements IndoorsLocationListener {\n // this should only be called after being connected to indoors service \n .....\n void addLocationListner(){\n \n Indoors indoors = IndoorsFactory.getInstance() \n indoors.registerLocationListener(this);\n \n } \n .....\n \n}", "language": "java" } ] } [/block] # setUserInteractionListener method: As in the example [Integrating indoo.rs into an existing App](doc:integrating-indoors-into-an-existing-app). [block:code] { "codes": [ { "code": "public class MainActivity extends FragmentActivity implements IndoorsLocationListener {\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n // ...\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\n\n // ...\n\n indoorsBuilder.setUserInteractionListener(this);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n indoorsFragment = surfaceBuilder.build();\n \n\t\tFragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n\t\ttransaction.add(android.R.id.content, indoorsFragment, \"indoors\");\n\t\ttransaction.commit(\n\n // ...\n }\n......", "language": "java" } ] } [/block] [block:api-header] { "type": "basic", "title": "2. Stop localisation" } [/block] To disable all calculations on the localisation engine and GPS, you must deregister all registered location listeners. To unregister locationListner you can call: # removeLocationListener method: **After being connected to indoors service you can start or stop localiastion** in case you used registerLocationListener [block:code] { "codes": [ { "code": " class MainActivity implements IndoorsLocationListener {\n // this should only be called after being connected to indoors service \n \n protected void onStop() {\n super.onStop();\n stopLocationListner()\n IndoorsFactory.releaseInstance(this);\n }\n void stopLocationListner(){\n Indoors indoors = IndoorsFactory.getInstance() \n indoors.removeLocationListner(this);\n } \n \n }", "language": "java" } ] } [/block] # setUserInteractionListener method: when you kill the app the location Listener is unregistered automatically. [block:callout] { "type": "danger", "title": "IndoorsLocationListener", "body": "please note that the method setUserInteractionListener does the registerLocationListener call automatically (after connecting to the service), use registerLocationListener only if you to add or remove location listener manually,\nor in case of Localisation without UI." } [/block]
[block:api-header] { "type": "basic", "title": "1. Start Localisation" } [/block] To start the localisation calculations on the localisation engine and GPS. if you need GPS please don t forget to add the **ACCESS_FINE_LOCATION** permission in Manifest and adding GPS fallback parameters in MMT. To register location listener you can call: # registerLocationListener method: As described in [Localization without UI](doc:localisation-without-ui) **After being connected to indoors service you can start or stop localiastion** [block:code] { "codes": [ { "code": "class MainActivity implements IndoorsLocationListener {\n // this should only be called after being connected to indoors service \n .....\n void addLocationListner(){\n \n Indoors indoors = IndoorsFactory.getInstance() \n indoors.registerLocationListener(this);\n \n } \n .....\n \n}", "language": "java" } ] } [/block] # setUserInteractionListener method: As in the example [Integrating indoo.rs into an existing App](doc:integrating-indoors-into-an-existing-app). [block:code] { "codes": [ { "code": "public class MainActivity extends FragmentActivity implements IndoorsLocationListener {\n\n @Override\n protected void onCreate(Bundle savedInstanceState) {\n // ...\n\n IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n IndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\n\n // ...\n\n indoorsBuilder.setUserInteractionListener(this);\n\n surfaceBuilder.setIndoorsBuilder(indoorsBuilder);\n\n indoorsFragment = surfaceBuilder.build();\n \n\t\tFragmentTransaction transaction = getSupportFragmentManager().beginTransaction();\n\t\ttransaction.add(android.R.id.content, indoorsFragment, \"indoors\");\n\t\ttransaction.commit(\n\n // ...\n }\n......", "language": "java" } ] } [/block] [block:api-header] { "type": "basic", "title": "2. Stop localisation" } [/block] To disable all calculations on the localisation engine and GPS, you must deregister all registered location listeners. To unregister locationListner you can call: # removeLocationListener method: **After being connected to indoors service you can start or stop localiastion** in case you used registerLocationListener [block:code] { "codes": [ { "code": " class MainActivity implements IndoorsLocationListener {\n // this should only be called after being connected to indoors service \n \n protected void onStop() {\n super.onStop();\n stopLocationListner()\n IndoorsFactory.releaseInstance(this);\n }\n void stopLocationListner(){\n Indoors indoors = IndoorsFactory.getInstance() \n indoors.removeLocationListner(this);\n } \n \n }", "language": "java" } ] } [/block] # setUserInteractionListener method: when you kill the app the location Listener is unregistered automatically. [block:callout] { "type": "danger", "title": "IndoorsLocationListener", "body": "please note that the method setUserInteractionListener does the registerLocationListener call automatically (after connecting to the service), use registerLocationListener only if you to add or remove location listener manually,\nor in case of Localisation without UI." } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b3","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"In some instances the App developer might want to store the current map position and restore it. To get the currently visible area you have to call the method - getVisibleMapRect() on your IndoorsFragment. It will give you a VisibleMapRect object that you can store and later use to call the method - setVisibleMapRectAndUpdateSurface(visibleMapRect) to restore exactly the same spot on the map.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"...\\n\\nVisibleMapRect visibleMapRect = indoorsFragment.getVisibleMapRect();\\n\\n...\\n\\nindoorsFragment.setVisibleMapRectAndUpdateSurface(visibleMapRect);\\n\\n...\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-09-09T12:22:37.468Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":18,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"get-and-set-visible-map-area-android","sync_unique":"","title":"Get and set visible map area (Android)","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Get and set visible map area (Android)


In some instances the App developer might want to store the current map position and restore it. To get the currently visible area you have to call the method - getVisibleMapRect() on your IndoorsFragment. It will give you a VisibleMapRect object that you can store and later use to call the method - setVisibleMapRectAndUpdateSurface(visibleMapRect) to restore exactly the same spot on the map. [block:code] { "codes": [ { "code": "...\n\nVisibleMapRect visibleMapRect = indoorsFragment.getVisibleMapRect();\n\n...\n\nindoorsFragment.setVisibleMapRectAndUpdateSurface(visibleMapRect);\n\n...", "language": "java" } ] } [/block]
In some instances the App developer might want to store the current map position and restore it. To get the currently visible area you have to call the method - getVisibleMapRect() on your IndoorsFragment. It will give you a VisibleMapRect object that you can store and later use to call the method - setVisibleMapRectAndUpdateSurface(visibleMapRect) to restore exactly the same spot on the map. [block:code] { "codes": [ { "code": "...\n\nVisibleMapRect visibleMapRect = indoorsFragment.getVisibleMapRect();\n\n...\n\nindoorsFragment.setVisibleMapRectAndUpdateSurface(visibleMapRect);\n\n...", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b4","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"If you want to tell if the user has interacted with the map you can add a IndoorsSurfaceInteractionCallback while building the IndoorsSurface. \n\nIf you additionally want to capture the position on the map that the user has moved to you can use [Get and set visible map area](doc:get-and-set-visible-map-area-android)\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\t\\t\\tsurfaceBuilder.setIndoorsSurfaceInteractionCallback(new IndoorsSurfaceInteractionCallback() {\\n\\t\\t\\t\\t@Override\\n\\t\\t\\t\\tpublic void onUserInteraction(SurfaceState surfaceStateAfterInteraction) {\\n\\t\\t\\t\\t\\tLog.i(TAG,\\\"User had an interaction with the map\\\" );\\n\\t\\t\\t\\t}\\n\\t\\t\\t});\\n\\n\\n\",\n      \"language\": \"java\"\n    },\n    {\n      \"code\": \"\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-09-11T13:56:40.040Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":19,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"user-interaction-callback","sync_unique":"","title":"User interaction Callback","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

User interaction Callback


If you want to tell if the user has interacted with the map you can add a IndoorsSurfaceInteractionCallback while building the IndoorsSurface. If you additionally want to capture the position on the map that the user has moved to you can use [Get and set visible map area](doc:get-and-set-visible-map-area-android) [block:code] { "codes": [ { "code": "\t\t\tsurfaceBuilder.setIndoorsSurfaceInteractionCallback(new IndoorsSurfaceInteractionCallback() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onUserInteraction(SurfaceState surfaceStateAfterInteraction) {\n\t\t\t\t\tLog.i(TAG,\"User had an interaction with the map\" );\n\t\t\t\t}\n\t\t\t});\n\n\n", "language": "java" }, { "code": "", "language": "text" } ] } [/block]
If you want to tell if the user has interacted with the map you can add a IndoorsSurfaceInteractionCallback while building the IndoorsSurface. If you additionally want to capture the position on the map that the user has moved to you can use [Get and set visible map area](doc:get-and-set-visible-map-area-android) [block:code] { "codes": [ { "code": "\t\t\tsurfaceBuilder.setIndoorsSurfaceInteractionCallback(new IndoorsSurfaceInteractionCallback() {\n\t\t\t\t@Override\n\t\t\t\tpublic void onUserInteraction(SurfaceState surfaceStateAfterInteraction) {\n\t\t\t\t\tLog.i(TAG,\"User had an interaction with the map\" );\n\t\t\t\t}\n\t\t\t});\n\n\n", "language": "java" }, { "code": "", "language": "text" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b5","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"1. SDK current Version\"\n}\n[/block]\nTo get the SDK current Version, after being connected to indoors service, you can call  ***\"getCurrentVersion\"***, the method returns a string with the current SDK version.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoors = IndoorsFactory.getInstance();\\nindoors.getCurrentVersion();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nHere is a full example: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\\nIndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\\nindoorsBuilder.setContext(this);\\n// TODO: replace this with your API-key\\nindoorsBuilder.setApiKey(\\\"API-KEY\\\");\\n// TODO: replace 12345 with the id of the building you uploaded to\\n// our cloud using the MMT\\nindoorsBuilder.setBuildingId((long) 12345);\\n// callback for indoo.rs-events\\nindoorsBuilder.setUserInteractionListener(this);\\nsurfaceBuilder.setIndoorsBuilder(indoorsBuilder);\\nindoorsFragment = surfaceBuilder.build();\\n.......\\nindoors = IndoorsFactory.getInstance();\\nindoors.getCurrentVersion();\\n......\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-09-14T10:22:54.546Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":20,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"sdk-version","sync_unique":"","title":"SDK Version","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

SDK Version


[block:api-header] { "type": "basic", "title": "1. SDK current Version" } [/block] To get the SDK current Version, after being connected to indoors service, you can call ***"getCurrentVersion"***, the method returns a string with the current SDK version. [block:code] { "codes": [ { "code": "indoors = IndoorsFactory.getInstance();\nindoors.getCurrentVersion();", "language": "java" } ] } [/block] Here is a full example: [block:code] { "codes": [ { "code": "IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\nIndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\nindoorsBuilder.setContext(this);\n// TODO: replace this with your API-key\nindoorsBuilder.setApiKey(\"API-KEY\");\n// TODO: replace 12345 with the id of the building you uploaded to\n// our cloud using the MMT\nindoorsBuilder.setBuildingId((long) 12345);\n// callback for indoo.rs-events\nindoorsBuilder.setUserInteractionListener(this);\nsurfaceBuilder.setIndoorsBuilder(indoorsBuilder);\nindoorsFragment = surfaceBuilder.build();\n.......\nindoors = IndoorsFactory.getInstance();\nindoors.getCurrentVersion();\n......", "language": "java" } ] } [/block]
[block:api-header] { "type": "basic", "title": "1. SDK current Version" } [/block] To get the SDK current Version, after being connected to indoors service, you can call ***"getCurrentVersion"***, the method returns a string with the current SDK version. [block:code] { "codes": [ { "code": "indoors = IndoorsFactory.getInstance();\nindoors.getCurrentVersion();", "language": "java" } ] } [/block] Here is a full example: [block:code] { "codes": [ { "code": "IndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\nIndoorsSurfaceFactory.Builder surfaceBuilder = new IndoorsSurfaceFactory.Builder();\nindoorsBuilder.setContext(this);\n// TODO: replace this with your API-key\nindoorsBuilder.setApiKey(\"API-KEY\");\n// TODO: replace 12345 with the id of the building you uploaded to\n// our cloud using the MMT\nindoorsBuilder.setBuildingId((long) 12345);\n// callback for indoo.rs-events\nindoorsBuilder.setUserInteractionListener(this);\nsurfaceBuilder.setIndoorsBuilder(indoorsBuilder);\nindoorsFragment = surfaceBuilder.build();\n.......\nindoors = IndoorsFactory.getInstance();\nindoors.getCurrentVersion();\n......", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b6","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Deleting the download listener while a download is still in progress\",\n  \"body\": \"Note that the download listener has to exist for the entire duration of the download and must not be deleted as this will cause a memory access error.\\nThe download listener can be safely deleted after the download has been completed or cancelled.\"\n}\n[/block]\nYou can cancel already started building download by calling next method:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().cancelBuildingDownload();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThe ***IndoorsLocationListener*** has the *buildingLoadingCanceled*  listener, which is called when building download is canceled. Please take a look at section [Integrating indoo.rs into an existing App](doc:integrating-indoors-into-an-existing-app) Javadoc: [buildingLoadingCanceled](https://my.indoo.rs/javadoc/com/customlbs/library/IndoorsLocationListener.html#buildingLoadingCanceled%28%29)","category":"57e3bcc2378b341700c82091","createdAt":"2016-02-12T10:55:48.211Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":21,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"building-download","sync_unique":"","title":"Building Download","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Building Download


[block:callout] { "type": "danger", "title": "Deleting the download listener while a download is still in progress", "body": "Note that the download listener has to exist for the entire duration of the download and must not be deleted as this will cause a memory access error.\nThe download listener can be safely deleted after the download has been completed or cancelled." } [/block] You can cancel already started building download by calling next method: [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().cancelBuildingDownload();", "language": "java" } ] } [/block] The ***IndoorsLocationListener*** has the *buildingLoadingCanceled* listener, which is called when building download is canceled. Please take a look at section [Integrating indoo.rs into an existing App](doc:integrating-indoors-into-an-existing-app) Javadoc: [buildingLoadingCanceled](https://my.indoo.rs/javadoc/com/customlbs/library/IndoorsLocationListener.html#buildingLoadingCanceled%28%29)
[block:callout] { "type": "danger", "title": "Deleting the download listener while a download is still in progress", "body": "Note that the download listener has to exist for the entire duration of the download and must not be deleted as this will cause a memory access error.\nThe download listener can be safely deleted after the download has been completed or cancelled." } [/block] You can cancel already started building download by calling next method: [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().cancelBuildingDownload();", "language": "java" } ] } [/block] The ***IndoorsLocationListener*** has the *buildingLoadingCanceled* listener, which is called when building download is canceled. Please take a look at section [Integrating indoo.rs into an existing App](doc:integrating-indoors-into-an-existing-app) Javadoc: [buildingLoadingCanceled](https://my.indoo.rs/javadoc/com/customlbs/library/IndoorsLocationListener.html#buildingLoadingCanceled%28%29)
{"__v":0,"_id":"57e3bcc2378b341700c820b7","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"If you have a special need for customizing the background color around the map in the IndoorsSurface, you can set it to be a color you provide with the following lines of code which will generate a *SurfacePainterConfiguration*, based on the *DefaultSurfacePainterConfiguration*, that is then applied to the *IndoorsSurfaceFactory.Builder* object, just before the *.build()* method is called to get the *IndoorsFragment*. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"\\n\\t\\tSurfacePainterConfiguration.PaintConfiguration noTilePaintConfiguration = new SurfacePainterConfiguration.PaintConfiguration();\\n\\t\\tnoTilePaintConfiguration.setColor(Color.parseColor(\\\"#ff0000ff\\\"));\\n\\t\\tnoTilePaintConfiguration.setStyle(Paint.Style.valueOf(\\\"FILL\\\"));\\n\\t\\tnoTilePaintConfiguration.setAntiAlias(false);\\n\\n\\t\\tSurfacePainterConfiguration surfacePainterConfiguration = DefaultSurfacePainterConfiguration.getConfiguration();\\n\\t\\tsurfacePainterConfiguration.setNoTilePaintConfiguration(noTilePaintConfiguration);\\n\\n\\t\\tsurfaceBuilder.setSurfacePainterConfiguration(surfacePainterConfiguration);\\n\\n\\t\\tindoorsFragment = surfaceBuilder.build();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2015-11-03T14:19:54.685Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":22,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"changing-the-background-color-of-the-map","sync_unique":"","title":"Changing the background color of the map","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Changing the background color of the map


If you have a special need for customizing the background color around the map in the IndoorsSurface, you can set it to be a color you provide with the following lines of code which will generate a *SurfacePainterConfiguration*, based on the *DefaultSurfacePainterConfiguration*, that is then applied to the *IndoorsSurfaceFactory.Builder* object, just before the *.build()* method is called to get the *IndoorsFragment*. [block:code] { "codes": [ { "code": "\n\t\tSurfacePainterConfiguration.PaintConfiguration noTilePaintConfiguration = new SurfacePainterConfiguration.PaintConfiguration();\n\t\tnoTilePaintConfiguration.setColor(Color.parseColor(\"#ff0000ff\"));\n\t\tnoTilePaintConfiguration.setStyle(Paint.Style.valueOf(\"FILL\"));\n\t\tnoTilePaintConfiguration.setAntiAlias(false);\n\n\t\tSurfacePainterConfiguration surfacePainterConfiguration = DefaultSurfacePainterConfiguration.getConfiguration();\n\t\tsurfacePainterConfiguration.setNoTilePaintConfiguration(noTilePaintConfiguration);\n\n\t\tsurfaceBuilder.setSurfacePainterConfiguration(surfacePainterConfiguration);\n\n\t\tindoorsFragment = surfaceBuilder.build();", "language": "java" } ] } [/block]
If you have a special need for customizing the background color around the map in the IndoorsSurface, you can set it to be a color you provide with the following lines of code which will generate a *SurfacePainterConfiguration*, based on the *DefaultSurfacePainterConfiguration*, that is then applied to the *IndoorsSurfaceFactory.Builder* object, just before the *.build()* method is called to get the *IndoorsFragment*. [block:code] { "codes": [ { "code": "\n\t\tSurfacePainterConfiguration.PaintConfiguration noTilePaintConfiguration = new SurfacePainterConfiguration.PaintConfiguration();\n\t\tnoTilePaintConfiguration.setColor(Color.parseColor(\"#ff0000ff\"));\n\t\tnoTilePaintConfiguration.setStyle(Paint.Style.valueOf(\"FILL\"));\n\t\tnoTilePaintConfiguration.setAntiAlias(false);\n\n\t\tSurfacePainterConfiguration surfacePainterConfiguration = DefaultSurfacePainterConfiguration.getConfiguration();\n\t\tsurfacePainterConfiguration.setNoTilePaintConfiguration(noTilePaintConfiguration);\n\n\t\tsurfaceBuilder.setSurfacePainterConfiguration(surfacePainterConfiguration);\n\n\t\tindoorsFragment = surfaceBuilder.build();", "language": "java" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820b9","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"The **Kalman filter** is used to improve localisation accuracy for certain setups. Contact support@indoo.rs to get more information about your venue. By default this filter is enabled for every building.\n\nThe **Stabilisation filter** is used to reduce user location jumps when you are not walking. You can also set the time, representing how long it takes for the stabilisation filter to kick in. The minimum value is 4000 ms, maximum is 20000 ms.\n\nBefore connecting to the indoors service, as a first step add the following parameters:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"LocalizationParameters parameters = new LocalizationParameters(); \\t\\t  \\nparameters.setUseKalmanStrategy(false);\\t\\t \\nparameters.setUseStabilizationFilter(false);\\t\\t\\nparameters.setStabilizationFilterTime(4000); //4000 milliseconds 4s\\nIndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\\n....\\nindoorsBuilder.setLocalizationParameters(parameters);\\n...\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Default Values\",\n  \"body\": \"By default the Kalman and Stabilization filter are enabled and Stabilization filter time is 4 seconds (the maximum value is 20 seconds).\"\n}\n[/block]","category":"57e3bcc2378b341700c82091","createdAt":"2016-03-24T17:21:42.922Z","excerpt":"This section describes how to configure the localization parameters for stabilization filter and kalman filter in indoors.","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":24,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"using-stabilization-filter-and-kalman-filter","sync_unique":"","title":"Using Kalman and Stabilisation Filter","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Using Kalman and Stabilisation Filter

This section describes how to configure the localization parameters for stabilization filter and kalman filter in indoors.

The **Kalman filter** is used to improve localisation accuracy for certain setups. Contact support@indoo.rs to get more information about your venue. By default this filter is enabled for every building. The **Stabilisation filter** is used to reduce user location jumps when you are not walking. You can also set the time, representing how long it takes for the stabilisation filter to kick in. The minimum value is 4000 ms, maximum is 20000 ms. Before connecting to the indoors service, as a first step add the following parameters: [block:code] { "codes": [ { "code": "LocalizationParameters parameters = new LocalizationParameters(); \t\t \nparameters.setUseKalmanStrategy(false);\t\t \nparameters.setUseStabilizationFilter(false);\t\t\nparameters.setStabilizationFilterTime(4000); //4000 milliseconds 4s\nIndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n....\nindoorsBuilder.setLocalizationParameters(parameters);\n...", "language": "java" } ] } [/block] [block:callout] { "type": "warning", "title": "Default Values", "body": "By default the Kalman and Stabilization filter are enabled and Stabilization filter time is 4 seconds (the maximum value is 20 seconds)." } [/block]
The **Kalman filter** is used to improve localisation accuracy for certain setups. Contact support@indoo.rs to get more information about your venue. By default this filter is enabled for every building. The **Stabilisation filter** is used to reduce user location jumps when you are not walking. You can also set the time, representing how long it takes for the stabilisation filter to kick in. The minimum value is 4000 ms, maximum is 20000 ms. Before connecting to the indoors service, as a first step add the following parameters: [block:code] { "codes": [ { "code": "LocalizationParameters parameters = new LocalizationParameters(); \t\t \nparameters.setUseKalmanStrategy(false);\t\t \nparameters.setUseStabilizationFilter(false);\t\t\nparameters.setStabilizationFilterTime(4000); //4000 milliseconds 4s\nIndoorsFactory.Builder indoorsBuilder = new IndoorsFactory.Builder();\n....\nindoorsBuilder.setLocalizationParameters(parameters);\n...", "language": "java" } ] } [/block] [block:callout] { "type": "warning", "title": "Default Values", "body": "By default the Kalman and Stabilization filter are enabled and Stabilization filter time is 4 seconds (the maximum value is 20 seconds)." } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820ba","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Integrating indoo.rs localization is now easier than ever. It’s a matter of a few steps to integrate our SDK into your XCode-project.\nTo get your first indoo.rs-powered app up and running as fast as possible you can download a sample project from my.indoo.rs. This project includes everything you need to load and display a map, as well as locate yourself (you have to create a map first, of course). Sample project is available in both Objective-C and Swift.\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Change log\"\n}\n[/block]\nChange log main changes: \n - C types replaced by Objective-C types\n - Deprecated and obsolete classes/methods removed\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"Prior to 4.2.0\",\n    \"h-1\": \"4.2.0\",\n    \"6-0\": \"IndoorsSurfaceEnums.h\\n\\n- enum: IndoorsSurfaceZoneDisplayMode\\n- enum: IndoorsSurfaceUserPositionDisplayMode (deprecated)\",\n    \"6-1\": \"Removed from public API. \\n\\n- enum: ISZoneDisplayMode (moved to ISMapScrollView.h)\\n- enum: IndoorsSurfaceUserPositionDisplayMode removed\",\n    \"12-0\": \"IDSContext.h\\n - enum: Context\\n - enum: State\",\n    \"12-1\": \"Changed naming of enums:\\n- enum: IndoorsContext \\n- enum: IDSState\",\n    \"14-0\": \"IndoorsDelegate.h\\n\\nIndoorsServiceDelegate's delegate method connected is depreacated\\n\\nLoadingBuildingDelegate\\n- (void)loadingBuilding:(NSNumber *)progress;\",\n    \"14-1\": \"IndoorsDelegate.h\\n\\nconnected removed from public API.\\n\\n\\nLoadingBuildingDelegate\\n@optional\\n- (void)loadingBuilding:(NSNumber *)progress;\",\n    \"0-0\": \"IndoorsBuilder.h (deprecated)\",\n    \"0-1\": \"Removed from public API.\",\n    \"15-0\": \"EvaluationDelegate.h\\n\\n- (void)evaluationProvider:(EvaluationProvider *)evaluationProvider didChangeFloor:(int)level;\",\n    \"15-1\": \"EvaluationDelegate.h\\n\\n- (void)evaluationProvider:(EvaluationProvider *)evaluationProvider didChangeFloor:(NSInteger)level;\",\n    \"17-0\": \"IDSBuilding.h\\n\\n@property (nonatomic) float rotation;\\n- (int)getInitialFloorLevel;\\n- (IDSFloor *)getFloorById:(long)floorId;\\n- (IDSZone *)getZoneById:(long)zoneId;\",\n    \"17-1\": \"IDSBuilding.h\\n\\n@property (nonatomic) NSNumber *rotation;\\n- (NSInteger)getInitialFloorLevel;\\n- (IDSFloor \\\\*)getFloorById:(NSNumber *)floorId;\\n- (IDSZone \\\\*)getZoneById:(NSNumber *)zoneId;\",\n    \"23-0\": \"IDSBuildingManager.h\\n\\n - (void)loadBuildingWithId:(NSUInteger)buildingId progress:(void (^)(double progress, NSUInteger currentStep, NSUInteger totalSteps, NSString \\\\*phase))progress completion:(void (^)(IDSBuilding \\\\*building, NSError \\\\*error))completion;\",\n    \"23-1\": \"IDSBuildingManager.h\\n\\n - (void)loadBuildingWithId:(NSUInteger)buildingId progress:(void (^)(NSInteger progress, NSInteger currentStep, NSInteger totalSteps, NSString \\\\*phase))progress completion:(void (^)(IDSBuilding \\\\*building, NSError \\\\*error))completion;\",\n    \"24-0\": \"IDSDefaultMap.h\\n\\n@property(nonatomic) long defaultMapID;\\n@property(nonatomic) double mmPerPixelBase;\\n@property (nonatomic) long mapID;\\n@property (nonatomic) int tileSizeMaximum;\\n@property (nonatomic) double meterPerPixel;\\n- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col;\",\n    \"24-1\": \"IDSDefaultMap.h\\n\\n@property (nonatomic) NSNumber *defaultMapID;\\n@property (nonatomic) NSNumber *mmPerPixelBase;\\n@property (nonatomic) NSNumber *mapID;\\n@property (nonatomic) NSInteger tileSizeMaximum;\\n@property (nonatomic) NSNumber *meterPerPixel;\\n- (UIImage *)tileForScale:(CGFloat)scale row:(NSInteger)row col:(NSInteger)col;\",\n    \"18-0\": \"IDSFloor.h\\n\\n@property (nonatomic) long floorID;\\n@property (nonatomic) int widthInMeter;\\n@property (nonatomic) int lengthInMeter;\\n@property (nonatomic) int leftOriginInMeter;\\n@property (nonatomic) int topOriginInMeter;\\n@property (nonatomic) int mmWidth;\\n@property (nonatomic) int mmHeight;\",\n    \"18-1\": \"IDSFloor.h\\n\\n@property (nonatomic) NSNumber *floorID;\\n@property (nonatomic) NSInteger widthInMeter;\\n@property (nonatomic) NSInteger lengthInMeter;\\n@property (nonatomic) NSInteger leftOriginInMeter;\\n@property (nonatomic) NSInteger topOriginInMeter;\\n@property (nonatomic) NSInteger mmWidth;\\n@property (nonatomic) NSInteger mmHeight;\",\n    \"2-0\": \"IDSLogLevels.h\",\n    \"2-1\": \"- Removed from public API. \\n- Content moved to IDSLog.h\",\n    \"22-0\": \"IDSMap.h\\n\\n@property (nonatomic) long mapID;\\n@property (nonatomic) int tileSizeMaximum;\\n@property (nonatomic) double meterPerPixel;\\n@property (nonatomic, assign, readonly) float mmPerPixelBase;\\n- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col;\",\n    \"22-1\": \"IDSMap.h\\n\\n@property (nonatomic) NSNumber *mapID;\\n@property (nonatomic) NSInteger tileSizeMaximum;\\n@property (nonatomic) NSNumber *meterPerPixel;\\n@property (nonatomic, assign, readonly) NSNumber *mmPerPixelBase;\\n- (UIImage *)tileForScale:(CGFloat)scale row:(NSInteger)row col:(NSInteger)col;\",\n    \"19-0\": \"IDSTile.h\\n\\n@property (nonatomic) CGFloat mmPerPixel;\",\n    \"19-1\": \"IDSTile.h\\n\\n@property (nonatomic) NSNumber *mmPerPixel;\",\n    \"20-0\": \"IDSZone.h\\n\\n@property (nonatomic) long zone_id;\",\n    \"20-1\": \"IDSZone.h\\n\\n@property (nonatomic) NSNumber *zone_id;\",\n    \"21-0\": \"IDSZonePoint.h\\n\\n@property (nonatomic) int zonepoint_id;\\n@property (nonatomic) int x;\\n@property (nonatomic) int y;\\n@property (nonatomic) int sortOrder;\",\n    \"21-1\": \"IDSZonePoint.h\\n\\n@property (nonatomic) NSInteger zonepoint_id;\\n@property (nonatomic) NSInteger x;\\n@property (nonatomic) NSInteger y;\\n@property (nonatomic) NSInteger sortOrder;\",\n    \"3-0\": \"IndoorsErrorCode.h\",\n    \"3-1\": \"- Removed from public API.\\n- Content moved to IndoorsError.h\\n- Error code enum naming changed.\",\n    \"27-0\": \"IndoorsException.h\",\n    \"27-1\": \"Methods removed:\\n\\n+ (id)raiseWithException:(NSException*)e;\\n+ (void)raiseWithMessage:(NSString*)message;\\n+ (void) raiseWithException:(NSException*)exception withMessage:(NSString*)message andErrorCode:(IndoorsErrorCode)errorcode;\\n- (id)init;\\n- (IndoorsErrorCode) getErrorCode;\",\n    \"16-0\": \"IndoorsLocationListener.h\\n\\n- (void)orientationUpdated:(float)orientation;\\n- (void)changedFloor:(int)floorLevel withName:(NSString*)name;\",\n    \"16-1\": \"IndoorsLocationListener.h\\n\\n- (void)orientationUpdated:(NSNumber *)orientation;\\n- (void)changedFloor:(NSInteger)floorLevel withName:(NSString*)name;\",\n    \"1-1\": \"Removed from public API.\",\n    \"1-0\": \"IndoorsSurfaceBuilder.h  (deprecated)\",\n    \"10-0\": \"ISIndoorsSurface.h\\n\\n@property (nonatomic) double dotOnRailsJumpingDistance;\\n\\n- (void)setUserPositionDisplayMode:(IndoorsSurfaceUserPositionDisplayModes)userPositionDisplayMode (deprecated)\",\n    \"10-1\": \"ISIndoorsSurface.h\\n\\n@property (nonatomic) NSNumber *dotOnRailsJumpingDistance;\\n\\n - setUserPositionDisplayMode - Removed from public API.\",\n    \"11-0\": \"ISIndoorsSurfaceViewController.h\\n\\n@property (nonatomic, readonly) float userOrientation;\",\n    \"11-1\": \"ISIndoorsSurfaceViewController.h\\n\\n@property (nonatomic, readonly) NSNumber *userOrientation;\",\n    \"25-0\": \"ISMapScrollView.h\\n\\n- (void)setUserOrientation:(float)orientation;\\n- (void)zoomToMapRect:(CGRect)rect animated:(BOOL)animated (deprecated)\\n- (void)setUserPositionDisplayMode:(IndoorsSurfaceUserPositionDisplayModes)userPositionDisplayMode (deprecated)\",\n    \"25-1\": \"ISMapScrollView.h\\n\\n- (void)setUserOrientation:(NSNumber *)orientation;\\n- zoomToMapRect removed\\n- setUserPositionDisplayMode removed\",\n    \"26-0\": \"ISUserAnnotationView.h\\n\\n@property (nonatomic) CGFloat orientation;\",\n    \"26-1\": \"ISUserAnnotationView.h\\n\\n@property (nonatomic) NSNumber *orientation;\",\n    \"9-0\": \"Indoors.h\\n\\n- (void)setRouteSnappingMaxDistance:(double)maxDistance;\\n- (void)setPredefinedRouteSnappingMaxDistance:(double)maxDistance;\",\n    \"9-1\": \"Indoors.h\\n\\n- (void)setRouteSnappingMaxDistance:(NSNumber *)maxDistance;\\n- (void)setPredefinedRouteSnappingMaxDistance:(NSNumber *)maxDistance;\",\n    \"4-0\": \"Networktype.h\",\n    \"4-1\": \"- Removed from public API.\\n- Content moved to IDSNetowrk.h\",\n    \"5-0\": \"IndoorsParameters.h\",\n    \"5-1\": \"- Removed from public API.\\n- Content moved to Indoors.h\",\n    \"13-0\": \"IDSTile.h\\n\\n@property (nonatomic) long *tileID;\",\n    \"13-1\": \"IDSTile.h\\n\\n@property (nonatomic) NSNumber *tileID;\",\n    \"7-0\": \"IDSMap.h\",\n    \"7-1\": \"Removed from public API (not needed for public use).\",\n    \"8-0\": \"IDSNetwork.h\",\n    \"8-1\": \"Removed from public API (not needed for public use).\"\n  },\n  \"cols\": 2,\n  \"rows\": 28\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Integrating Indoors SDK into an existing app\"\n}\n[/block]\nYou can find indoo.rs SDK library on [cocoapods website](https://cocoapods.org/pods/IndoorsSDK-iOS). If you are not familiar with cocoapods first go trough tutorial on cocapods website on how to download your first cocoapod.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"After installing indoo.rs SDK cocoapod make sure to always open the .xcworkspace file instead of .xcodeproj!\",\n  \"title\": \"\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Make sure not to use the \\\"-all_load\\\" linker-flag, which breaks the build for our SDK.\"\n}\n[/block]\nStarting with iOS 8, you also have to provide a NSLocationWhenInUseUsageDescription-key in your project's Info.plist. The SDK will not work at all if this is not present. Just add the following lines to your Info.plist file:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<key>NSLocationWhenInUseUsageDescription</key>\\n<string>NSLocationWhenInUseUsageDescription</string>\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"SDK integration into Swift project\"\n}\n[/block]\nIndoo.rs SDK is written in Objective-C language, and therefore if you want to use it in Swift project you have to create [bridging header](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html). In order for our SDK to work properly, you will need to import 3 header files inside the bridging header:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#ifndef ObjectiveCBridge_h\\n#define ObjectiveCBridge_h\\n\\n#import <Foundation/Foundation.h>\\n#import <UIKit/UIKit.h>\\n#import <IndoorsSDK/IndoorsSDK.h>\\n\\n#endif /* ObjectiveCBridge_h */\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\nAfter this you will also need to link next frameworks and libraries into your project in order for the SDK to work:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"QuartzCore.framework\\nSystemConfiguration.framework\\nCoreMotion.framework\\nCFNetwork.framework\\nUIKit.framework\\nFoundation.framework\\nCoreBluetooth.framework\\nCoreGraphics.framework\\nCoreLocation.framework\\nlibsqlite3.0.tbd\\nlibc++.tbd\\nlibz.tbd\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-25T09:53:22.801Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":0,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"getting-started-with-indoors-ios-sdk","sync_unique":"","title":"Getting Started with indoo.rs SDK","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Getting Started with indoo.rs SDK


Integrating indoo.rs localization is now easier than ever. It’s a matter of a few steps to integrate our SDK into your XCode-project. To get your first indoo.rs-powered app up and running as fast as possible you can download a sample project from my.indoo.rs. This project includes everything you need to load and display a map, as well as locate yourself (you have to create a map first, of course). Sample project is available in both Objective-C and Swift. [block:api-header] { "type": "basic", "title": "Change log" } [/block] Change log main changes: - C types replaced by Objective-C types - Deprecated and obsolete classes/methods removed [block:parameters] { "data": { "h-0": "Prior to 4.2.0", "h-1": "4.2.0", "6-0": "IndoorsSurfaceEnums.h\n\n- enum: IndoorsSurfaceZoneDisplayMode\n- enum: IndoorsSurfaceUserPositionDisplayMode (deprecated)", "6-1": "Removed from public API. \n\n- enum: ISZoneDisplayMode (moved to ISMapScrollView.h)\n- enum: IndoorsSurfaceUserPositionDisplayMode removed", "12-0": "IDSContext.h\n - enum: Context\n - enum: State", "12-1": "Changed naming of enums:\n- enum: IndoorsContext \n- enum: IDSState", "14-0": "IndoorsDelegate.h\n\nIndoorsServiceDelegate's delegate method connected is depreacated\n\nLoadingBuildingDelegate\n- (void)loadingBuilding:(NSNumber *)progress;", "14-1": "IndoorsDelegate.h\n\nconnected removed from public API.\n\n\nLoadingBuildingDelegate\n@optional\n- (void)loadingBuilding:(NSNumber *)progress;", "0-0": "IndoorsBuilder.h (deprecated)", "0-1": "Removed from public API.", "15-0": "EvaluationDelegate.h\n\n- (void)evaluationProvider:(EvaluationProvider *)evaluationProvider didChangeFloor:(int)level;", "15-1": "EvaluationDelegate.h\n\n- (void)evaluationProvider:(EvaluationProvider *)evaluationProvider didChangeFloor:(NSInteger)level;", "17-0": "IDSBuilding.h\n\n@property (nonatomic) float rotation;\n- (int)getInitialFloorLevel;\n- (IDSFloor *)getFloorById:(long)floorId;\n- (IDSZone *)getZoneById:(long)zoneId;", "17-1": "IDSBuilding.h\n\n@property (nonatomic) NSNumber *rotation;\n- (NSInteger)getInitialFloorLevel;\n- (IDSFloor \\*)getFloorById:(NSNumber *)floorId;\n- (IDSZone \\*)getZoneById:(NSNumber *)zoneId;", "23-0": "IDSBuildingManager.h\n\n - (void)loadBuildingWithId:(NSUInteger)buildingId progress:(void (^)(double progress, NSUInteger currentStep, NSUInteger totalSteps, NSString \\*phase))progress completion:(void (^)(IDSBuilding \\*building, NSError \\*error))completion;", "23-1": "IDSBuildingManager.h\n\n - (void)loadBuildingWithId:(NSUInteger)buildingId progress:(void (^)(NSInteger progress, NSInteger currentStep, NSInteger totalSteps, NSString \\*phase))progress completion:(void (^)(IDSBuilding \\*building, NSError \\*error))completion;", "24-0": "IDSDefaultMap.h\n\n@property(nonatomic) long defaultMapID;\n@property(nonatomic) double mmPerPixelBase;\n@property (nonatomic) long mapID;\n@property (nonatomic) int tileSizeMaximum;\n@property (nonatomic) double meterPerPixel;\n- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col;", "24-1": "IDSDefaultMap.h\n\n@property (nonatomic) NSNumber *defaultMapID;\n@property (nonatomic) NSNumber *mmPerPixelBase;\n@property (nonatomic) NSNumber *mapID;\n@property (nonatomic) NSInteger tileSizeMaximum;\n@property (nonatomic) NSNumber *meterPerPixel;\n- (UIImage *)tileForScale:(CGFloat)scale row:(NSInteger)row col:(NSInteger)col;", "18-0": "IDSFloor.h\n\n@property (nonatomic) long floorID;\n@property (nonatomic) int widthInMeter;\n@property (nonatomic) int lengthInMeter;\n@property (nonatomic) int leftOriginInMeter;\n@property (nonatomic) int topOriginInMeter;\n@property (nonatomic) int mmWidth;\n@property (nonatomic) int mmHeight;", "18-1": "IDSFloor.h\n\n@property (nonatomic) NSNumber *floorID;\n@property (nonatomic) NSInteger widthInMeter;\n@property (nonatomic) NSInteger lengthInMeter;\n@property (nonatomic) NSInteger leftOriginInMeter;\n@property (nonatomic) NSInteger topOriginInMeter;\n@property (nonatomic) NSInteger mmWidth;\n@property (nonatomic) NSInteger mmHeight;", "2-0": "IDSLogLevels.h", "2-1": "- Removed from public API. \n- Content moved to IDSLog.h", "22-0": "IDSMap.h\n\n@property (nonatomic) long mapID;\n@property (nonatomic) int tileSizeMaximum;\n@property (nonatomic) double meterPerPixel;\n@property (nonatomic, assign, readonly) float mmPerPixelBase;\n- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col;", "22-1": "IDSMap.h\n\n@property (nonatomic) NSNumber *mapID;\n@property (nonatomic) NSInteger tileSizeMaximum;\n@property (nonatomic) NSNumber *meterPerPixel;\n@property (nonatomic, assign, readonly) NSNumber *mmPerPixelBase;\n- (UIImage *)tileForScale:(CGFloat)scale row:(NSInteger)row col:(NSInteger)col;", "19-0": "IDSTile.h\n\n@property (nonatomic) CGFloat mmPerPixel;", "19-1": "IDSTile.h\n\n@property (nonatomic) NSNumber *mmPerPixel;", "20-0": "IDSZone.h\n\n@property (nonatomic) long zone_id;", "20-1": "IDSZone.h\n\n@property (nonatomic) NSNumber *zone_id;", "21-0": "IDSZonePoint.h\n\n@property (nonatomic) int zonepoint_id;\n@property (nonatomic) int x;\n@property (nonatomic) int y;\n@property (nonatomic) int sortOrder;", "21-1": "IDSZonePoint.h\n\n@property (nonatomic) NSInteger zonepoint_id;\n@property (nonatomic) NSInteger x;\n@property (nonatomic) NSInteger y;\n@property (nonatomic) NSInteger sortOrder;", "3-0": "IndoorsErrorCode.h", "3-1": "- Removed from public API.\n- Content moved to IndoorsError.h\n- Error code enum naming changed.", "27-0": "IndoorsException.h", "27-1": "Methods removed:\n\n+ (id)raiseWithException:(NSException*)e;\n+ (void)raiseWithMessage:(NSString*)message;\n+ (void) raiseWithException:(NSException*)exception withMessage:(NSString*)message andErrorCode:(IndoorsErrorCode)errorcode;\n- (id)init;\n- (IndoorsErrorCode) getErrorCode;", "16-0": "IndoorsLocationListener.h\n\n- (void)orientationUpdated:(float)orientation;\n- (void)changedFloor:(int)floorLevel withName:(NSString*)name;", "16-1": "IndoorsLocationListener.h\n\n- (void)orientationUpdated:(NSNumber *)orientation;\n- (void)changedFloor:(NSInteger)floorLevel withName:(NSString*)name;", "1-1": "Removed from public API.", "1-0": "IndoorsSurfaceBuilder.h (deprecated)", "10-0": "ISIndoorsSurface.h\n\n@property (nonatomic) double dotOnRailsJumpingDistance;\n\n- (void)setUserPositionDisplayMode:(IndoorsSurfaceUserPositionDisplayModes)userPositionDisplayMode (deprecated)", "10-1": "ISIndoorsSurface.h\n\n@property (nonatomic) NSNumber *dotOnRailsJumpingDistance;\n\n - setUserPositionDisplayMode - Removed from public API.", "11-0": "ISIndoorsSurfaceViewController.h\n\n@property (nonatomic, readonly) float userOrientation;", "11-1": "ISIndoorsSurfaceViewController.h\n\n@property (nonatomic, readonly) NSNumber *userOrientation;", "25-0": "ISMapScrollView.h\n\n- (void)setUserOrientation:(float)orientation;\n- (void)zoomToMapRect:(CGRect)rect animated:(BOOL)animated (deprecated)\n- (void)setUserPositionDisplayMode:(IndoorsSurfaceUserPositionDisplayModes)userPositionDisplayMode (deprecated)", "25-1": "ISMapScrollView.h\n\n- (void)setUserOrientation:(NSNumber *)orientation;\n- zoomToMapRect removed\n- setUserPositionDisplayMode removed", "26-0": "ISUserAnnotationView.h\n\n@property (nonatomic) CGFloat orientation;", "26-1": "ISUserAnnotationView.h\n\n@property (nonatomic) NSNumber *orientation;", "9-0": "Indoors.h\n\n- (void)setRouteSnappingMaxDistance:(double)maxDistance;\n- (void)setPredefinedRouteSnappingMaxDistance:(double)maxDistance;", "9-1": "Indoors.h\n\n- (void)setRouteSnappingMaxDistance:(NSNumber *)maxDistance;\n- (void)setPredefinedRouteSnappingMaxDistance:(NSNumber *)maxDistance;", "4-0": "Networktype.h", "4-1": "- Removed from public API.\n- Content moved to IDSNetowrk.h", "5-0": "IndoorsParameters.h", "5-1": "- Removed from public API.\n- Content moved to Indoors.h", "13-0": "IDSTile.h\n\n@property (nonatomic) long *tileID;", "13-1": "IDSTile.h\n\n@property (nonatomic) NSNumber *tileID;", "7-0": "IDSMap.h", "7-1": "Removed from public API (not needed for public use).", "8-0": "IDSNetwork.h", "8-1": "Removed from public API (not needed for public use)." }, "cols": 2, "rows": 28 } [/block] [block:api-header] { "type": "basic", "title": "Integrating Indoors SDK into an existing app" } [/block] You can find indoo.rs SDK library on [cocoapods website](https://cocoapods.org/pods/IndoorsSDK-iOS). If you are not familiar with cocoapods first go trough tutorial on cocapods website on how to download your first cocoapod. [block:callout] { "type": "info", "body": "After installing indoo.rs SDK cocoapod make sure to always open the .xcworkspace file instead of .xcodeproj!", "title": "" } [/block] [block:callout] { "type": "warning", "body": "Make sure not to use the \"-all_load\" linker-flag, which breaks the build for our SDK." } [/block] Starting with iOS 8, you also have to provide a NSLocationWhenInUseUsageDescription-key in your project's Info.plist. The SDK will not work at all if this is not present. Just add the following lines to your Info.plist file: [block:code] { "codes": [ { "code": "<key>NSLocationWhenInUseUsageDescription</key>\n<string>NSLocationWhenInUseUsageDescription</string>", "language": "xml" } ] } [/block] [block:api-header] { "type": "basic", "title": "SDK integration into Swift project" } [/block] Indoo.rs SDK is written in Objective-C language, and therefore if you want to use it in Swift project you have to create [bridging header](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html). In order for our SDK to work properly, you will need to import 3 header files inside the bridging header: [block:code] { "codes": [ { "code": "#ifndef ObjectiveCBridge_h\n#define ObjectiveCBridge_h\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n#import <IndoorsSDK/IndoorsSDK.h>\n\n#endif /* ObjectiveCBridge_h */", "language": "swift" } ] } [/block] After this you will also need to link next frameworks and libraries into your project in order for the SDK to work: [block:code] { "codes": [ { "code": "QuartzCore.framework\nSystemConfiguration.framework\nCoreMotion.framework\nCFNetwork.framework\nUIKit.framework\nFoundation.framework\nCoreBluetooth.framework\nCoreGraphics.framework\nCoreLocation.framework\nlibsqlite3.0.tbd\nlibc++.tbd\nlibz.tbd", "language": "text" } ] } [/block]
Integrating indoo.rs localization is now easier than ever. It’s a matter of a few steps to integrate our SDK into your XCode-project. To get your first indoo.rs-powered app up and running as fast as possible you can download a sample project from my.indoo.rs. This project includes everything you need to load and display a map, as well as locate yourself (you have to create a map first, of course). Sample project is available in both Objective-C and Swift. [block:api-header] { "type": "basic", "title": "Change log" } [/block] Change log main changes: - C types replaced by Objective-C types - Deprecated and obsolete classes/methods removed [block:parameters] { "data": { "h-0": "Prior to 4.2.0", "h-1": "4.2.0", "6-0": "IndoorsSurfaceEnums.h\n\n- enum: IndoorsSurfaceZoneDisplayMode\n- enum: IndoorsSurfaceUserPositionDisplayMode (deprecated)", "6-1": "Removed from public API. \n\n- enum: ISZoneDisplayMode (moved to ISMapScrollView.h)\n- enum: IndoorsSurfaceUserPositionDisplayMode removed", "12-0": "IDSContext.h\n - enum: Context\n - enum: State", "12-1": "Changed naming of enums:\n- enum: IndoorsContext \n- enum: IDSState", "14-0": "IndoorsDelegate.h\n\nIndoorsServiceDelegate's delegate method connected is depreacated\n\nLoadingBuildingDelegate\n- (void)loadingBuilding:(NSNumber *)progress;", "14-1": "IndoorsDelegate.h\n\nconnected removed from public API.\n\n\nLoadingBuildingDelegate\n@optional\n- (void)loadingBuilding:(NSNumber *)progress;", "0-0": "IndoorsBuilder.h (deprecated)", "0-1": "Removed from public API.", "15-0": "EvaluationDelegate.h\n\n- (void)evaluationProvider:(EvaluationProvider *)evaluationProvider didChangeFloor:(int)level;", "15-1": "EvaluationDelegate.h\n\n- (void)evaluationProvider:(EvaluationProvider *)evaluationProvider didChangeFloor:(NSInteger)level;", "17-0": "IDSBuilding.h\n\n@property (nonatomic) float rotation;\n- (int)getInitialFloorLevel;\n- (IDSFloor *)getFloorById:(long)floorId;\n- (IDSZone *)getZoneById:(long)zoneId;", "17-1": "IDSBuilding.h\n\n@property (nonatomic) NSNumber *rotation;\n- (NSInteger)getInitialFloorLevel;\n- (IDSFloor \\*)getFloorById:(NSNumber *)floorId;\n- (IDSZone \\*)getZoneById:(NSNumber *)zoneId;", "23-0": "IDSBuildingManager.h\n\n - (void)loadBuildingWithId:(NSUInteger)buildingId progress:(void (^)(double progress, NSUInteger currentStep, NSUInteger totalSteps, NSString \\*phase))progress completion:(void (^)(IDSBuilding \\*building, NSError \\*error))completion;", "23-1": "IDSBuildingManager.h\n\n - (void)loadBuildingWithId:(NSUInteger)buildingId progress:(void (^)(NSInteger progress, NSInteger currentStep, NSInteger totalSteps, NSString \\*phase))progress completion:(void (^)(IDSBuilding \\*building, NSError \\*error))completion;", "24-0": "IDSDefaultMap.h\n\n@property(nonatomic) long defaultMapID;\n@property(nonatomic) double mmPerPixelBase;\n@property (nonatomic) long mapID;\n@property (nonatomic) int tileSizeMaximum;\n@property (nonatomic) double meterPerPixel;\n- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col;", "24-1": "IDSDefaultMap.h\n\n@property (nonatomic) NSNumber *defaultMapID;\n@property (nonatomic) NSNumber *mmPerPixelBase;\n@property (nonatomic) NSNumber *mapID;\n@property (nonatomic) NSInteger tileSizeMaximum;\n@property (nonatomic) NSNumber *meterPerPixel;\n- (UIImage *)tileForScale:(CGFloat)scale row:(NSInteger)row col:(NSInteger)col;", "18-0": "IDSFloor.h\n\n@property (nonatomic) long floorID;\n@property (nonatomic) int widthInMeter;\n@property (nonatomic) int lengthInMeter;\n@property (nonatomic) int leftOriginInMeter;\n@property (nonatomic) int topOriginInMeter;\n@property (nonatomic) int mmWidth;\n@property (nonatomic) int mmHeight;", "18-1": "IDSFloor.h\n\n@property (nonatomic) NSNumber *floorID;\n@property (nonatomic) NSInteger widthInMeter;\n@property (nonatomic) NSInteger lengthInMeter;\n@property (nonatomic) NSInteger leftOriginInMeter;\n@property (nonatomic) NSInteger topOriginInMeter;\n@property (nonatomic) NSInteger mmWidth;\n@property (nonatomic) NSInteger mmHeight;", "2-0": "IDSLogLevels.h", "2-1": "- Removed from public API. \n- Content moved to IDSLog.h", "22-0": "IDSMap.h\n\n@property (nonatomic) long mapID;\n@property (nonatomic) int tileSizeMaximum;\n@property (nonatomic) double meterPerPixel;\n@property (nonatomic, assign, readonly) float mmPerPixelBase;\n- (UIImage *)tileForScale:(CGFloat)scale row:(int)row col:(int)col;", "22-1": "IDSMap.h\n\n@property (nonatomic) NSNumber *mapID;\n@property (nonatomic) NSInteger tileSizeMaximum;\n@property (nonatomic) NSNumber *meterPerPixel;\n@property (nonatomic, assign, readonly) NSNumber *mmPerPixelBase;\n- (UIImage *)tileForScale:(CGFloat)scale row:(NSInteger)row col:(NSInteger)col;", "19-0": "IDSTile.h\n\n@property (nonatomic) CGFloat mmPerPixel;", "19-1": "IDSTile.h\n\n@property (nonatomic) NSNumber *mmPerPixel;", "20-0": "IDSZone.h\n\n@property (nonatomic) long zone_id;", "20-1": "IDSZone.h\n\n@property (nonatomic) NSNumber *zone_id;", "21-0": "IDSZonePoint.h\n\n@property (nonatomic) int zonepoint_id;\n@property (nonatomic) int x;\n@property (nonatomic) int y;\n@property (nonatomic) int sortOrder;", "21-1": "IDSZonePoint.h\n\n@property (nonatomic) NSInteger zonepoint_id;\n@property (nonatomic) NSInteger x;\n@property (nonatomic) NSInteger y;\n@property (nonatomic) NSInteger sortOrder;", "3-0": "IndoorsErrorCode.h", "3-1": "- Removed from public API.\n- Content moved to IndoorsError.h\n- Error code enum naming changed.", "27-0": "IndoorsException.h", "27-1": "Methods removed:\n\n+ (id)raiseWithException:(NSException*)e;\n+ (void)raiseWithMessage:(NSString*)message;\n+ (void) raiseWithException:(NSException*)exception withMessage:(NSString*)message andErrorCode:(IndoorsErrorCode)errorcode;\n- (id)init;\n- (IndoorsErrorCode) getErrorCode;", "16-0": "IndoorsLocationListener.h\n\n- (void)orientationUpdated:(float)orientation;\n- (void)changedFloor:(int)floorLevel withName:(NSString*)name;", "16-1": "IndoorsLocationListener.h\n\n- (void)orientationUpdated:(NSNumber *)orientation;\n- (void)changedFloor:(NSInteger)floorLevel withName:(NSString*)name;", "1-1": "Removed from public API.", "1-0": "IndoorsSurfaceBuilder.h (deprecated)", "10-0": "ISIndoorsSurface.h\n\n@property (nonatomic) double dotOnRailsJumpingDistance;\n\n- (void)setUserPositionDisplayMode:(IndoorsSurfaceUserPositionDisplayModes)userPositionDisplayMode (deprecated)", "10-1": "ISIndoorsSurface.h\n\n@property (nonatomic) NSNumber *dotOnRailsJumpingDistance;\n\n - setUserPositionDisplayMode - Removed from public API.", "11-0": "ISIndoorsSurfaceViewController.h\n\n@property (nonatomic, readonly) float userOrientation;", "11-1": "ISIndoorsSurfaceViewController.h\n\n@property (nonatomic, readonly) NSNumber *userOrientation;", "25-0": "ISMapScrollView.h\n\n- (void)setUserOrientation:(float)orientation;\n- (void)zoomToMapRect:(CGRect)rect animated:(BOOL)animated (deprecated)\n- (void)setUserPositionDisplayMode:(IndoorsSurfaceUserPositionDisplayModes)userPositionDisplayMode (deprecated)", "25-1": "ISMapScrollView.h\n\n- (void)setUserOrientation:(NSNumber *)orientation;\n- zoomToMapRect removed\n- setUserPositionDisplayMode removed", "26-0": "ISUserAnnotationView.h\n\n@property (nonatomic) CGFloat orientation;", "26-1": "ISUserAnnotationView.h\n\n@property (nonatomic) NSNumber *orientation;", "9-0": "Indoors.h\n\n- (void)setRouteSnappingMaxDistance:(double)maxDistance;\n- (void)setPredefinedRouteSnappingMaxDistance:(double)maxDistance;", "9-1": "Indoors.h\n\n- (void)setRouteSnappingMaxDistance:(NSNumber *)maxDistance;\n- (void)setPredefinedRouteSnappingMaxDistance:(NSNumber *)maxDistance;", "4-0": "Networktype.h", "4-1": "- Removed from public API.\n- Content moved to IDSNetowrk.h", "5-0": "IndoorsParameters.h", "5-1": "- Removed from public API.\n- Content moved to Indoors.h", "13-0": "IDSTile.h\n\n@property (nonatomic) long *tileID;", "13-1": "IDSTile.h\n\n@property (nonatomic) NSNumber *tileID;", "7-0": "IDSMap.h", "7-1": "Removed from public API (not needed for public use).", "8-0": "IDSNetwork.h", "8-1": "Removed from public API (not needed for public use)." }, "cols": 2, "rows": 28 } [/block] [block:api-header] { "type": "basic", "title": "Integrating Indoors SDK into an existing app" } [/block] You can find indoo.rs SDK library on [cocoapods website](https://cocoapods.org/pods/IndoorsSDK-iOS). If you are not familiar with cocoapods first go trough tutorial on cocapods website on how to download your first cocoapod. [block:callout] { "type": "info", "body": "After installing indoo.rs SDK cocoapod make sure to always open the .xcworkspace file instead of .xcodeproj!", "title": "" } [/block] [block:callout] { "type": "warning", "body": "Make sure not to use the \"-all_load\" linker-flag, which breaks the build for our SDK." } [/block] Starting with iOS 8, you also have to provide a NSLocationWhenInUseUsageDescription-key in your project's Info.plist. The SDK will not work at all if this is not present. Just add the following lines to your Info.plist file: [block:code] { "codes": [ { "code": "<key>NSLocationWhenInUseUsageDescription</key>\n<string>NSLocationWhenInUseUsageDescription</string>", "language": "xml" } ] } [/block] [block:api-header] { "type": "basic", "title": "SDK integration into Swift project" } [/block] Indoo.rs SDK is written in Objective-C language, and therefore if you want to use it in Swift project you have to create [bridging header](https://developer.apple.com/library/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html). In order for our SDK to work properly, you will need to import 3 header files inside the bridging header: [block:code] { "codes": [ { "code": "#ifndef ObjectiveCBridge_h\n#define ObjectiveCBridge_h\n\n#import <Foundation/Foundation.h>\n#import <UIKit/UIKit.h>\n#import <IndoorsSDK/IndoorsSDK.h>\n\n#endif /* ObjectiveCBridge_h */", "language": "swift" } ] } [/block] After this you will also need to link next frameworks and libraries into your project in order for the SDK to work: [block:code] { "codes": [ { "code": "QuartzCore.framework\nSystemConfiguration.framework\nCoreMotion.framework\nCFNetwork.framework\nUIKit.framework\nFoundation.framework\nCoreBluetooth.framework\nCoreGraphics.framework\nCoreLocation.framework\nlibsqlite3.0.tbd\nlibc++.tbd\nlibz.tbd", "language": "text" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820bb","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"In order to load and display a building, initialize the indoo.rs-SDK with your API-key and use an instance of ISIndoorsSurfaceViewController like this (for a full example download MyFirstIndoorsApp from https://my.indoo.rs):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n\\n// ...\\n  \\n- (void)viewDidLoad {\\n    [super viewDidLoad];\\n    \\n    __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\\\"YOUR-API-KEY\\\" andServiceDelegate:self];\\n    \\n    _indoorsSurfaceViewController = [[ISIndoorsSurfaceViewController alloc] init];\\n    _indoorsSurfaceViewController.delegate = self;\\n    \\n    [self addSurfaceAsChildViewController];\\n    // REPLACE WITH YOUR BUILDING ID\\n    [_indoorsSurfaceViewController loadBuildingWithBuildingId:12345678]; \\n}\\n\\n- (void)addSurfaceAsChildViewController {\\n    [self addChildViewController:_indoorsSurfaceViewController];\\n    _indoorsSurfaceViewController.view.frame = self.view.frame;\\n    [self.view addSubview:_indoorsSurfaceViewController.view];\\n    [_indoorsSurfaceViewController didMoveToParentViewController:self];\\n}\\n\\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"override func viewDidLoad() {\\n    super.viewDidLoad()\\n\\n    _ = Indoors(licenseKey:\\\"YOUR-API-KEY\\\", andServiceDelegate:self)\\n\\n    _indoorsSurfaceViewController = ISIndoorsSurfaceViewController()\\n    _indoorsSurfaceViewController!.delegate = self\\n\\n    addSurfaceAsChildViewController()\\n\\n    _indoorsSurfaceViewController!.loadBuildingWithBuildingId(12345678)\\n}\\n\\nfunc addSurfaceAsChildViewController () {\\n    self.addChildViewController(_indoorsSurfaceViewController!)\\n    _indoorsSurfaceViewController!.view.frame = self.view.frame\\n    self.view.addSubview(_indoorsSurfaceViewController!.view)\\n    _indoorsSurfaceViewController!.didMoveToParentViewController(self)\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nLook up IndoorsServiceDelegate.h for a list of delegate methods you can implement. For most apps, this is already enough. If you want to react to position changes, you might add something like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// ...\\n\\n- (void)viewDidLoad\\n{\\n  // ...\\n  \\n  [[Indoors instance] registerLocationListener:self];\\n}\\n\\n#pragma mark - IndoorsLocationListener\\n  \\n- (void)positionUpdated:(IDSCoordinate *)userPosition\\n{\\n  // React to new position\\n}\\n\\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// ...\\n\\noverride func viewDidLoad() {\\n    super.viewDidLoad()\\n    \\n    // ...\\n    \\n    Indoors.instance().registerLocationListener(self)\\n}\\n\\n// MARK: IndoorsLocationListener\\n\\nfunc positionUpdated(userPosition: IDSCoordinate!) {\\n   // React to new position \\n}\\n\\n// ...\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIf you want to react to floor changes and a few more things look up IndoorsLocationListener.h for a list of delegate methods you can implement.","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:28:03.319Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":1,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"integrating-indoors-into-an-existing-app-1","sync_unique":"","title":"Load and display your building","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Load and display your building


In order to load and display a building, initialize the indoo.rs-SDK with your API-key and use an instance of ISIndoorsSurfaceViewController like this (for a full example download MyFirstIndoorsApp from https://my.indoo.rs): [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n\n// ...\n \n- (void)viewDidLoad {\n [super viewDidLoad];\n \n __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\"YOUR-API-KEY\" andServiceDelegate:self];\n \n _indoorsSurfaceViewController = [[ISIndoorsSurfaceViewController alloc] init];\n _indoorsSurfaceViewController.delegate = self;\n \n [self addSurfaceAsChildViewController];\n // REPLACE WITH YOUR BUILDING ID\n [_indoorsSurfaceViewController loadBuildingWithBuildingId:12345678]; \n}\n\n- (void)addSurfaceAsChildViewController {\n [self addChildViewController:_indoorsSurfaceViewController];\n _indoorsSurfaceViewController.view.frame = self.view.frame;\n [self.view addSubview:_indoorsSurfaceViewController.view];\n [_indoorsSurfaceViewController didMoveToParentViewController:self];\n}\n\n// ...", "language": "objectivec" }, { "code": "override func viewDidLoad() {\n super.viewDidLoad()\n\n _ = Indoors(licenseKey:\"YOUR-API-KEY\", andServiceDelegate:self)\n\n _indoorsSurfaceViewController = ISIndoorsSurfaceViewController()\n _indoorsSurfaceViewController!.delegate = self\n\n addSurfaceAsChildViewController()\n\n _indoorsSurfaceViewController!.loadBuildingWithBuildingId(12345678)\n}\n\nfunc addSurfaceAsChildViewController () {\n self.addChildViewController(_indoorsSurfaceViewController!)\n _indoorsSurfaceViewController!.view.frame = self.view.frame\n self.view.addSubview(_indoorsSurfaceViewController!.view)\n _indoorsSurfaceViewController!.didMoveToParentViewController(self)\n}", "language": "swift", "name": "Swift" } ] } [/block] Look up IndoorsServiceDelegate.h for a list of delegate methods you can implement. For most apps, this is already enough. If you want to react to position changes, you might add something like this: [block:code] { "codes": [ { "code": "// ...\n\n- (void)viewDidLoad\n{\n // ...\n \n [[Indoors instance] registerLocationListener:self];\n}\n\n#pragma mark - IndoorsLocationListener\n \n- (void)positionUpdated:(IDSCoordinate *)userPosition\n{\n // React to new position\n}\n\n// ...", "language": "objectivec" }, { "code": "// ...\n\noverride func viewDidLoad() {\n super.viewDidLoad()\n \n // ...\n \n Indoors.instance().registerLocationListener(self)\n}\n\n// MARK: IndoorsLocationListener\n\nfunc positionUpdated(userPosition: IDSCoordinate!) {\n // React to new position \n}\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block] If you want to react to floor changes and a few more things look up IndoorsLocationListener.h for a list of delegate methods you can implement.
In order to load and display a building, initialize the indoo.rs-SDK with your API-key and use an instance of ISIndoorsSurfaceViewController like this (for a full example download MyFirstIndoorsApp from https://my.indoo.rs): [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n\n// ...\n \n- (void)viewDidLoad {\n [super viewDidLoad];\n \n __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\"YOUR-API-KEY\" andServiceDelegate:self];\n \n _indoorsSurfaceViewController = [[ISIndoorsSurfaceViewController alloc] init];\n _indoorsSurfaceViewController.delegate = self;\n \n [self addSurfaceAsChildViewController];\n // REPLACE WITH YOUR BUILDING ID\n [_indoorsSurfaceViewController loadBuildingWithBuildingId:12345678]; \n}\n\n- (void)addSurfaceAsChildViewController {\n [self addChildViewController:_indoorsSurfaceViewController];\n _indoorsSurfaceViewController.view.frame = self.view.frame;\n [self.view addSubview:_indoorsSurfaceViewController.view];\n [_indoorsSurfaceViewController didMoveToParentViewController:self];\n}\n\n// ...", "language": "objectivec" }, { "code": "override func viewDidLoad() {\n super.viewDidLoad()\n\n _ = Indoors(licenseKey:\"YOUR-API-KEY\", andServiceDelegate:self)\n\n _indoorsSurfaceViewController = ISIndoorsSurfaceViewController()\n _indoorsSurfaceViewController!.delegate = self\n\n addSurfaceAsChildViewController()\n\n _indoorsSurfaceViewController!.loadBuildingWithBuildingId(12345678)\n}\n\nfunc addSurfaceAsChildViewController () {\n self.addChildViewController(_indoorsSurfaceViewController!)\n _indoorsSurfaceViewController!.view.frame = self.view.frame\n self.view.addSubview(_indoorsSurfaceViewController!.view)\n _indoorsSurfaceViewController!.didMoveToParentViewController(self)\n}", "language": "swift", "name": "Swift" } ] } [/block] Look up IndoorsServiceDelegate.h for a list of delegate methods you can implement. For most apps, this is already enough. If you want to react to position changes, you might add something like this: [block:code] { "codes": [ { "code": "// ...\n\n- (void)viewDidLoad\n{\n // ...\n \n [[Indoors instance] registerLocationListener:self];\n}\n\n#pragma mark - IndoorsLocationListener\n \n- (void)positionUpdated:(IDSCoordinate *)userPosition\n{\n // React to new position\n}\n\n// ...", "language": "objectivec" }, { "code": "// ...\n\noverride func viewDidLoad() {\n super.viewDidLoad()\n \n // ...\n \n Indoors.instance().registerLocationListener(self)\n}\n\n// MARK: IndoorsLocationListener\n\nfunc positionUpdated(userPosition: IDSCoordinate!) {\n // React to new position \n}\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block] If you want to react to floor changes and a few more things look up IndoorsLocationListener.h for a list of delegate methods you can implement.
{"__v":0,"_id":"57e3bcc2378b341700c820bc","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Indoo.rs SDK prints out a line containing the SDKs version number when you call initWithLicenceKey:andServiceDelegate. You should find a line like this in the Xcode debug terminal:\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoo.rs SDK version: 3.8.0\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]\nYou can also get the version directly with the following method of the Indoors class:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[Indoors versionInfo];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.versionInfo()\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-09-07T09:18:40.286Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":2,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"get-indoors-sdk-version-info","sync_unique":"","title":"indoo.rs SDK version info","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

indoo.rs SDK version info


Indoo.rs SDK prints out a line containing the SDKs version number when you call initWithLicenceKey:andServiceDelegate. You should find a line like this in the Xcode debug terminal: [block:code] { "codes": [ { "code": "indoo.rs SDK version: 3.8.0", "language": "text" } ] } [/block] You can also get the version directly with the following method of the Indoors class: [block:code] { "codes": [ { "code": "[Indoors versionInfo];", "language": "objectivec" }, { "code": "Indoors.versionInfo()", "language": "swift", "name": "Swift" } ] } [/block]
Indoo.rs SDK prints out a line containing the SDKs version number when you call initWithLicenceKey:andServiceDelegate. You should find a line like this in the Xcode debug terminal: [block:code] { "codes": [ { "code": "indoo.rs SDK version: 3.8.0", "language": "text" } ] } [/block] You can also get the version directly with the following method of the Indoors class: [block:code] { "codes": [ { "code": "[Indoors versionInfo];", "language": "objectivec" }, { "code": "Indoors.versionInfo()", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820bd","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"This is useful if you're working on an app for a remote venue (e.g. a shopping mal, event venue, etc) but still want to have some position displayed on the map. Thus, it is possible to test your project in simulator or when no networks are available.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// Init the indoo.rs-SDK shared instance with\\n__unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\\\"YOUR-API-KEY\\\" andServiceDelegate:self];\\n\\n// Make sure to call this before loading a building!\\n[[Indoors instance] enableEvaluationMode:YES];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// Init the indoo.rs-SDK shared instance with\\n_ = Indoors(licenseKey:\\\"YOUR-API-KEY\\\", andServiceDelegate:self)\\n\\n// Make sure to call this before loading a building!\\nIndoors.instance().enableEvaluationMode(true)\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:40:28.767Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":3,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"evaluation-mode-1","sync_unique":"","title":"Evaluation Mode","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Evaluation Mode


This is useful if you're working on an app for a remote venue (e.g. a shopping mal, event venue, etc) but still want to have some position displayed on the map. Thus, it is possible to test your project in simulator or when no networks are available. [block:code] { "codes": [ { "code": "// Init the indoo.rs-SDK shared instance with\n__unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\"YOUR-API-KEY\" andServiceDelegate:self];\n\n// Make sure to call this before loading a building!\n[[Indoors instance] enableEvaluationMode:YES];", "language": "objectivec" }, { "code": "// Init the indoo.rs-SDK shared instance with\n_ = Indoors(licenseKey:\"YOUR-API-KEY\", andServiceDelegate:self)\n\n// Make sure to call this before loading a building!\nIndoors.instance().enableEvaluationMode(true)", "language": "swift", "name": "Swift" } ] } [/block]
This is useful if you're working on an app for a remote venue (e.g. a shopping mal, event venue, etc) but still want to have some position displayed on the map. Thus, it is possible to test your project in simulator or when no networks are available. [block:code] { "codes": [ { "code": "// Init the indoo.rs-SDK shared instance with\n__unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\"YOUR-API-KEY\" andServiceDelegate:self];\n\n// Make sure to call this before loading a building!\n[[Indoors instance] enableEvaluationMode:YES];", "language": "objectivec" }, { "code": "// Init the indoo.rs-SDK shared instance with\n_ = Indoors(licenseKey:\"YOUR-API-KEY\", andServiceDelegate:self)\n\n// Make sure to call this before loading a building!\nIndoors.instance().enableEvaluationMode(true)", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820be","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Calculating and displaying a route on the map is a matter of a few lines too:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n \\n@interface IDViewController () <RoutingDelegate>\\n \\n// ...\\n \\n- (void)calculateRoute\\n{\\n    IDSCoordinate* start = [[IDSCoordinate alloc] initWithX:1234 andY:1234 andFloorLevel:0];\\n    IDSCoordinate* end = [[IDSCoordinate alloc] initWithX:12345 andY:12345 andFloorLevel:0];\\n \\n    [[Indoors instance] routeFromLocation:start toLocation:end delegate:self];\\n}\\n \\n// ...\\n \\n#pragma mark - RoutingDelegate\\n- (void)setRoute:(NSArray *)path\\n{\\n    [self.surfaceBuilder showPathWithPoints:path];\\n}\\n \\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"class ViewController: UIViewController, RoutingDelegate {\\n\\n\\t// ...\\n\\n\\tfunc calculateRoute() {\\n    \\tvar start = IDSCoordinate(x: 1234, andY: 1234, andFloorLevel: 0);\\n    \\tvar end = IDSCoordinate(x: 12345, andY: 12345, andFloorLevel: 0);\\n\\n    \\tIndoors.instance().routeFromLocation(start, toLocation: end, delegate: \\tself)\\n  }\\n  \\n  // MARK: RoutingDelegate\\n  \\n  func setRoute(path: [AnyObject]!) {\\n      _indoorsSurfaceViewController!.surfaceView.showPathWithPoints(path)\\n  }\\n  \\n  // ...\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nFor example, you could update the route every time a new position is calculated by calling the calculateRoute-method in the code shown above.\n\nYou can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example.\n\nIf you want to cancel (remove) already drawn route, you can call this method:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[_indoorsSurfaceViewController.surfaceView.mapScrollView clearRouting];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"_indoorsSurfaceViewController!.surfaceView.mapScrollView.clearRouting()\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:43:04.393Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":4,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"routing-1","sync_unique":"","title":"Routing","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Routing


Calculating and displaying a route on the map is a matter of a few lines too: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n@interface IDViewController () <RoutingDelegate>\n \n// ...\n \n- (void)calculateRoute\n{\n IDSCoordinate* start = [[IDSCoordinate alloc] initWithX:1234 andY:1234 andFloorLevel:0];\n IDSCoordinate* end = [[IDSCoordinate alloc] initWithX:12345 andY:12345 andFloorLevel:0];\n \n [[Indoors instance] routeFromLocation:start toLocation:end delegate:self];\n}\n \n// ...\n \n#pragma mark - RoutingDelegate\n- (void)setRoute:(NSArray *)path\n{\n [self.surfaceBuilder showPathWithPoints:path];\n}\n \n// ...", "language": "objectivec" }, { "code": "class ViewController: UIViewController, RoutingDelegate {\n\n\t// ...\n\n\tfunc calculateRoute() {\n \tvar start = IDSCoordinate(x: 1234, andY: 1234, andFloorLevel: 0);\n \tvar end = IDSCoordinate(x: 12345, andY: 12345, andFloorLevel: 0);\n\n \tIndoors.instance().routeFromLocation(start, toLocation: end, delegate: \tself)\n }\n \n // MARK: RoutingDelegate\n \n func setRoute(path: [AnyObject]!) {\n _indoorsSurfaceViewController!.surfaceView.showPathWithPoints(path)\n }\n \n // ...\n}", "language": "swift", "name": "Swift" } ] } [/block] For example, you could update the route every time a new position is calculated by calling the calculateRoute-method in the code shown above. You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example. If you want to cancel (remove) already drawn route, you can call this method: [block:code] { "codes": [ { "code": "[_indoorsSurfaceViewController.surfaceView.mapScrollView clearRouting];", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.mapScrollView.clearRouting()", "language": "swift", "name": "Swift" } ] } [/block]
Calculating and displaying a route on the map is a matter of a few lines too: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n@interface IDViewController () <RoutingDelegate>\n \n// ...\n \n- (void)calculateRoute\n{\n IDSCoordinate* start = [[IDSCoordinate alloc] initWithX:1234 andY:1234 andFloorLevel:0];\n IDSCoordinate* end = [[IDSCoordinate alloc] initWithX:12345 andY:12345 andFloorLevel:0];\n \n [[Indoors instance] routeFromLocation:start toLocation:end delegate:self];\n}\n \n// ...\n \n#pragma mark - RoutingDelegate\n- (void)setRoute:(NSArray *)path\n{\n [self.surfaceBuilder showPathWithPoints:path];\n}\n \n// ...", "language": "objectivec" }, { "code": "class ViewController: UIViewController, RoutingDelegate {\n\n\t// ...\n\n\tfunc calculateRoute() {\n \tvar start = IDSCoordinate(x: 1234, andY: 1234, andFloorLevel: 0);\n \tvar end = IDSCoordinate(x: 12345, andY: 12345, andFloorLevel: 0);\n\n \tIndoors.instance().routeFromLocation(start, toLocation: end, delegate: \tself)\n }\n \n // MARK: RoutingDelegate\n \n func setRoute(path: [AnyObject]!) {\n _indoorsSurfaceViewController!.surfaceView.showPathWithPoints(path)\n }\n \n // ...\n}", "language": "swift", "name": "Swift" } ] } [/block] For example, you could update the route every time a new position is calculated by calling the calculateRoute-method in the code shown above. You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example. If you want to cancel (remove) already drawn route, you can call this method: [block:code] { "codes": [ { "code": "[_indoorsSurfaceViewController.surfaceView.mapScrollView clearRouting];", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.mapScrollView.clearRouting()", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820bf","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"1. Path Snapping for routing\"\n}\n[/block]\nIf you're fairly certain that a user is going to walk the route that is being displayed right now, we recommend to activate what we call \"route snapping\": the calculated position snaps to the shown route if it is within a certain area of the route.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"From SDK version 3.8 Path Snapping feature is removed from IndoorsSurface, and it can only be accessed directly from the SDK.\"\n}\n[/block]\nSDK methods which now provide path snapping functionality are:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] enableRouteSnappingWithRoute:route];\\n[[Indoors instance] disableRouteSnapping];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().enableRouteSnappingWithRoute(route)\\nIndoors.instance().disableRouteSnapping()\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nBy default, path snapping option is disabled.\n\nWhen route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. When changing distance, we suggest you to use scale between 1000-20000 millimetres. API method is provided below.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setRouteSnappingMaxDistance:maxDistance];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().setRouteSnappingMaxDistance(maxDistance)\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"2. Path Snapping for predefined routes\"\n}\n[/block]\nTo draw predefined routes use [MMT tool](https://my.indoo.rs/javadoc/mmt_guide/). After you create a predefined route, you can enable or disable \"path snapping\" using following SDK methods.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] enablePredefinedRouteSnapping];\\n[[Indoors instance] disablePredefinedRouteSnapping];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().enablePredefinedRouteSnapping()\\nIndoors.instance().disablePredefinedRouteSnapping()\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIndoors SDK allows you to enable or disable \"predefined route snapping\" option at any point by calling public API methods provided above. By default route snapping for predefined routes is disabled.\n\nWhen predefined route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. When changing distance, we suggest you to use scale between 1000-20000 millimetres.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setPredefinedRouteSnappingMaxDistance:maxDistance];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().setPredefinedRouteSnappingMaxDistance(maxDistance)\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-09-23T09:13:28.859Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":5,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"path-snapping","sync_unique":"","title":"Path Snapping","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Path Snapping


[block:api-header] { "type": "basic", "title": "1. Path Snapping for routing" } [/block] If you're fairly certain that a user is going to walk the route that is being displayed right now, we recommend to activate what we call "route snapping": the calculated position snaps to the shown route if it is within a certain area of the route. [block:callout] { "type": "danger", "body": "From SDK version 3.8 Path Snapping feature is removed from IndoorsSurface, and it can only be accessed directly from the SDK." } [/block] SDK methods which now provide path snapping functionality are: [block:code] { "codes": [ { "code": "[[Indoors instance] enableRouteSnappingWithRoute:route];\n[[Indoors instance] disableRouteSnapping];", "language": "objectivec" }, { "code": "Indoors.instance().enableRouteSnappingWithRoute(route)\nIndoors.instance().disableRouteSnapping()", "language": "swift", "name": "Swift" } ] } [/block] By default, path snapping option is disabled. When route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. When changing distance, we suggest you to use scale between 1000-20000 millimetres. API method is provided below. [block:code] { "codes": [ { "code": "[[Indoors instance] setRouteSnappingMaxDistance:maxDistance];", "language": "objectivec" }, { "code": "Indoors.instance().setRouteSnappingMaxDistance(maxDistance)", "language": "swift", "name": "Swift" } ] } [/block] [block:api-header] { "type": "basic", "title": "2. Path Snapping for predefined routes" } [/block] To draw predefined routes use [MMT tool](https://my.indoo.rs/javadoc/mmt_guide/). After you create a predefined route, you can enable or disable "path snapping" using following SDK methods. [block:code] { "codes": [ { "code": "[[Indoors instance] enablePredefinedRouteSnapping];\n[[Indoors instance] disablePredefinedRouteSnapping];", "language": "objectivec" }, { "code": "Indoors.instance().enablePredefinedRouteSnapping()\nIndoors.instance().disablePredefinedRouteSnapping()", "language": "swift", "name": "Swift" } ] } [/block] Indoors SDK allows you to enable or disable "predefined route snapping" option at any point by calling public API methods provided above. By default route snapping for predefined routes is disabled. When predefined route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. When changing distance, we suggest you to use scale between 1000-20000 millimetres. [block:code] { "codes": [ { "code": "[[Indoors instance] setPredefinedRouteSnappingMaxDistance:maxDistance];", "language": "objectivec" }, { "code": "Indoors.instance().setPredefinedRouteSnappingMaxDistance(maxDistance)", "language": "swift", "name": "Swift" } ] } [/block]
[block:api-header] { "type": "basic", "title": "1. Path Snapping for routing" } [/block] If you're fairly certain that a user is going to walk the route that is being displayed right now, we recommend to activate what we call "route snapping": the calculated position snaps to the shown route if it is within a certain area of the route. [block:callout] { "type": "danger", "body": "From SDK version 3.8 Path Snapping feature is removed from IndoorsSurface, and it can only be accessed directly from the SDK." } [/block] SDK methods which now provide path snapping functionality are: [block:code] { "codes": [ { "code": "[[Indoors instance] enableRouteSnappingWithRoute:route];\n[[Indoors instance] disableRouteSnapping];", "language": "objectivec" }, { "code": "Indoors.instance().enableRouteSnappingWithRoute(route)\nIndoors.instance().disableRouteSnapping()", "language": "swift", "name": "Swift" } ] } [/block] By default, path snapping option is disabled. When route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. When changing distance, we suggest you to use scale between 1000-20000 millimetres. API method is provided below. [block:code] { "codes": [ { "code": "[[Indoors instance] setRouteSnappingMaxDistance:maxDistance];", "language": "objectivec" }, { "code": "Indoors.instance().setRouteSnappingMaxDistance(maxDistance)", "language": "swift", "name": "Swift" } ] } [/block] [block:api-header] { "type": "basic", "title": "2. Path Snapping for predefined routes" } [/block] To draw predefined routes use [MMT tool](https://my.indoo.rs/javadoc/mmt_guide/). After you create a predefined route, you can enable or disable "path snapping" using following SDK methods. [block:code] { "codes": [ { "code": "[[Indoors instance] enablePredefinedRouteSnapping];\n[[Indoors instance] disablePredefinedRouteSnapping];", "language": "objectivec" }, { "code": "Indoors.instance().enablePredefinedRouteSnapping()\nIndoors.instance().disablePredefinedRouteSnapping()", "language": "swift", "name": "Swift" } ] } [/block] Indoors SDK allows you to enable or disable "predefined route snapping" option at any point by calling public API methods provided above. By default route snapping for predefined routes is disabled. When predefined route snapping is enabled, you can adjust maximum snapping distance. Default value for distance is 5000 millimetres. When changing distance, we suggest you to use scale between 1000-20000 millimetres. [block:code] { "codes": [ { "code": "[[Indoors instance] setPredefinedRouteSnappingMaxDistance:maxDistance];", "language": "objectivec" }, { "code": "Indoors.instance().setPredefinedRouteSnappingMaxDistance(maxDistance)", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820c0","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"Dot on Rails represents a feature, which can by enabling it enhance user experience of the dot movement. Dot will always stay on the predefined path, and will not jump trough walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif) you can see how this actually works.\n\n\"ISIndoorsSurface.h\" class contains a property with which you can turn on or off this feature. By default Dot on Rails feature is set to NO. If predefined route snapping is disabled, and you try to enable Dot on Rails, predefined route snapping will be automatically enabled.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@property (nonatomic) BOOL enableDotOnRails;\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS\"\n    }\n  ]\n}\n[/block]\nLike path snapping, Dot on Rails feature has it's maximum distance in which it can jump to a predefined path. Value is in millimetres. The default value is 10.000, and recommended values are between 1.000 and 30.000 mm.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@property (nonatomic) double dotOnRailsJumpingDistance;\",\n      \"language\": \"objectivec\",\n      \"name\": \"iOS\"\n    }\n  ]\n}\n[/block]\nExample on how to use it with our ISIndoorsSurfaceViewController class:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsSurfaceVC.surfaceView.dotOnRailsJumpingDistance = 22000;\\nindoorsSurfaceVC.surfaceView.enableDotOnRails = YES;\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"_indoorsSurfaceViewController!.surfaceView.dotOnRailsJumpingDistance = 22000\\n_indoorsSurfaceViewController!.surfaceView.enableDotOnRails = true\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2016-01-22T09:37:10.171Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":6,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"dot-on-rails","sync_unique":"","title":"Dot on Rails","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Dot on Rails


Dot on Rails represents a feature, which can by enabling it enhance user experience of the dot movement. Dot will always stay on the predefined path, and will not jump trough walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif) you can see how this actually works. "ISIndoorsSurface.h" class contains a property with which you can turn on or off this feature. By default Dot on Rails feature is set to NO. If predefined route snapping is disabled, and you try to enable Dot on Rails, predefined route snapping will be automatically enabled. [block:code] { "codes": [ { "code": "@property (nonatomic) BOOL enableDotOnRails;", "language": "objectivec", "name": "iOS" } ] } [/block] Like path snapping, Dot on Rails feature has it's maximum distance in which it can jump to a predefined path. Value is in millimetres. The default value is 10.000, and recommended values are between 1.000 and 30.000 mm. [block:code] { "codes": [ { "code": "@property (nonatomic) double dotOnRailsJumpingDistance;", "language": "objectivec", "name": "iOS" } ] } [/block] Example on how to use it with our ISIndoorsSurfaceViewController class: [block:code] { "codes": [ { "code": "indoorsSurfaceVC.surfaceView.dotOnRailsJumpingDistance = 22000;\nindoorsSurfaceVC.surfaceView.enableDotOnRails = YES;", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.dotOnRailsJumpingDistance = 22000\n_indoorsSurfaceViewController!.surfaceView.enableDotOnRails = true", "language": "swift", "name": "Swift" } ] } [/block]
Dot on Rails represents a feature, which can by enabling it enhance user experience of the dot movement. Dot will always stay on the predefined path, and will not jump trough walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif) you can see how this actually works. "ISIndoorsSurface.h" class contains a property with which you can turn on or off this feature. By default Dot on Rails feature is set to NO. If predefined route snapping is disabled, and you try to enable Dot on Rails, predefined route snapping will be automatically enabled. [block:code] { "codes": [ { "code": "@property (nonatomic) BOOL enableDotOnRails;", "language": "objectivec", "name": "iOS" } ] } [/block] Like path snapping, Dot on Rails feature has it's maximum distance in which it can jump to a predefined path. Value is in millimetres. The default value is 10.000, and recommended values are between 1.000 and 30.000 mm. [block:code] { "codes": [ { "code": "@property (nonatomic) double dotOnRailsJumpingDistance;", "language": "objectivec", "name": "iOS" } ] } [/block] Example on how to use it with our ISIndoorsSurfaceViewController class: [block:code] { "codes": [ { "code": "indoorsSurfaceVC.surfaceView.dotOnRailsJumpingDistance = 22000;\nindoorsSurfaceVC.surfaceView.enableDotOnRails = YES;", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.dotOnRailsJumpingDistance = 22000\n_indoorsSurfaceViewController!.surfaceView.enableDotOnRails = true", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820c1","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example.\n\nAnother way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route them to where they want to go.\n\nYou can access the list of all available zones by accessing NSMutableArray property \"zones\" from IDSFloor object. This property contains all available zones, assigned to the specific floor. List of floors is available from IDSBuilding object as a NSMutableDictionary property \"floors\".\nExample code on how to access all zones: \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"NSMutableArray *allZones = [NSMutableArray array];\\nfor (IDSFloor *floor in building.floors.allValues) {\\n\\t\\t[allZones addObjectsFromArray:floor.zones];\\n}\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"var allZones = NSMutableArray()\\nfor floor in building.floors.allValues as! [IDSFloor] {\\n    allZones.addObjectsFromArray(floor.zones as [AnyObject])\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:46:54.480Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":7,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"zones-1","sync_unique":"","title":"Zones","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Zones


You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route them to where they want to go. You can access the list of all available zones by accessing NSMutableArray property "zones" from IDSFloor object. This property contains all available zones, assigned to the specific floor. List of floors is available from IDSBuilding object as a NSMutableDictionary property "floors". Example code on how to access all zones: [block:code] { "codes": [ { "code": "NSMutableArray *allZones = [NSMutableArray array];\nfor (IDSFloor *floor in building.floors.allValues) {\n\t\t[allZones addObjectsFromArray:floor.zones];\n}", "language": "objectivec" }, { "code": "var allZones = NSMutableArray()\nfor floor in building.floors.allValues as! [IDSFloor] {\n allZones.addObjectsFromArray(floor.zones as [AnyObject])\n}", "language": "swift", "name": "Swift" } ] } [/block]
You can use zones for identification of rooms, shops, or more generally speaking any area of interest. If a user enters a zone, you could show a notification and offer a discount for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route them to where they want to go. You can access the list of all available zones by accessing NSMutableArray property "zones" from IDSFloor object. This property contains all available zones, assigned to the specific floor. List of floors is available from IDSBuilding object as a NSMutableDictionary property "floors". Example code on how to access all zones: [block:code] { "codes": [ { "code": "NSMutableArray *allZones = [NSMutableArray array];\nfor (IDSFloor *floor in building.floors.allValues) {\n\t\t[allZones addObjectsFromArray:floor.zones];\n}", "language": "objectivec" }, { "code": "var allZones = NSMutableArray()\nfor floor in building.floors.allValues as! [IDSFloor] {\n allZones.addObjectsFromArray(floor.zones as [AnyObject])\n}", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820c2","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Depending on your specific use case, the user might only be interested to know in which room / shop he's currently located. If that's the case in your app, you should use something like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[_surfaceViewController.surfaceView setZoneDisplayMode:IndoorsSurfaceZoneDisplayModeUserCurrentLocation];\\n_indoorsSurfaceViewController.surfaceView.showsUserPosition = NO; \",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"_indoorsSurfaceViewController!.surfaceView.setZoneDisplayMode(IndoorsSurfaceZoneDisplayModes.UserCurrentLocation)\\n_indoorsSurfaceViewController!.surfaceView.showsUserPosition = false\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nIf you want to show the exact position of the user (\"Expert Mode\", aka \"Fingerprinting\") you could change the icon of the current user position like this. Please also see the header documentation for more customisation options.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// This icon will be used when the user's orientation is known\\n// and userPositionIconIndicatesUserOrientation is set to YES.\\n_surfaceViewController.surfaceView.userPositionIcon = [UIImage imageNamed:@\\\"YOUR_ARROW_IMAGE\\\"];\\n\\n// This icon will be used when the user's orientation is not known\\n// or userPositionIconIndicatesUserOrientation is set to NO.\\n_surfaceViewController.surfaceView.noOrientationUserPositionIcon = [UIImage imageNamed:@\\\"YOUR_DOT_IMAGE\\\"];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// This icon will be used when the user's orientation is known\\n// and userPositionIconIndicatesUserOrientation is set to YES.\\n_indoorsSurfaceViewController!.surfaceView.userPositionIcon = UIImage(named:\\\"YOUR_ARROW_IMAGE\\\")\\n\\n// This icon will be used when the user's orientation is not known\\n// or userPositionIconIndicatesUserOrientation is set to NO.\\n_indoorsSurfaceViewController!.surfaceView.noOrientationUserPositionIcon = UIImage(named: \\\"YOUR_DOT_IMAGE\\\")\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nAnother use case might require you to simply show all available zones, which is also possible:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[_surfaceViewController.surfaceView setZoneDisplayMode:IndoorsSurfaceZoneDisplayModeAllAvailable];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"_indoorsSurfaceViewController!.surfaceView.setZoneDisplayMode(IndoorsSurfaceZoneDisplayModes.AllAvailable)\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:47:48.820Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":8,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"styling-1","sync_unique":"","title":"Styling","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Styling


Depending on your specific use case, the user might only be interested to know in which room / shop he's currently located. If that's the case in your app, you should use something like this: [block:code] { "codes": [ { "code": "[_surfaceViewController.surfaceView setZoneDisplayMode:IndoorsSurfaceZoneDisplayModeUserCurrentLocation];\n_indoorsSurfaceViewController.surfaceView.showsUserPosition = NO; ", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.setZoneDisplayMode(IndoorsSurfaceZoneDisplayModes.UserCurrentLocation)\n_indoorsSurfaceViewController!.surfaceView.showsUserPosition = false", "language": "swift", "name": "Swift" } ] } [/block] If you want to show the exact position of the user ("Expert Mode", aka "Fingerprinting") you could change the icon of the current user position like this. Please also see the header documentation for more customisation options. [block:code] { "codes": [ { "code": "// This icon will be used when the user's orientation is known\n// and userPositionIconIndicatesUserOrientation is set to YES.\n_surfaceViewController.surfaceView.userPositionIcon = [UIImage imageNamed:@\"YOUR_ARROW_IMAGE\"];\n\n// This icon will be used when the user's orientation is not known\n// or userPositionIconIndicatesUserOrientation is set to NO.\n_surfaceViewController.surfaceView.noOrientationUserPositionIcon = [UIImage imageNamed:@\"YOUR_DOT_IMAGE\"];", "language": "objectivec" }, { "code": "// This icon will be used when the user's orientation is known\n// and userPositionIconIndicatesUserOrientation is set to YES.\n_indoorsSurfaceViewController!.surfaceView.userPositionIcon = UIImage(named:\"YOUR_ARROW_IMAGE\")\n\n// This icon will be used when the user's orientation is not known\n// or userPositionIconIndicatesUserOrientation is set to NO.\n_indoorsSurfaceViewController!.surfaceView.noOrientationUserPositionIcon = UIImage(named: \"YOUR_DOT_IMAGE\")", "language": "swift", "name": "Swift" } ] } [/block] Another use case might require you to simply show all available zones, which is also possible: [block:code] { "codes": [ { "code": "[_surfaceViewController.surfaceView setZoneDisplayMode:IndoorsSurfaceZoneDisplayModeAllAvailable];", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.setZoneDisplayMode(IndoorsSurfaceZoneDisplayModes.AllAvailable)", "language": "swift", "name": "Swift" } ] } [/block]
Depending on your specific use case, the user might only be interested to know in which room / shop he's currently located. If that's the case in your app, you should use something like this: [block:code] { "codes": [ { "code": "[_surfaceViewController.surfaceView setZoneDisplayMode:IndoorsSurfaceZoneDisplayModeUserCurrentLocation];\n_indoorsSurfaceViewController.surfaceView.showsUserPosition = NO; ", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.setZoneDisplayMode(IndoorsSurfaceZoneDisplayModes.UserCurrentLocation)\n_indoorsSurfaceViewController!.surfaceView.showsUserPosition = false", "language": "swift", "name": "Swift" } ] } [/block] If you want to show the exact position of the user ("Expert Mode", aka "Fingerprinting") you could change the icon of the current user position like this. Please also see the header documentation for more customisation options. [block:code] { "codes": [ { "code": "// This icon will be used when the user's orientation is known\n// and userPositionIconIndicatesUserOrientation is set to YES.\n_surfaceViewController.surfaceView.userPositionIcon = [UIImage imageNamed:@\"YOUR_ARROW_IMAGE\"];\n\n// This icon will be used when the user's orientation is not known\n// or userPositionIconIndicatesUserOrientation is set to NO.\n_surfaceViewController.surfaceView.noOrientationUserPositionIcon = [UIImage imageNamed:@\"YOUR_DOT_IMAGE\"];", "language": "objectivec" }, { "code": "// This icon will be used when the user's orientation is known\n// and userPositionIconIndicatesUserOrientation is set to YES.\n_indoorsSurfaceViewController!.surfaceView.userPositionIcon = UIImage(named:\"YOUR_ARROW_IMAGE\")\n\n// This icon will be used when the user's orientation is not known\n// or userPositionIconIndicatesUserOrientation is set to NO.\n_indoorsSurfaceViewController!.surfaceView.noOrientationUserPositionIcon = UIImage(named: \"YOUR_DOT_IMAGE\")", "language": "swift", "name": "Swift" } ] } [/block] Another use case might require you to simply show all available zones, which is also possible: [block:code] { "codes": [ { "code": "[_surfaceViewController.surfaceView setZoneDisplayMode:IndoorsSurfaceZoneDisplayModeAllAvailable];", "language": "objectivec" }, { "code": "_indoorsSurfaceViewController!.surfaceView.setZoneDisplayMode(IndoorsSurfaceZoneDisplayModes.AllAvailable)", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820c3","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"It is also possible to add overlays on top of our map:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n \\n// ...\\n \\n- (void)buildingLoaded:(IDSBuilding *)building\\n{\\n    [self addImageOverlay];\\n}\\n \\n- (void)addImageOverlay\\n{\\n    // TODO: copy a file named \\\"test.png\\\" into your XCode-project!\\n    UIImage *image = [UIImage imageNamed:@\\\"test\\\"];\\n    CGFloat ratio = image.size.height / image.size.width;\\n    \\n    ISImageMapOverlay *imageOverlay = [[ISImageMapOverlay alloc] initWithOverlayBounds:\\n                                       CGRectMake (0, 0, 10000, 10000 * ratio)];\\n    imageOverlay.imageView.image = image;\\n    imageOverlay.userInteractionEnabled = YES;\\n    \\n    UIGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self \\n                                          action:@selector(handleTap:)];\\n    [imageOverlay addGestureRecognizer:tapRecognizer];\\n    \\n    [_surfaceViewController.surfaceView.mapScrollView addOverlay:imageOverlay toFloorLevel:0];\\n}\\n \\n- (void)handleTap:(UIGestureRecognizer *)gestureRecognizer\\n{\\n    CGPoint point = [gestureRecognizer locationInView:_surfaceViewController.surfaceView.mapScrollView];\\n    IDSCoordinate *coord = [_surfaceViewController.surfaceView.mapScrollView coordinateForPoint:point];\\n    NSLog(@\\\"Test image tapped! Location: x=%d y=%d\\\", coord.x, coord.y);\\n}\\n \\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// ...\\n\\nfunc buildingLoaded(building : IDSBuilding!) {\\n    addImageOverlay()\\n}\\n\\nfunc addImageOverlay() {\\n    // TODO: copy a file named \\\"test.png\\\" into your XCode-project!\\n    let image = UIImage(named: \\\"test\\\")\\n    let ratio = image!.size.height / image!.size.width\\n\\n    let imageOverlay = ISImageMapOverlay(overlayBounds: CGRectMake(0, 0, 10000, 10000 * ratio))\\n    imageOverlay.imageView.image = image\\n    imageOverlay.userInteractionEnabled = true\\n\\n    let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:)))\\n    imageOverlay.addGestureRecognizer(tapRecognizer)\\n        \\n    _surfaceViewController!.surfaceView.mapScrollView.addOverlay(imageOverlay, toFloorLevel: 0)\\n}\\n\\nfunc handleTap(gestureRecognizer: UIGestureRecognizer) {\\n    let point = gestureRecognizer.locationInView(_surfaceViewController!.surfaceView.mapScrollView)\\n    let coord = _surfaceViewController!.surfaceView.mapScrollView.coordinateForPoint(point)\\n    NSLog(\\\"Test image tapped! Location x=%d  y=%d\\\", coord.x, coord.y)    \\n}\\n\\n// ...\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nWhen map is zoomed in/out overlays will zoom in/out with the map. This is considered experimental for now. Use with caution!","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:49:37.363Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":9,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"overlays-1","sync_unique":"","title":"Overlays","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Overlays


It is also possible to add overlays on top of our map: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n// ...\n \n- (void)buildingLoaded:(IDSBuilding *)building\n{\n [self addImageOverlay];\n}\n \n- (void)addImageOverlay\n{\n // TODO: copy a file named \"test.png\" into your XCode-project!\n UIImage *image = [UIImage imageNamed:@\"test\"];\n CGFloat ratio = image.size.height / image.size.width;\n \n ISImageMapOverlay *imageOverlay = [[ISImageMapOverlay alloc] initWithOverlayBounds:\n CGRectMake (0, 0, 10000, 10000 * ratio)];\n imageOverlay.imageView.image = image;\n imageOverlay.userInteractionEnabled = YES;\n \n UIGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self \n action:@selector(handleTap:)];\n [imageOverlay addGestureRecognizer:tapRecognizer];\n \n [_surfaceViewController.surfaceView.mapScrollView addOverlay:imageOverlay toFloorLevel:0];\n}\n \n- (void)handleTap:(UIGestureRecognizer *)gestureRecognizer\n{\n CGPoint point = [gestureRecognizer locationInView:_surfaceViewController.surfaceView.mapScrollView];\n IDSCoordinate *coord = [_surfaceViewController.surfaceView.mapScrollView coordinateForPoint:point];\n NSLog(@\"Test image tapped! Location: x=%d y=%d\", coord.x, coord.y);\n}\n \n// ...", "language": "objectivec" }, { "code": "// ...\n\nfunc buildingLoaded(building : IDSBuilding!) {\n addImageOverlay()\n}\n\nfunc addImageOverlay() {\n // TODO: copy a file named \"test.png\" into your XCode-project!\n let image = UIImage(named: \"test\")\n let ratio = image!.size.height / image!.size.width\n\n let imageOverlay = ISImageMapOverlay(overlayBounds: CGRectMake(0, 0, 10000, 10000 * ratio))\n imageOverlay.imageView.image = image\n imageOverlay.userInteractionEnabled = true\n\n let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:)))\n imageOverlay.addGestureRecognizer(tapRecognizer)\n \n _surfaceViewController!.surfaceView.mapScrollView.addOverlay(imageOverlay, toFloorLevel: 0)\n}\n\nfunc handleTap(gestureRecognizer: UIGestureRecognizer) {\n let point = gestureRecognizer.locationInView(_surfaceViewController!.surfaceView.mapScrollView)\n let coord = _surfaceViewController!.surfaceView.mapScrollView.coordinateForPoint(point)\n NSLog(\"Test image tapped! Location x=%d y=%d\", coord.x, coord.y) \n}\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block] When map is zoomed in/out overlays will zoom in/out with the map. This is considered experimental for now. Use with caution!
It is also possible to add overlays on top of our map: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n// ...\n \n- (void)buildingLoaded:(IDSBuilding *)building\n{\n [self addImageOverlay];\n}\n \n- (void)addImageOverlay\n{\n // TODO: copy a file named \"test.png\" into your XCode-project!\n UIImage *image = [UIImage imageNamed:@\"test\"];\n CGFloat ratio = image.size.height / image.size.width;\n \n ISImageMapOverlay *imageOverlay = [[ISImageMapOverlay alloc] initWithOverlayBounds:\n CGRectMake (0, 0, 10000, 10000 * ratio)];\n imageOverlay.imageView.image = image;\n imageOverlay.userInteractionEnabled = YES;\n \n UIGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self \n action:@selector(handleTap:)];\n [imageOverlay addGestureRecognizer:tapRecognizer];\n \n [_surfaceViewController.surfaceView.mapScrollView addOverlay:imageOverlay toFloorLevel:0];\n}\n \n- (void)handleTap:(UIGestureRecognizer *)gestureRecognizer\n{\n CGPoint point = [gestureRecognizer locationInView:_surfaceViewController.surfaceView.mapScrollView];\n IDSCoordinate *coord = [_surfaceViewController.surfaceView.mapScrollView coordinateForPoint:point];\n NSLog(@\"Test image tapped! Location: x=%d y=%d\", coord.x, coord.y);\n}\n \n// ...", "language": "objectivec" }, { "code": "// ...\n\nfunc buildingLoaded(building : IDSBuilding!) {\n addImageOverlay()\n}\n\nfunc addImageOverlay() {\n // TODO: copy a file named \"test.png\" into your XCode-project!\n let image = UIImage(named: \"test\")\n let ratio = image!.size.height / image!.size.width\n\n let imageOverlay = ISImageMapOverlay(overlayBounds: CGRectMake(0, 0, 10000, 10000 * ratio))\n imageOverlay.imageView.image = image\n imageOverlay.userInteractionEnabled = true\n\n let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.handleTap(_:)))\n imageOverlay.addGestureRecognizer(tapRecognizer)\n \n _surfaceViewController!.surfaceView.mapScrollView.addOverlay(imageOverlay, toFloorLevel: 0)\n}\n\nfunc handleTap(gestureRecognizer: UIGestureRecognizer) {\n let point = gestureRecognizer.locationInView(_surfaceViewController!.surfaceView.mapScrollView)\n let coord = _surfaceViewController!.surfaceView.mapScrollView.coordinateForPoint(point)\n NSLog(\"Test image tapped! Location x=%d y=%d\", coord.x, coord.y) \n}\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block] When map is zoomed in/out overlays will zoom in/out with the map. This is considered experimental for now. Use with caution!
{"__v":0,"_id":"57e3bcc2378b341700c820c4","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"Annotations are also one way of adding overlays on the map, but the main difference is that annotations are scaling each time map is zoomed in or out. Example for annotation usage is user location dot. \n\nCode explaining how to create your own annotation can be found below:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n \\n// ...\\n \\n- (void)buildingLoaded:(IDSBuilding *)building\\n{\\n    [self addImageAnnotation];\\n}\\n \\n- (void)addImageAnnotation\\n{\\n    // TODO: copy a file named \\\"test.png\\\" into your XCode-project!\\n    UIImage *image = [UIImage imageNamed:@\\\"test\\\"];\\n    \\n    ISImageAnnotationView *imageAnnotation = [[ISImageAnnotationView alloc] initWithCoordinate:coordinate image:image position:position];\\n    \\n    [_surfaceViewController.surfaceView.mapScrollView addAnnotation:imageAnnotation];\\n}\\n \\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// ...\\n\\nfunc buildingLoaded(building : IDSBuilding!) {\\n    addImageAnnotation()\\n}\\n\\nfunc addImageAnnotation() {\\n    // TODO: copy a file named \\\"test.png\\\" into your XCode-project!\\n    let image = UIImage(named: \\\"test\\\")\\n    \\n    let imageAnnotation = ISImageAnnotationView(coordinate: coordinate, image: image, position: position)\\n        \\n    _surfaceViewController!.surfaceView.mapScrollView .addAnnotation(imageAnnotation)\\n}\\n\\n// ...\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nCoordinate represents point of interest to the annotation. Position determine how will annotation be oriented around the coordinate. Position values are: ISAnnotationViewPositionTop, ISAnnotationViewPositionRigh, ISAnnotationViewPositionBottom, ISAnnotationViewPositionLeft and ISAnnotationViewPositionCenter.","category":"57e3bcc2378b341700c82092","createdAt":"2015-12-23T10:01:23.083Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":10,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"annotations","sync_unique":"","title":"Annotations","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Annotations


Annotations are also one way of adding overlays on the map, but the main difference is that annotations are scaling each time map is zoomed in or out. Example for annotation usage is user location dot. Code explaining how to create your own annotation can be found below: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n// ...\n \n- (void)buildingLoaded:(IDSBuilding *)building\n{\n [self addImageAnnotation];\n}\n \n- (void)addImageAnnotation\n{\n // TODO: copy a file named \"test.png\" into your XCode-project!\n UIImage *image = [UIImage imageNamed:@\"test\"];\n \n ISImageAnnotationView *imageAnnotation = [[ISImageAnnotationView alloc] initWithCoordinate:coordinate image:image position:position];\n \n [_surfaceViewController.surfaceView.mapScrollView addAnnotation:imageAnnotation];\n}\n \n// ...", "language": "objectivec" }, { "code": "// ...\n\nfunc buildingLoaded(building : IDSBuilding!) {\n addImageAnnotation()\n}\n\nfunc addImageAnnotation() {\n // TODO: copy a file named \"test.png\" into your XCode-project!\n let image = UIImage(named: \"test\")\n \n let imageAnnotation = ISImageAnnotationView(coordinate: coordinate, image: image, position: position)\n \n _surfaceViewController!.surfaceView.mapScrollView .addAnnotation(imageAnnotation)\n}\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block] Coordinate represents point of interest to the annotation. Position determine how will annotation be oriented around the coordinate. Position values are: ISAnnotationViewPositionTop, ISAnnotationViewPositionRigh, ISAnnotationViewPositionBottom, ISAnnotationViewPositionLeft and ISAnnotationViewPositionCenter.
Annotations are also one way of adding overlays on the map, but the main difference is that annotations are scaling each time map is zoomed in or out. Example for annotation usage is user location dot. Code explaining how to create your own annotation can be found below: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n// ...\n \n- (void)buildingLoaded:(IDSBuilding *)building\n{\n [self addImageAnnotation];\n}\n \n- (void)addImageAnnotation\n{\n // TODO: copy a file named \"test.png\" into your XCode-project!\n UIImage *image = [UIImage imageNamed:@\"test\"];\n \n ISImageAnnotationView *imageAnnotation = [[ISImageAnnotationView alloc] initWithCoordinate:coordinate image:image position:position];\n \n [_surfaceViewController.surfaceView.mapScrollView addAnnotation:imageAnnotation];\n}\n \n// ...", "language": "objectivec" }, { "code": "// ...\n\nfunc buildingLoaded(building : IDSBuilding!) {\n addImageAnnotation()\n}\n\nfunc addImageAnnotation() {\n // TODO: copy a file named \"test.png\" into your XCode-project!\n let image = UIImage(named: \"test\")\n \n let imageAnnotation = ISImageAnnotationView(coordinate: coordinate, image: image, position: position)\n \n _surfaceViewController!.surfaceView.mapScrollView .addAnnotation(imageAnnotation)\n}\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block] Coordinate represents point of interest to the annotation. Position determine how will annotation be oriented around the coordinate. Position values are: ISAnnotationViewPositionTop, ISAnnotationViewPositionRigh, ISAnnotationViewPositionBottom, ISAnnotationViewPositionLeft and ISAnnotationViewPositionCenter.
{"__v":2,"_id":"57e3bcc2378b341700c820c5","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Our SDK allows you to bundle maps directly with your app, so that users won't have to download them separately when opening the app for the first time. This is especially useful if you expect your users to have no internet connectivity when they launch your app for the first time.\n\nFirst you have to download the map file directly from the server. Here is a [curl](http://curl.haxx.se/) command to do that (you have to replace \"API_KEY\" and \"BUILDING_ID\" with the proper values):\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"curl -X GET -H \\\"x-indoors-api-key: API_KEY\\\" -H \\\"Accept: application/x-com.customlbs.indoorsphonemap+zip\\\" https://api.indoo.rs/indoors/rest/buildings/BUILDING_ID/mapfile -o building.idp\",\n      \"language\": \"shell\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"command execution\",\n  \"body\": \"Make sure you are located in the project folder when executing curl command.\"\n}\n[/block]\nThe resulting file needs to have an \".idp\" file extension. Now drag this file into your XCode-project and make sure to add it to the appropriate target(s). You can include multiple maps (e.g. call them <BUILDING_ID>.idp)\n\nThe SDK will now check if there is a matching map included in your app every time you request to load a building. Please note, that the SDK will only load the map from inside the app if the building IDs match exactly. In order to find out what the building ID of your map is, open the MMT and find your building under \"File\" - \"My buildings...\".\n\nUpdates to your map will be downloaded automatically, as the SDK checks for new versions of the map in the background (when the app is running). Localisation is restarted automatically after the updated map has been downloaded.\n\nNote: In order to get the map downloaded, the SDK has to be running. If the SDK is turned off (or the map is not in the foreground) no downloads will be initiated.\n\nIf you don't want the SDK to download a new map version when there is a new one available, set \"alwaysDownloadNewBuildingVersion\" parameter to NO. Default value is YES which means your new version will be downloaded in the background.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@property (nonatomic) BOOL alwaysDownloadNewBuildingVersion;\",\n      \"language\": \"objectivec\",\n      \"name\": \"Indoors.h\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:50:03.921Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","next":{"description":"","pages":[]},"order":11,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"map-with-app-1","sync_unique":"","title":"Map with App","type":"basic","updates":["5840043fc0507319000634b2"],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Map with App


Our SDK allows you to bundle maps directly with your app, so that users won't have to download them separately when opening the app for the first time. This is especially useful if you expect your users to have no internet connectivity when they launch your app for the first time. First you have to download the map file directly from the server. Here is a [curl](http://curl.haxx.se/) command to do that (you have to replace "API_KEY" and "BUILDING_ID" with the proper values): [block:code] { "codes": [ { "code": "curl -X GET -H \"x-indoors-api-key: API_KEY\" -H \"Accept: application/x-com.customlbs.indoorsphonemap+zip\" https://api.indoo.rs/indoors/rest/buildings/BUILDING_ID/mapfile -o building.idp", "language": "shell" } ] } [/block] [block:callout] { "type": "warning", "title": "command execution", "body": "Make sure you are located in the project folder when executing curl command." } [/block] The resulting file needs to have an ".idp" file extension. Now drag this file into your XCode-project and make sure to add it to the appropriate target(s). You can include multiple maps (e.g. call them <BUILDING_ID>.idp) The SDK will now check if there is a matching map included in your app every time you request to load a building. Please note, that the SDK will only load the map from inside the app if the building IDs match exactly. In order to find out what the building ID of your map is, open the MMT and find your building under "File" - "My buildings...". Updates to your map will be downloaded automatically, as the SDK checks for new versions of the map in the background (when the app is running). Localisation is restarted automatically after the updated map has been downloaded. Note: In order to get the map downloaded, the SDK has to be running. If the SDK is turned off (or the map is not in the foreground) no downloads will be initiated. If you don't want the SDK to download a new map version when there is a new one available, set "alwaysDownloadNewBuildingVersion" parameter to NO. Default value is YES which means your new version will be downloaded in the background. [block:code] { "codes": [ { "code": "@property (nonatomic) BOOL alwaysDownloadNewBuildingVersion;", "language": "objectivec", "name": "Indoors.h" } ] } [/block]
Our SDK allows you to bundle maps directly with your app, so that users won't have to download them separately when opening the app for the first time. This is especially useful if you expect your users to have no internet connectivity when they launch your app for the first time. First you have to download the map file directly from the server. Here is a [curl](http://curl.haxx.se/) command to do that (you have to replace "API_KEY" and "BUILDING_ID" with the proper values): [block:code] { "codes": [ { "code": "curl -X GET -H \"x-indoors-api-key: API_KEY\" -H \"Accept: application/x-com.customlbs.indoorsphonemap+zip\" https://api.indoo.rs/indoors/rest/buildings/BUILDING_ID/mapfile -o building.idp", "language": "shell" } ] } [/block] [block:callout] { "type": "warning", "title": "command execution", "body": "Make sure you are located in the project folder when executing curl command." } [/block] The resulting file needs to have an ".idp" file extension. Now drag this file into your XCode-project and make sure to add it to the appropriate target(s). You can include multiple maps (e.g. call them <BUILDING_ID>.idp) The SDK will now check if there is a matching map included in your app every time you request to load a building. Please note, that the SDK will only load the map from inside the app if the building IDs match exactly. In order to find out what the building ID of your map is, open the MMT and find your building under "File" - "My buildings...". Updates to your map will be downloaded automatically, as the SDK checks for new versions of the map in the background (when the app is running). Localisation is restarted automatically after the updated map has been downloaded. Note: In order to get the map downloaded, the SDK has to be running. If the SDK is turned off (or the map is not in the foreground) no downloads will be initiated. If you don't want the SDK to download a new map version when there is a new one available, set "alwaysDownloadNewBuildingVersion" parameter to NO. Default value is YES which means your new version will be downloaded in the background. [block:code] { "codes": [ { "code": "@property (nonatomic) BOOL alwaysDownloadNewBuildingVersion;", "language": "objectivec", "name": "Indoors.h" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820c6","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"Calculating a position while your app is not visible to the user is currently not possible. Please refer to the standard iBeacon API provided by iOS for such usecases.","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:51:04.851Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":12,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"background-only-localization","sync_unique":"","title":"Background-only localization","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Background-only localization


Calculating a position while your app is not visible to the user is currently not possible. Please refer to the standard iBeacon API provided by iOS for such usecases.
Calculating a position while your app is not visible to the user is currently not possible. Please refer to the standard iBeacon API provided by iOS for such usecases.
{"__v":0,"_id":"57e3bcc2378b341700c820c7","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"If you want to use our SDK only to calculate a position - without displaying it on our Surface - you can do so like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n \\n// ...\\n \\n- (void)viewDidLoad\\n{\\n    // ...\\n    \\n    __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\\\"YOUR-API-KEY\\\" andServiceDelegate:nil]; // For the sake of simplicity we pass nil as delegate.\\n  \\n  [[Indoors instance] registerLocationListener:self];\\n    \\n  IDSBuilding* building = [[IDSBuilding alloc] init];\\n  building.buildingID = 12345678; // REPLACE WITH YOUR BUILDING ID\\n \\n  [[Indoors instance] getBuilding:building forRequestDelegate:nil]; // For the sake of simplicity we pass nil as delegate.\\n}\\n\\n#pragma mark - IndoorsLocationListener\\n  \\n- (void)positionUpdated:(IDSCoordinate *)userPosition\\n{\\n\\t// React to new position.\\n}\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// ...\\n \\noverride func viewDidLoad() {\\n    // ...\\n    _ = Indoors(licenseKey: \\\"YOUR-API-KEY\\\", andServiceDelegate: self) // For the sake of simplicity we pass nil as delegate.\\n  \\n  Indoors.instance().registerLocationListener(self)\\n    \\n  let building = IDSBuilding()\\n  building.buildingID = 12345678 // REPLACE WITH YOUR BUILDING ID\\n  \\n  Indoors.instance().getBuilding(building, forRequestDelegate: nil) // For the sake of simplicity we pass nil as delegate.\\n}\\n\\n// MARK: IndoorsLocationListener\\n    \\nfunc positionUpdated(userPosition: IDSCoordinate!) {\\n    //React to new position.\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nThis is useful for apps which already have their own map rendering in place.","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:51:35.402Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":13,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"localization-without-ui","sync_unique":"","title":"Localization without UI","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Localization without UI


If you want to use our SDK only to calculate a position - without displaying it on our Surface - you can do so like this: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n// ...\n \n- (void)viewDidLoad\n{\n // ...\n \n __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\"YOUR-API-KEY\" andServiceDelegate:nil]; // For the sake of simplicity we pass nil as delegate.\n \n [[Indoors instance] registerLocationListener:self];\n \n IDSBuilding* building = [[IDSBuilding alloc] init];\n building.buildingID = 12345678; // REPLACE WITH YOUR BUILDING ID\n \n [[Indoors instance] getBuilding:building forRequestDelegate:nil]; // For the sake of simplicity we pass nil as delegate.\n}\n\n#pragma mark - IndoorsLocationListener\n \n- (void)positionUpdated:(IDSCoordinate *)userPosition\n{\n\t// React to new position.\n}", "language": "objectivec" }, { "code": "// ...\n \noverride func viewDidLoad() {\n // ...\n _ = Indoors(licenseKey: \"YOUR-API-KEY\", andServiceDelegate: self) // For the sake of simplicity we pass nil as delegate.\n \n Indoors.instance().registerLocationListener(self)\n \n let building = IDSBuilding()\n building.buildingID = 12345678 // REPLACE WITH YOUR BUILDING ID\n \n Indoors.instance().getBuilding(building, forRequestDelegate: nil) // For the sake of simplicity we pass nil as delegate.\n}\n\n// MARK: IndoorsLocationListener\n \nfunc positionUpdated(userPosition: IDSCoordinate!) {\n //React to new position.\n}", "language": "swift", "name": "Swift" } ] } [/block] This is useful for apps which already have their own map rendering in place.
If you want to use our SDK only to calculate a position - without displaying it on our Surface - you can do so like this: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n \n// ...\n \n- (void)viewDidLoad\n{\n // ...\n \n __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:@\"YOUR-API-KEY\" andServiceDelegate:nil]; // For the sake of simplicity we pass nil as delegate.\n \n [[Indoors instance] registerLocationListener:self];\n \n IDSBuilding* building = [[IDSBuilding alloc] init];\n building.buildingID = 12345678; // REPLACE WITH YOUR BUILDING ID\n \n [[Indoors instance] getBuilding:building forRequestDelegate:nil]; // For the sake of simplicity we pass nil as delegate.\n}\n\n#pragma mark - IndoorsLocationListener\n \n- (void)positionUpdated:(IDSCoordinate *)userPosition\n{\n\t// React to new position.\n}", "language": "objectivec" }, { "code": "// ...\n \noverride func viewDidLoad() {\n // ...\n _ = Indoors(licenseKey: \"YOUR-API-KEY\", andServiceDelegate: self) // For the sake of simplicity we pass nil as delegate.\n \n Indoors.instance().registerLocationListener(self)\n \n let building = IDSBuilding()\n building.buildingID = 12345678 // REPLACE WITH YOUR BUILDING ID\n \n Indoors.instance().getBuilding(building, forRequestDelegate: nil) // For the sake of simplicity we pass nil as delegate.\n}\n\n// MARK: IndoorsLocationListener\n \nfunc positionUpdated(userPosition: IDSCoordinate!) {\n //React to new position.\n}", "language": "swift", "name": "Swift" } ] } [/block] This is useful for apps which already have their own map rendering in place.
{"__v":0,"_id":"57e3bcc2378b341700c820c8","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"If you want to show a map without actually starting localization (e.g. because you don't have a working beacon infrastructure set up yet), you can do so by combining the new IDSBuildingManager with ISIndoorsSurfaceViewController. Use the IDSBuildingManager to load a building and pass it to the ISIndoorsSurfaceViewControllers surface view. Be sure to set the floor level too. Here is a complete example:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n\\n// ...\\n\\n- (void)viewDidLoad \\n{\\n    [super viewDidLoad];\\n    \\n    NSString *apiKey = @\\\"YOUR_API_KEY\\\"; // REPLACE WITH YOUR API KEY\\n    NSUInteger buildingId = 12345678; // REPLACE WITH YOUR BUILDING ID\\n    \\n    __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:apiKey andServiceDelegate:nil];\\n    \\n    _indoorsSurfaceViewController = [[ISIndoorsSurfaceViewController alloc] init];\\n    \\n    [self addSurfaceAsChildViewController];\\n    \\n    IDSBuildingManager *buildingManager = [[IDSBuildingManager alloc] init];\\n    [buildingManager loadBuildingWithId:buildingId progress:^(double progress, NSUInteger currentStep, NSUInteger totalSteps, NSString *phase) {\\n        NSLog(@\\\"Progress: %f\\\", progress);\\n    } completion:^(IDSBuilding *building, NSError *error) {\\n        if (error) {\\n            NSLog(@\\\"An error occured: %@ Reason: %@\\\", error.localizedDescription, error.localizedFailureReason);\\n            return;\\n        }\\n        \\n        [_indoorsSurfaceViewController.surfaceView setBuildingForSurface:building];\\n        [_indoorsSurfaceViewController.surfaceView setFloorLevel:[building getInitialFloorLevel]];\\n    }];\\n}\\n\\n- (void)addSurfaceAsChildViewController\\n{\\n    [self addChildViewController:_indoorsSurfaceViewController];\\n    _indoorsSurfaceViewController.view.frame = self.view.frame;\\n    [self.view addSubview:_indoorsSurfaceViewController.view];\\n    [_indoorsSurfaceViewController didMoveToParentViewController:self];\\n}\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"override func viewDidLoad() {\\n    super.viewDidLoad()\\n\\n    _ = Indoors(licenseKey:\\\"YOUR-API-KEY\\\", andServiceDelegate:nil)\\n\\n    _indoorsSurfaceViewController = ISIndoorsSurfaceViewController()\\n    _indoorsSurfaceViewController!.delegate = self\\n\\n    addSurfaceAsChildViewController()\\n\\n    let buildingManager = IDSBuildingManager()\\n    buildingManager.loadBuildingWithId(buildingId, progress: {(progress: Int, currentStep: Int, totalSteps: Int, phase: String!) -> Void in\\n        NSLog(\\\"Progress: %f\\\", progress)\\n    }, completion: {(building: IDSBuilding!, error: NSError!) -> Void in\\n        if error != nil {\\n//           NSLog(\\\"An error occured: %@ Reason: %@\\\", error.localizedDescription, error.localizedFailureReason)\\n             return\\n         }\\n    \\t\\t self._indoorsSurfaceViewController!.surfaceView.setBuildingForSurface(building)\\n         self._indoorsSurfaceViewController!.surfaceView.setFloorLevel(building.getInitialFloorLevel())\\n    })\\n}\\n\\nfunc addSurfaceAsChildViewController () {\\n    self.addChildViewController(_indoorsSurfaceViewController!)\\n    _indoorsSurfaceViewController!.view.frame = self.view.frame\\n    self.view.addSubview(_indoorsSurfaceViewController!.view)\\n    _indoorsSurfaceViewController!.didMoveToParentViewController(self)\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-07-07T17:25:02.305Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":14,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"ui-without-localization","sync_unique":"","title":"UI without localization","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

UI without localization


If you want to show a map without actually starting localization (e.g. because you don't have a working beacon infrastructure set up yet), you can do so by combining the new IDSBuildingManager with ISIndoorsSurfaceViewController. Use the IDSBuildingManager to load a building and pass it to the ISIndoorsSurfaceViewControllers surface view. Be sure to set the floor level too. Here is a complete example: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n\n// ...\n\n- (void)viewDidLoad \n{\n [super viewDidLoad];\n \n NSString *apiKey = @\"YOUR_API_KEY\"; // REPLACE WITH YOUR API KEY\n NSUInteger buildingId = 12345678; // REPLACE WITH YOUR BUILDING ID\n \n __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:apiKey andServiceDelegate:nil];\n \n _indoorsSurfaceViewController = [[ISIndoorsSurfaceViewController alloc] init];\n \n [self addSurfaceAsChildViewController];\n \n IDSBuildingManager *buildingManager = [[IDSBuildingManager alloc] init];\n [buildingManager loadBuildingWithId:buildingId progress:^(double progress, NSUInteger currentStep, NSUInteger totalSteps, NSString *phase) {\n NSLog(@\"Progress: %f\", progress);\n } completion:^(IDSBuilding *building, NSError *error) {\n if (error) {\n NSLog(@\"An error occured: %@ Reason: %@\", error.localizedDescription, error.localizedFailureReason);\n return;\n }\n \n [_indoorsSurfaceViewController.surfaceView setBuildingForSurface:building];\n [_indoorsSurfaceViewController.surfaceView setFloorLevel:[building getInitialFloorLevel]];\n }];\n}\n\n- (void)addSurfaceAsChildViewController\n{\n [self addChildViewController:_indoorsSurfaceViewController];\n _indoorsSurfaceViewController.view.frame = self.view.frame;\n [self.view addSubview:_indoorsSurfaceViewController.view];\n [_indoorsSurfaceViewController didMoveToParentViewController:self];\n}", "language": "objectivec" }, { "code": "override func viewDidLoad() {\n super.viewDidLoad()\n\n _ = Indoors(licenseKey:\"YOUR-API-KEY\", andServiceDelegate:nil)\n\n _indoorsSurfaceViewController = ISIndoorsSurfaceViewController()\n _indoorsSurfaceViewController!.delegate = self\n\n addSurfaceAsChildViewController()\n\n let buildingManager = IDSBuildingManager()\n buildingManager.loadBuildingWithId(buildingId, progress: {(progress: Int, currentStep: Int, totalSteps: Int, phase: String!) -> Void in\n NSLog(\"Progress: %f\", progress)\n }, completion: {(building: IDSBuilding!, error: NSError!) -> Void in\n if error != nil {\n// NSLog(\"An error occured: %@ Reason: %@\", error.localizedDescription, error.localizedFailureReason)\n return\n }\n \t\t self._indoorsSurfaceViewController!.surfaceView.setBuildingForSurface(building)\n self._indoorsSurfaceViewController!.surfaceView.setFloorLevel(building.getInitialFloorLevel())\n })\n}\n\nfunc addSurfaceAsChildViewController () {\n self.addChildViewController(_indoorsSurfaceViewController!)\n _indoorsSurfaceViewController!.view.frame = self.view.frame\n self.view.addSubview(_indoorsSurfaceViewController!.view)\n _indoorsSurfaceViewController!.didMoveToParentViewController(self)\n}", "language": "swift", "name": "Swift" } ] } [/block]
If you want to show a map without actually starting localization (e.g. because you don't have a working beacon infrastructure set up yet), you can do so by combining the new IDSBuildingManager with ISIndoorsSurfaceViewController. Use the IDSBuildingManager to load a building and pass it to the ISIndoorsSurfaceViewControllers surface view. Be sure to set the floor level too. Here is a complete example: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n\n// ...\n\n- (void)viewDidLoad \n{\n [super viewDidLoad];\n \n NSString *apiKey = @\"YOUR_API_KEY\"; // REPLACE WITH YOUR API KEY\n NSUInteger buildingId = 12345678; // REPLACE WITH YOUR BUILDING ID\n \n __unused Indoors *indoors = [[Indoors alloc] initWithLicenseKey:apiKey andServiceDelegate:nil];\n \n _indoorsSurfaceViewController = [[ISIndoorsSurfaceViewController alloc] init];\n \n [self addSurfaceAsChildViewController];\n \n IDSBuildingManager *buildingManager = [[IDSBuildingManager alloc] init];\n [buildingManager loadBuildingWithId:buildingId progress:^(double progress, NSUInteger currentStep, NSUInteger totalSteps, NSString *phase) {\n NSLog(@\"Progress: %f\", progress);\n } completion:^(IDSBuilding *building, NSError *error) {\n if (error) {\n NSLog(@\"An error occured: %@ Reason: %@\", error.localizedDescription, error.localizedFailureReason);\n return;\n }\n \n [_indoorsSurfaceViewController.surfaceView setBuildingForSurface:building];\n [_indoorsSurfaceViewController.surfaceView setFloorLevel:[building getInitialFloorLevel]];\n }];\n}\n\n- (void)addSurfaceAsChildViewController\n{\n [self addChildViewController:_indoorsSurfaceViewController];\n _indoorsSurfaceViewController.view.frame = self.view.frame;\n [self.view addSubview:_indoorsSurfaceViewController.view];\n [_indoorsSurfaceViewController didMoveToParentViewController:self];\n}", "language": "objectivec" }, { "code": "override func viewDidLoad() {\n super.viewDidLoad()\n\n _ = Indoors(licenseKey:\"YOUR-API-KEY\", andServiceDelegate:nil)\n\n _indoorsSurfaceViewController = ISIndoorsSurfaceViewController()\n _indoorsSurfaceViewController!.delegate = self\n\n addSurfaceAsChildViewController()\n\n let buildingManager = IDSBuildingManager()\n buildingManager.loadBuildingWithId(buildingId, progress: {(progress: Int, currentStep: Int, totalSteps: Int, phase: String!) -> Void in\n NSLog(\"Progress: %f\", progress)\n }, completion: {(building: IDSBuilding!, error: NSError!) -> Void in\n if error != nil {\n// NSLog(\"An error occured: %@ Reason: %@\", error.localizedDescription, error.localizedFailureReason)\n return\n }\n \t\t self._indoorsSurfaceViewController!.surfaceView.setBuildingForSurface(building)\n self._indoorsSurfaceViewController!.surfaceView.setFloorLevel(building.getInitialFloorLevel())\n })\n}\n\nfunc addSurfaceAsChildViewController () {\n self.addChildViewController(_indoorsSurfaceViewController!)\n _indoorsSurfaceViewController!.view.frame = self.view.frame\n self.view.addSubview(_indoorsSurfaceViewController!.view)\n _indoorsSurfaceViewController!.didMoveToParentViewController(self)\n}", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820c9","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Removing delegate while a download is still in progress\",\n  \"body\": \"Note that the delegate has to exist for the entire duration of the download and must not be removed as this will cause a memory access error.\\nThe delegate can be safely removed after the download has been completed or cancelled.\"\n}\n[/block]\nYou can cancel already started building download by calling this method:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] cancelGetBuilding];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().cancelGetBuilding()\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2016-02-12T10:57:10.538Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":15,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"building-download-1","sync_unique":"","title":"Building Download","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Building Download


[block:callout] { "type": "danger", "title": "Removing delegate while a download is still in progress", "body": "Note that the delegate has to exist for the entire duration of the download and must not be removed as this will cause a memory access error.\nThe delegate can be safely removed after the download has been completed or cancelled." } [/block] You can cancel already started building download by calling this method: [block:code] { "codes": [ { "code": "[[Indoors instance] cancelGetBuilding];", "language": "objectivec" }, { "code": "Indoors.instance().cancelGetBuilding()", "language": "swift", "name": "Swift" } ] } [/block]
[block:callout] { "type": "danger", "title": "Removing delegate while a download is still in progress", "body": "Note that the delegate has to exist for the entire duration of the download and must not be removed as this will cause a memory access error.\nThe delegate can be safely removed after the download has been completed or cancelled." } [/block] You can cancel already started building download by calling this method: [block:code] { "codes": [ { "code": "[[Indoors instance] cancelGetBuilding];", "language": "objectivec" }, { "code": "Indoors.instance().cancelGetBuilding()", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820ca","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Most people prefer GPS coordinates over our internal coordinates:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <IndoorsSDK/IndoorsSDK.h>\\n#import <CoreLocation/CoreLocation.h>\\n \\n// ...\\n \\n@property (strong, nonatomic) IDSBuilding *currentBuilding;\\n \\n// ...\\n#pragma mark LoadingBuildingDelegate \\n\\n- (void)buildingLoaded:(IDSBuilding *)building\\n{\\n    self.currentBuilding = building;\\n}\\n \\n#pragma mark IndoorsLocationListener\\n\\n- (void)positionUpdated:(IDSCoordinate *)userPosition\\n{\\n    if (self.currentBuilding) {\\n        CLLocation* location = [IndoorsCoordinateUtil geoLocationForCoordinate:userPosition inBuilding:self.currentBuilding];\\n        \\n        NSLog(@\\\"Current gps position is %@\\\", location);\\n    } else {\\n        NSLog(@\\\"This should not happen. Building not initialized, but position calculated.\\\");\\n    }\\n}\\n \\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"import CoreLocation\\n\\n// ...\\n\\nvar _currentBuilding: IDSBuilding?\\n\\n// ...\\n\\n// MARK: LoadingBuildingDelegate\\n\\nfunc buildingLoaded(building : IDSBuilding!) {\\n    _currentBuilding = building\\n}\\n\\n// MARK: IndoorsLocationListener\\n\\nfunc positionUpdated(userPosition: IDSCoordinate!) {\\n   if _currentBuilding != nil {\\n       let location: CLLocation = IndoorsCoordinateUtil.geoLocationForCoordinate(userPosition, inBuilding: _currentBuilding)\\n       NSLog(\\\"current gps position is %@\\\", location)\\n    } else {\\n        NSLog(\\\"This should not happen. Building not initialized, but position calculated.\\\");\\n    }\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nPlease keep in mind that this won't work if: \n   \na) You didn't set a origin for your building in the MMT.\n   \nb) If you set no / a wrong rotation for your building in the MMT!","category":"57e3bcc2378b341700c82092","createdAt":"2015-03-13T09:52:25.567Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":16,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"gps-coordinates-1","sync_unique":"","title":"GPS-Coordinates","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

GPS-Coordinates


Most people prefer GPS coordinates over our internal coordinates: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n#import <CoreLocation/CoreLocation.h>\n \n// ...\n \n@property (strong, nonatomic) IDSBuilding *currentBuilding;\n \n// ...\n#pragma mark LoadingBuildingDelegate \n\n- (void)buildingLoaded:(IDSBuilding *)building\n{\n self.currentBuilding = building;\n}\n \n#pragma mark IndoorsLocationListener\n\n- (void)positionUpdated:(IDSCoordinate *)userPosition\n{\n if (self.currentBuilding) {\n CLLocation* location = [IndoorsCoordinateUtil geoLocationForCoordinate:userPosition inBuilding:self.currentBuilding];\n \n NSLog(@\"Current gps position is %@\", location);\n } else {\n NSLog(@\"This should not happen. Building not initialized, but position calculated.\");\n }\n}\n \n// ...", "language": "objectivec" }, { "code": "import CoreLocation\n\n// ...\n\nvar _currentBuilding: IDSBuilding?\n\n// ...\n\n// MARK: LoadingBuildingDelegate\n\nfunc buildingLoaded(building : IDSBuilding!) {\n _currentBuilding = building\n}\n\n// MARK: IndoorsLocationListener\n\nfunc positionUpdated(userPosition: IDSCoordinate!) {\n if _currentBuilding != nil {\n let location: CLLocation = IndoorsCoordinateUtil.geoLocationForCoordinate(userPosition, inBuilding: _currentBuilding)\n NSLog(\"current gps position is %@\", location)\n } else {\n NSLog(\"This should not happen. Building not initialized, but position calculated.\");\n }\n}", "language": "swift", "name": "Swift" } ] } [/block] Please keep in mind that this won't work if: a) You didn't set a origin for your building in the MMT. b) If you set no / a wrong rotation for your building in the MMT!
Most people prefer GPS coordinates over our internal coordinates: [block:code] { "codes": [ { "code": "#import <IndoorsSDK/IndoorsSDK.h>\n#import <CoreLocation/CoreLocation.h>\n \n// ...\n \n@property (strong, nonatomic) IDSBuilding *currentBuilding;\n \n// ...\n#pragma mark LoadingBuildingDelegate \n\n- (void)buildingLoaded:(IDSBuilding *)building\n{\n self.currentBuilding = building;\n}\n \n#pragma mark IndoorsLocationListener\n\n- (void)positionUpdated:(IDSCoordinate *)userPosition\n{\n if (self.currentBuilding) {\n CLLocation* location = [IndoorsCoordinateUtil geoLocationForCoordinate:userPosition inBuilding:self.currentBuilding];\n \n NSLog(@\"Current gps position is %@\", location);\n } else {\n NSLog(@\"This should not happen. Building not initialized, but position calculated.\");\n }\n}\n \n// ...", "language": "objectivec" }, { "code": "import CoreLocation\n\n// ...\n\nvar _currentBuilding: IDSBuilding?\n\n// ...\n\n// MARK: LoadingBuildingDelegate\n\nfunc buildingLoaded(building : IDSBuilding!) {\n _currentBuilding = building\n}\n\n// MARK: IndoorsLocationListener\n\nfunc positionUpdated(userPosition: IDSCoordinate!) {\n if _currentBuilding != nil {\n let location: CLLocation = IndoorsCoordinateUtil.geoLocationForCoordinate(userPosition, inBuilding: _currentBuilding)\n NSLog(\"current gps position is %@\", location)\n } else {\n NSLog(\"This should not happen. Building not initialized, but position calculated.\");\n }\n}", "language": "swift", "name": "Swift" } ] } [/block] Please keep in mind that this won't work if: a) You didn't set a origin for your building in the MMT. b) If you set no / a wrong rotation for your building in the MMT!
{"__v":0,"_id":"57e3bcc2378b341700c820cb","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Sometimes you might want to move and zoom to a specific area of the map or you want to restore the state when the user closed and reopened the map. To get the currently visible area you have to call the method - (CGRect)visibleMapRect on your IndoorsSurface object. You can use the method - (void)setVisibleMapRect:animated: to move and zoom the map to your desired area.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"// ...\\n\\nCGRect mapRect = _indoorsSurfaceViewController.surfaceView.visibleMapRect;\\n\\n// ...\\n  \\n[_indoorsSurfaceViewController.surfaceView setVisibleMapRect:mapRect animated:NO];\\n\\n// ...\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"// ...\\n\\nlet mapRect: CGRect = _indoorsSurfaceViewController!.surfaceView.visibleMapRect\\n\\n// ...\\n  \\n_indoorsSurfaceViewController!.surfaceView.setVisibleMapRect(mapRect, animated: true)\\n\\n// ...\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2015-08-31T15:35:58.957Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":17,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"get-and-set-visible-map-area","sync_unique":"","title":"Get and set visible map area","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Get and set visible map area


Sometimes you might want to move and zoom to a specific area of the map or you want to restore the state when the user closed and reopened the map. To get the currently visible area you have to call the method - (CGRect)visibleMapRect on your IndoorsSurface object. You can use the method - (void)setVisibleMapRect:animated: to move and zoom the map to your desired area. [block:code] { "codes": [ { "code": "// ...\n\nCGRect mapRect = _indoorsSurfaceViewController.surfaceView.visibleMapRect;\n\n// ...\n \n[_indoorsSurfaceViewController.surfaceView setVisibleMapRect:mapRect animated:NO];\n\n// ...", "language": "objectivec" }, { "code": "// ...\n\nlet mapRect: CGRect = _indoorsSurfaceViewController!.surfaceView.visibleMapRect\n\n// ...\n \n_indoorsSurfaceViewController!.surfaceView.setVisibleMapRect(mapRect, animated: true)\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block]
Sometimes you might want to move and zoom to a specific area of the map or you want to restore the state when the user closed and reopened the map. To get the currently visible area you have to call the method - (CGRect)visibleMapRect on your IndoorsSurface object. You can use the method - (void)setVisibleMapRect:animated: to move and zoom the map to your desired area. [block:code] { "codes": [ { "code": "// ...\n\nCGRect mapRect = _indoorsSurfaceViewController.surfaceView.visibleMapRect;\n\n// ...\n \n[_indoorsSurfaceViewController.surfaceView setVisibleMapRect:mapRect animated:NO];\n\n// ...", "language": "objectivec" }, { "code": "// ...\n\nlet mapRect: CGRect = _indoorsSurfaceViewController!.surfaceView.visibleMapRect\n\n// ...\n \n_indoorsSurfaceViewController!.surfaceView.setVisibleMapRect(mapRect, animated: true)\n\n// ...", "language": "swift", "name": "Swift" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820cc","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"The Kalman filter is used to improve localisation accuracy for certain setups. Contact support@indoo.rs to get more information about your venue. By default this filter is enabled for every building. You can disable the Kalman filter like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setEnableKalmanFilter:NO];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().enableKalmanFilter = false\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Enabling/disabling Kalman filter\",\n  \"body\": \"Make sure to set this value before you start with the building download.\"\n}\n[/block]\nThe Stabilisation filter is used to reduce user location jumps when you are not walking. You can also set the time, representing how long it takes for the stabilisation filter to kick in. Minimum value is 4000 ms, maximum is 20000 ms. To enable/disable stabilisation filter and set time use next code:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setEnableStabilisationFilter:YES];\\n[[Indoors instance] setStabilisationFilterTime:4000];\",\n      \"language\": \"objectivec\"\n    },\n    {\n      \"code\": \"Indoors.instance().enableStabilisationFilter = true\\n        Indoors.instance().stabilisationFilterTime = 4000\",\n      \"language\": \"swift\",\n      \"name\": \"Swift\"\n    }\n  ]\n}\n[/block]\nBy default, the stabilisation filter is enabled, and default time is 4000 ms.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Enabling/disabling Stabilisation filter and setting time\",\n  \"body\": \"Make sure to set this values before you start with the building download.\"\n}\n[/block]","category":"57e3bcc2378b341700c82092","createdAt":"2016-03-30T13:17:45.508Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":18,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"using-stabilisation-filter-and-kalman-filter","sync_unique":"","title":"Using Kalman and Stabilisation filter","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Using Kalman and Stabilisation filter


The Kalman filter is used to improve localisation accuracy for certain setups. Contact support@indoo.rs to get more information about your venue. By default this filter is enabled for every building. You can disable the Kalman filter like this: [block:code] { "codes": [ { "code": "[[Indoors instance] setEnableKalmanFilter:NO];", "language": "objectivec" }, { "code": "Indoors.instance().enableKalmanFilter = false", "language": "swift", "name": "Swift" } ] } [/block] [block:callout] { "type": "warning", "title": "Enabling/disabling Kalman filter", "body": "Make sure to set this value before you start with the building download." } [/block] The Stabilisation filter is used to reduce user location jumps when you are not walking. You can also set the time, representing how long it takes for the stabilisation filter to kick in. Minimum value is 4000 ms, maximum is 20000 ms. To enable/disable stabilisation filter and set time use next code: [block:code] { "codes": [ { "code": "[[Indoors instance] setEnableStabilisationFilter:YES];\n[[Indoors instance] setStabilisationFilterTime:4000];", "language": "objectivec" }, { "code": "Indoors.instance().enableStabilisationFilter = true\n Indoors.instance().stabilisationFilterTime = 4000", "language": "swift", "name": "Swift" } ] } [/block] By default, the stabilisation filter is enabled, and default time is 4000 ms. [block:callout] { "type": "warning", "title": "Enabling/disabling Stabilisation filter and setting time", "body": "Make sure to set this values before you start with the building download." } [/block]
The Kalman filter is used to improve localisation accuracy for certain setups. Contact support@indoo.rs to get more information about your venue. By default this filter is enabled for every building. You can disable the Kalman filter like this: [block:code] { "codes": [ { "code": "[[Indoors instance] setEnableKalmanFilter:NO];", "language": "objectivec" }, { "code": "Indoors.instance().enableKalmanFilter = false", "language": "swift", "name": "Swift" } ] } [/block] [block:callout] { "type": "warning", "title": "Enabling/disabling Kalman filter", "body": "Make sure to set this value before you start with the building download." } [/block] The Stabilisation filter is used to reduce user location jumps when you are not walking. You can also set the time, representing how long it takes for the stabilisation filter to kick in. Minimum value is 4000 ms, maximum is 20000 ms. To enable/disable stabilisation filter and set time use next code: [block:code] { "codes": [ { "code": "[[Indoors instance] setEnableStabilisationFilter:YES];\n[[Indoors instance] setStabilisationFilterTime:4000];", "language": "objectivec" }, { "code": "Indoors.instance().enableStabilisationFilter = true\n Indoors.instance().stabilisationFilterTime = 4000", "language": "swift", "name": "Swift" } ] } [/block] By default, the stabilisation filter is enabled, and default time is 4000 ms. [block:callout] { "type": "warning", "title": "Enabling/disabling Stabilisation filter and setting time", "body": "Make sure to set this values before you start with the building download." } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c82097","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"Welcome to our step-by-step guide for indoo.rs Mobile Toolkit. Please follow our detailed instructions for each step to gain the best possible first experience with our service. Be aware that you need an Internet connection during some of the following steps. Please read each section carefully.\n\n**Note: To successfully use the Mobile Toolkit you must be using a phone with android version 4.3 or above. This is the version in which Android added the necessarily Bluetooth APIs.**\n\nIn order to start using our service you need to create an account on the following website: https://my.indoo.rs If you click on the provided link, you will be taken to our website. Also please take a look at our guide on how to start using the desktop tool\nhttps://my.indoo.rs/javadoc/mmt_guide/","category":"57e3bcc2378b341700c82093","createdAt":"2015-03-25T09:55:45.390Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":0,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"getting-started-with-indoors-mobile-toolkit","sync_unique":"","title":"Getting Started with indoo.rs Mobile Toolkit","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Getting Started with indoo.rs Mobile Toolkit


Welcome to our step-by-step guide for indoo.rs Mobile Toolkit. Please follow our detailed instructions for each step to gain the best possible first experience with our service. Be aware that you need an Internet connection during some of the following steps. Please read each section carefully. **Note: To successfully use the Mobile Toolkit you must be using a phone with android version 4.3 or above. This is the version in which Android added the necessarily Bluetooth APIs.** In order to start using our service you need to create an account on the following website: https://my.indoo.rs If you click on the provided link, you will be taken to our website. Also please take a look at our guide on how to start using the desktop tool https://my.indoo.rs/javadoc/mmt_guide/
Welcome to our step-by-step guide for indoo.rs Mobile Toolkit. Please follow our detailed instructions for each step to gain the best possible first experience with our service. Be aware that you need an Internet connection during some of the following steps. Please read each section carefully. **Note: To successfully use the Mobile Toolkit you must be using a phone with android version 4.3 or above. This is the version in which Android added the necessarily Bluetooth APIs.** In order to start using our service you need to create an account on the following website: https://my.indoo.rs If you click on the provided link, you will be taken to our website. Also please take a look at our guide on how to start using the desktop tool https://my.indoo.rs/javadoc/mmt_guide/
{"__v":0,"_id":"57e3bcc2378b341700c82098","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"Fingerprinting is a more advanced feature than using proximity beacons, its a way of using a series of measurement points to tell our SDK about the radio \"landscape\" of your building, which we then use to give a more accurate and fluid position. \n\nTo use measurement points in your map must be switched to \"expert\" mode, either in the MMT or automatically when you upload fingerprints.\n\n**We do not recommend to mix adding proximity iBeacons and Measure Points in the same map, unless you know what you are doing.** \n\nYou can either use WiFi™ signals or iBeacons for localisation. If you just use WiFi™ signals, only Android™ devices will be supported. iBeacons on the other hand enable localisation on iOS and Android™ devices.\n\nNote: Both iBeacon and WiFi™ signals can be recorded simultaneously, however, ** indoo.rs localization will not work if both iBeacon and WiFi™ are present in the same map.** \n\nWe allow measurement of both at the same time to allow you to easily set up both an iBeacon and WiFi map with just one measurement pass.\n\nHowever, once finished: **you must delete either all iBeacons or all WiFi™ networks** after you are done measuring. How to do this is explained in the MMT guide here:\n[block:html]\n{\n  \"html\": \"<div></div>\\n<a href=\\\"https://my.indoo.rs/javadoc/mmt_guide/#ManageMeasuredNetworks\\\">Manage Measured Networks</a>\\n<style></style>\"\n}\n[/block]\nWhen measuring, we recommend to observe the following rules:\n\n* Measure in a grid approximately every 3 meters.\n* Measure at least 4 to 6 points per room. (size 25m2)\n* Face away from the nearest wall when measuring.\n* Take at least one fingerprint in each of the corners.\n* Spread the points evenly.\n* Don't spare with points, more is often better.\n* Try to avoid movement of other people, because that can influence the measurement.\n\nBecause of the way the system works, you must ensure that all points in the room are within the triangular area formed by at **least** three measurement points. This means for short corridors you will want to measure along **both** walls.\n\nAn example of good fingerprint measurement is shown below:\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/4vSv9YeJS5W23b5Ib5Cs_example.png\",\n        \"example.png\",\n        \"1851\",\n        \"939\",\n        \"#34749c\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOne of the the most common issue is that people produce measurement maps similar to below, which is a very bad example.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/1klUV14ZQdeyZ9nyHe9a_badexample.png\",\n        \"badexample.png\",\n        \"1851\",\n        \"939\",\n        \"#34739b\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nBelow is a video for more explanation on how to measure fingerprints:\n[block:embed]\n{\n  \"html\": \"<iframe class=\\\"embedly-embed\\\" src=\\\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fw5BSd8djImM%3Ffeature%3Doembed&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dw5BSd8djImM&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fw5BSd8djImM%2Fhqdefault.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=youtube\\\" width=\\\"854\\\" height=\\\"480\\\" scrolling=\\\"no\\\" frameborder=\\\"0\\\" allowfullscreen></iframe>\",\n  \"url\": \"https://www.youtube.com/watch?v=w5BSd8djImM\",\n  \"title\": \"indoo.rs - How to measure\",\n  \"favicon\": \"https://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico\",\n  \"image\": \"https://i.ytimg.com/vi/w5BSd8djImM/hqdefault.jpg\"\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-04-28T07:53:54.812Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":1,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"fingerprint-basics","sync_unique":"","title":"Fingerprint basics","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Fingerprint basics


Fingerprinting is a more advanced feature than using proximity beacons, its a way of using a series of measurement points to tell our SDK about the radio "landscape" of your building, which we then use to give a more accurate and fluid position. To use measurement points in your map must be switched to "expert" mode, either in the MMT or automatically when you upload fingerprints. **We do not recommend to mix adding proximity iBeacons and Measure Points in the same map, unless you know what you are doing.** You can either use WiFi™ signals or iBeacons for localisation. If you just use WiFi™ signals, only Android™ devices will be supported. iBeacons on the other hand enable localisation on iOS and Android™ devices. Note: Both iBeacon and WiFi™ signals can be recorded simultaneously, however, ** indoo.rs localization will not work if both iBeacon and WiFi™ are present in the same map.** We allow measurement of both at the same time to allow you to easily set up both an iBeacon and WiFi map with just one measurement pass. However, once finished: **you must delete either all iBeacons or all WiFi™ networks** after you are done measuring. How to do this is explained in the MMT guide here: [block:html] { "html": "<div></div>\n<a href=\"https://my.indoo.rs/javadoc/mmt_guide/#ManageMeasuredNetworks\">Manage Measured Networks</a>\n<style></style>" } [/block] When measuring, we recommend to observe the following rules: * Measure in a grid approximately every 3 meters. * Measure at least 4 to 6 points per room. (size 25m2) * Face away from the nearest wall when measuring. * Take at least one fingerprint in each of the corners. * Spread the points evenly. * Don't spare with points, more is often better. * Try to avoid movement of other people, because that can influence the measurement. Because of the way the system works, you must ensure that all points in the room are within the triangular area formed by at **least** three measurement points. This means for short corridors you will want to measure along **both** walls. An example of good fingerprint measurement is shown below: [block:image] { "images": [ { "image": [ "https://files.readme.io/4vSv9YeJS5W23b5Ib5Cs_example.png", "example.png", "1851", "939", "#34749c", "" ] } ] } [/block] One of the the most common issue is that people produce measurement maps similar to below, which is a very bad example. [block:image] { "images": [ { "image": [ "https://files.readme.io/1klUV14ZQdeyZ9nyHe9a_badexample.png", "badexample.png", "1851", "939", "#34739b", "" ] } ] } [/block] Below is a video for more explanation on how to measure fingerprints: [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fw5BSd8djImM%3Ffeature%3Doembed&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dw5BSd8djImM&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fw5BSd8djImM%2Fhqdefault.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=youtube\" width=\"854\" height=\"480\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://www.youtube.com/watch?v=w5BSd8djImM", "title": "indoo.rs - How to measure", "favicon": "https://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico", "image": "https://i.ytimg.com/vi/w5BSd8djImM/hqdefault.jpg" } [/block]
Fingerprinting is a more advanced feature than using proximity beacons, its a way of using a series of measurement points to tell our SDK about the radio "landscape" of your building, which we then use to give a more accurate and fluid position. To use measurement points in your map must be switched to "expert" mode, either in the MMT or automatically when you upload fingerprints. **We do not recommend to mix adding proximity iBeacons and Measure Points in the same map, unless you know what you are doing.** You can either use WiFi™ signals or iBeacons for localisation. If you just use WiFi™ signals, only Android™ devices will be supported. iBeacons on the other hand enable localisation on iOS and Android™ devices. Note: Both iBeacon and WiFi™ signals can be recorded simultaneously, however, ** indoo.rs localization will not work if both iBeacon and WiFi™ are present in the same map.** We allow measurement of both at the same time to allow you to easily set up both an iBeacon and WiFi map with just one measurement pass. However, once finished: **you must delete either all iBeacons or all WiFi™ networks** after you are done measuring. How to do this is explained in the MMT guide here: [block:html] { "html": "<div></div>\n<a href=\"https://my.indoo.rs/javadoc/mmt_guide/#ManageMeasuredNetworks\">Manage Measured Networks</a>\n<style></style>" } [/block] When measuring, we recommend to observe the following rules: * Measure in a grid approximately every 3 meters. * Measure at least 4 to 6 points per room. (size 25m2) * Face away from the nearest wall when measuring. * Take at least one fingerprint in each of the corners. * Spread the points evenly. * Don't spare with points, more is often better. * Try to avoid movement of other people, because that can influence the measurement. Because of the way the system works, you must ensure that all points in the room are within the triangular area formed by at **least** three measurement points. This means for short corridors you will want to measure along **both** walls. An example of good fingerprint measurement is shown below: [block:image] { "images": [ { "image": [ "https://files.readme.io/4vSv9YeJS5W23b5Ib5Cs_example.png", "example.png", "1851", "939", "#34749c", "" ] } ] } [/block] One of the the most common issue is that people produce measurement maps similar to below, which is a very bad example. [block:image] { "images": [ { "image": [ "https://files.readme.io/1klUV14ZQdeyZ9nyHe9a_badexample.png", "badexample.png", "1851", "939", "#34739b", "" ] } ] } [/block] Below is a video for more explanation on how to measure fingerprints: [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2Fw5BSd8djImM%3Ffeature%3Doembed&url=https%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3Dw5BSd8djImM&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2Fw5BSd8djImM%2Fhqdefault.jpg&key=02466f963b9b4bb8845a05b53d3235d7&type=text%2Fhtml&schema=youtube\" width=\"854\" height=\"480\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://www.youtube.com/watch?v=w5BSd8djImM", "title": "indoo.rs - How to measure", "favicon": "https://s.ytimg.com/yts/img/favicon-vflz7uhzw.ico", "image": "https://i.ytimg.com/vi/w5BSd8djImM/hqdefault.jpg" } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c82099","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"There are a few things you should always remember when positioning iBeacons:\n\n* It is best to place the beacons above head level or on the ceiling. (between 2 and 4 meters)\n* Furthermore all beacons should be placed at about the same height.\n* The range of an iBeacon is between 20 and 40 meters. Please keep in mind that the areas should overlap.\n* Three iBeacons will cover an area of 25m².\n* You should attempt to be surrounded at all times by at least three iBeacons to allow effective triangulation of positions.\n\nRemember that walls and obstructions will change the quality and spread of the radio data from a beacon, when applying the above principles you should do so on a per-room basis.","category":"57e3bcc2378b341700c82093","createdAt":"2015-04-28T07:59:18.645Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":2,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"positioning-ibeacons-for-fingerprinting","sync_unique":"","title":"Positioning iBeacons for fingerprinting","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Positioning iBeacons for fingerprinting


There are a few things you should always remember when positioning iBeacons: * It is best to place the beacons above head level or on the ceiling. (between 2 and 4 meters) * Furthermore all beacons should be placed at about the same height. * The range of an iBeacon is between 20 and 40 meters. Please keep in mind that the areas should overlap. * Three iBeacons will cover an area of 25m². * You should attempt to be surrounded at all times by at least three iBeacons to allow effective triangulation of positions. Remember that walls and obstructions will change the quality and spread of the radio data from a beacon, when applying the above principles you should do so on a per-room basis.
There are a few things you should always remember when positioning iBeacons: * It is best to place the beacons above head level or on the ceiling. (between 2 and 4 meters) * Furthermore all beacons should be placed at about the same height. * The range of an iBeacon is between 20 and 40 meters. Please keep in mind that the areas should overlap. * Three iBeacons will cover an area of 25m². * You should attempt to be surrounded at all times by at least three iBeacons to allow effective triangulation of positions. Remember that walls and obstructions will change the quality and spread of the radio data from a beacon, when applying the above principles you should do so on a per-room basis.
{"__v":0,"_id":"57e3bcc2378b341700c8209a","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"body":"This is the first screen on the mobile toolkit application, after you successfully create an account, you will be able to login using email, password and API Key (received after registration) \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/bzjyK4zvQMuz8D8PnTs4_indoorsMobileToolkitLogin.png\",\n        \"indoorsMobileToolkitLogin.png\",\n        \"1080\",\n        \"1920\",\n        \"#14939f\",\n        \"\"\n      ],\n      \"caption\": \"login screen\"\n    }\n  ]\n}\n[/block]\nFirst type in your email and password used for registration \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Z7jhOBFoSJSU70TRBxX6_indoorsMobileToolkitLoginEmail.png\",\n        \"indoorsMobileToolkitLoginEmail.png\",\n        \"1080\",\n        \"1920\",\n        \"#14939f\",\n        \"\"\n      ],\n      \"caption\": \"Enter email an password\"\n    }\n  ]\n}\n[/block]\nNext you need to enter your API Key received after registration. You can do this by entering API key yourself, or by scanning the received QRcode by pressing the QRcode icon on the right using the camera, which will open automatically.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Of7pwUHvTMOrpa2P0VqI_indoorsMobileToolkitLoginAPIKEY.png\",\n        \"indoorsMobileToolkitLoginAPIKEY.png\",\n        \"1080\",\n        \"1920\",\n        \"#14939f\",\n        \"\"\n      ],\n      \"caption\": \"Enter API key\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-03-13T09:57:44.740Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":3,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"registration-and-login","sync_unique":"","title":"Registration and Login","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Registration and Login


This is the first screen on the mobile toolkit application, after you successfully create an account, you will be able to login using email, password and API Key (received after registration) [block:image] { "images": [ { "image": [ "https://files.readme.io/bzjyK4zvQMuz8D8PnTs4_indoorsMobileToolkitLogin.png", "indoorsMobileToolkitLogin.png", "1080", "1920", "#14939f", "" ], "caption": "login screen" } ] } [/block] First type in your email and password used for registration [block:image] { "images": [ { "image": [ "https://files.readme.io/Z7jhOBFoSJSU70TRBxX6_indoorsMobileToolkitLoginEmail.png", "indoorsMobileToolkitLoginEmail.png", "1080", "1920", "#14939f", "" ], "caption": "Enter email an password" } ] } [/block] Next you need to enter your API Key received after registration. You can do this by entering API key yourself, or by scanning the received QRcode by pressing the QRcode icon on the right using the camera, which will open automatically. [block:image] { "images": [ { "image": [ "https://files.readme.io/Of7pwUHvTMOrpa2P0VqI_indoorsMobileToolkitLoginAPIKEY.png", "indoorsMobileToolkitLoginAPIKEY.png", "1080", "1920", "#14939f", "" ], "caption": "Enter API key" } ] } [/block]
This is the first screen on the mobile toolkit application, after you successfully create an account, you will be able to login using email, password and API Key (received after registration) [block:image] { "images": [ { "image": [ "https://files.readme.io/bzjyK4zvQMuz8D8PnTs4_indoorsMobileToolkitLogin.png", "indoorsMobileToolkitLogin.png", "1080", "1920", "#14939f", "" ], "caption": "login screen" } ] } [/block] First type in your email and password used for registration [block:image] { "images": [ { "image": [ "https://files.readme.io/Z7jhOBFoSJSU70TRBxX6_indoorsMobileToolkitLoginEmail.png", "indoorsMobileToolkitLoginEmail.png", "1080", "1920", "#14939f", "" ], "caption": "Enter email an password" } ] } [/block] Next you need to enter your API Key received after registration. You can do this by entering API key yourself, or by scanning the received QRcode by pressing the QRcode icon on the right using the camera, which will open automatically. [block:image] { "images": [ { "image": [ "https://files.readme.io/Of7pwUHvTMOrpa2P0VqI_indoorsMobileToolkitLoginAPIKEY.png", "indoorsMobileToolkitLoginAPIKEY.png", "1080", "1920", "#14939f", "" ], "caption": "Enter API key" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c8209b","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"After logging in successfully you will see the list of buildings you have created (to create a building please visit our guide [here](https://my.indoo.rs/javadoc/mmt_guide/ )).\n\nSelect the building you need to measure fingerprints for.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/uJNhTDS9THC8tRTieBcU_buildingselection.png\",\n        \"buildingselection.png\",\n        \"1080\",\n        \"1920\",\n        \"#1a98a4\",\n        \"\"\n      ],\n      \"caption\": \"Select buildings\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-03-13T10:47:24.480Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":4,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"selecting-your-buildings","sync_unique":"","title":"Selecting your buildings","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Selecting your buildings


After logging in successfully you will see the list of buildings you have created (to create a building please visit our guide [here](https://my.indoo.rs/javadoc/mmt_guide/ )). Select the building you need to measure fingerprints for. [block:image] { "images": [ { "image": [ "https://files.readme.io/uJNhTDS9THC8tRTieBcU_buildingselection.png", "buildingselection.png", "1080", "1920", "#1a98a4", "" ], "caption": "Select buildings" } ] } [/block]
After logging in successfully you will see the list of buildings you have created (to create a building please visit our guide [here](https://my.indoo.rs/javadoc/mmt_guide/ )). Select the building you need to measure fingerprints for. [block:image] { "images": [ { "image": [ "https://files.readme.io/uJNhTDS9THC8tRTieBcU_buildingselection.png", "buildingselection.png", "1080", "1920", "#1a98a4", "" ], "caption": "Select buildings" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c8209c","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"As shown in the image below, to measure fingerprints you have to press on the fingerprint button.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Q3BXRk10Q2GxIyMHWTU8_MapFingerPrint.png\",\n        \"MapFingerPrint.png\",\n        \"1080\",\n        \"1920\",\n        \"#0493a3\",\n        \"\"\n      ],\n      \"caption\": \"Measuring fingerprint 1\"\n    }\n  ]\n}\n[/block]\nUsing fingerprints means your map must be converted to expert mode, either in the MMT, or if you haven't done so already, uploading fingerprints from the Mobile Toolkit will modify this automatically. You will be presented with a dialog similar to the one below in this case, so you can choose whether to make this change.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Y5SuyQbaSguEm6xl4xdZ_Screenshot_2015-04-28-09-19-28.png\",\n        \"Screenshot_2015-04-28-09-19-28.png\",\n        \"1080\",\n        \"1920\",\n        \"#3ab6e4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n\nTo measure a fingerprint you have to:\n * first zoom in using pinch\n * move the location cursor (the orange balloon) to your location on the map \n * **then** press \"MEASURE FINGERPRINT\" (it will take around 15 seconds to measure)\n you will have to repeat this until you have sufficient fingerprints recorded to cover your map.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Measuring Fingerprint 2\",\n      \"image\": [\n        \"https://files.readme.io/rZ2giBXS7OEZkyCxC5jA_indoorsFingerPrintMode.png\",\n        \"indoorsFingerPrintMode.png\",\n        \"1080\",\n        \"1920\",\n        \"#0c92a1\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nWhen you press on 'MEASURE FINGERPRINT' you see the following dialog, if you change your mind you can press 'Cancel', then it will stop the measuring.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Measuring FingerPrint dialog\",\n      \"image\": [\n        \"https://files.readme.io/xcyi91oFTom5nwremsEk_measuringcanelButton.png\",\n        \"measuringcanelButton.png\",\n        \"1080\",\n        \"1920\",\n        \"#633504\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nThe location that you measured the fingerprint for will be marked with a white dot as shown in the screenshot, then move the cursor to the next location and repeat the process.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/dnR10bnQj20Tdqn2uWaq_MarkedLocations.png\",\n        \"MarkedLocations.png\",\n        \"1080\",\n        \"1920\",\n        \"#129db3\",\n        \"\"\n      ],\n      \"caption\": \"Marked Locations\",\n      \"border\": true\n    }\n  ]\n}\n[/block]\nTo help you estimating a proper position for the next fingerprint we have included an option to show an equidistant grid with selectable unit distance. Use this to better estimate the distances on the map for your next fingerprint. The grid zooms and pans with the map.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ht87YhqS4S77M6LBW6pq_Distance%20grid%20helper.png\",\n        \"Distance grid helper.png\",\n        \"1080\",\n        \"1920\",\n        \"#d344be\",\n        \"\"\n      ],\n      \"caption\": \"Distance Grid\",\n      \"border\": true\n    }\n  ]\n}\n[/block]\nAfter Measuring your fingerprint, the fingerprint measured will be uploaded immediately to the server, you will see the flowing message indicating that the upload started and upload finished:\n\n\n \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/fYqbrNV3THCX8pOvrOpe_StartedUpload.png\",\n        \"StartedUpload.png\",\n        \"1080\",\n        \"1920\",\n        \"#0f97aa\",\n        \"\"\n      ],\n      \"caption\": \"Started uploading\",\n      \"border\": true\n    }\n  ]\n}\n[/block]\nAfter the upload is successfully finished you see this:  \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/VfGcDTJoTleWXPvjE3kU_FinishedUpload.png\",\n        \"FinishedUpload.png\",\n        \"1080\",\n        \"1920\",\n        \"#0694a4\",\n        \"\"\n      ],\n      \"caption\": \"Finished uploading\",\n      \"border\": true\n    }\n  ]\n}\n[/block]\nWhen uploading the fingerprint did not finish successfully, you will see a message saying 'pending uploads'  and the number of not uploaded fingerprints \nas  the following:\n \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/NvHyToepToaICyDdU40f_Pending%20uploads.png\",\n        \"Pending uploads.png\",\n        \"1080\",\n        \"1920\",\n        \"#169fb8\",\n        \"\"\n      ],\n      \"caption\": \"Pending uploads\"\n    }\n  ]\n}\n[/block]\nIn case of an error while measuring you fingerprints you will see a message like the following and the fingerprint will not be uploaded: \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/hShmWaP1Sgm9JlZMMtWA_RadioDataErrorpng.png\",\n        \"RadioDataErrorpng.png\",\n        \"1080\",\n        \"1920\",\n        \"#0594a4\",\n        \"\"\n      ],\n      \"caption\": \"No Radio Data Error\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-03-13T10:48:47.095Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":5,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"measuring-finger-prints","sync_unique":"","title":"Measuring fingerprints","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Measuring fingerprints


As shown in the image below, to measure fingerprints you have to press on the fingerprint button. [block:image] { "images": [ { "image": [ "https://files.readme.io/Q3BXRk10Q2GxIyMHWTU8_MapFingerPrint.png", "MapFingerPrint.png", "1080", "1920", "#0493a3", "" ], "caption": "Measuring fingerprint 1" } ] } [/block] Using fingerprints means your map must be converted to expert mode, either in the MMT, or if you haven't done so already, uploading fingerprints from the Mobile Toolkit will modify this automatically. You will be presented with a dialog similar to the one below in this case, so you can choose whether to make this change. [block:image] { "images": [ { "image": [ "https://files.readme.io/Y5SuyQbaSguEm6xl4xdZ_Screenshot_2015-04-28-09-19-28.png", "Screenshot_2015-04-28-09-19-28.png", "1080", "1920", "#3ab6e4", "" ] } ] } [/block] To measure a fingerprint you have to: * first zoom in using pinch * move the location cursor (the orange balloon) to your location on the map * **then** press "MEASURE FINGERPRINT" (it will take around 15 seconds to measure) you will have to repeat this until you have sufficient fingerprints recorded to cover your map. [block:image] { "images": [ { "caption": "Measuring Fingerprint 2", "image": [ "https://files.readme.io/rZ2giBXS7OEZkyCxC5jA_indoorsFingerPrintMode.png", "indoorsFingerPrintMode.png", "1080", "1920", "#0c92a1", "" ] } ] } [/block] When you press on 'MEASURE FINGERPRINT' you see the following dialog, if you change your mind you can press 'Cancel', then it will stop the measuring. [block:image] { "images": [ { "caption": "Measuring FingerPrint dialog", "image": [ "https://files.readme.io/xcyi91oFTom5nwremsEk_measuringcanelButton.png", "measuringcanelButton.png", "1080", "1920", "#633504", "" ] } ] } [/block] The location that you measured the fingerprint for will be marked with a white dot as shown in the screenshot, then move the cursor to the next location and repeat the process. [block:image] { "images": [ { "image": [ "https://files.readme.io/dnR10bnQj20Tdqn2uWaq_MarkedLocations.png", "MarkedLocations.png", "1080", "1920", "#129db3", "" ], "caption": "Marked Locations", "border": true } ] } [/block] To help you estimating a proper position for the next fingerprint we have included an option to show an equidistant grid with selectable unit distance. Use this to better estimate the distances on the map for your next fingerprint. The grid zooms and pans with the map. [block:image] { "images": [ { "image": [ "https://files.readme.io/ht87YhqS4S77M6LBW6pq_Distance%20grid%20helper.png", "Distance grid helper.png", "1080", "1920", "#d344be", "" ], "caption": "Distance Grid", "border": true } ] } [/block] After Measuring your fingerprint, the fingerprint measured will be uploaded immediately to the server, you will see the flowing message indicating that the upload started and upload finished: [block:image] { "images": [ { "image": [ "https://files.readme.io/fYqbrNV3THCX8pOvrOpe_StartedUpload.png", "StartedUpload.png", "1080", "1920", "#0f97aa", "" ], "caption": "Started uploading", "border": true } ] } [/block] After the upload is successfully finished you see this: [block:image] { "images": [ { "image": [ "https://files.readme.io/VfGcDTJoTleWXPvjE3kU_FinishedUpload.png", "FinishedUpload.png", "1080", "1920", "#0694a4", "" ], "caption": "Finished uploading", "border": true } ] } [/block] When uploading the fingerprint did not finish successfully, you will see a message saying 'pending uploads' and the number of not uploaded fingerprints as the following: [block:image] { "images": [ { "image": [ "https://files.readme.io/NvHyToepToaICyDdU40f_Pending%20uploads.png", "Pending uploads.png", "1080", "1920", "#169fb8", "" ], "caption": "Pending uploads" } ] } [/block] In case of an error while measuring you fingerprints you will see a message like the following and the fingerprint will not be uploaded: [block:image] { "images": [ { "image": [ "https://files.readme.io/hShmWaP1Sgm9JlZMMtWA_RadioDataErrorpng.png", "RadioDataErrorpng.png", "1080", "1920", "#0594a4", "" ], "caption": "No Radio Data Error" } ] } [/block]
As shown in the image below, to measure fingerprints you have to press on the fingerprint button. [block:image] { "images": [ { "image": [ "https://files.readme.io/Q3BXRk10Q2GxIyMHWTU8_MapFingerPrint.png", "MapFingerPrint.png", "1080", "1920", "#0493a3", "" ], "caption": "Measuring fingerprint 1" } ] } [/block] Using fingerprints means your map must be converted to expert mode, either in the MMT, or if you haven't done so already, uploading fingerprints from the Mobile Toolkit will modify this automatically. You will be presented with a dialog similar to the one below in this case, so you can choose whether to make this change. [block:image] { "images": [ { "image": [ "https://files.readme.io/Y5SuyQbaSguEm6xl4xdZ_Screenshot_2015-04-28-09-19-28.png", "Screenshot_2015-04-28-09-19-28.png", "1080", "1920", "#3ab6e4", "" ] } ] } [/block] To measure a fingerprint you have to: * first zoom in using pinch * move the location cursor (the orange balloon) to your location on the map * **then** press "MEASURE FINGERPRINT" (it will take around 15 seconds to measure) you will have to repeat this until you have sufficient fingerprints recorded to cover your map. [block:image] { "images": [ { "caption": "Measuring Fingerprint 2", "image": [ "https://files.readme.io/rZ2giBXS7OEZkyCxC5jA_indoorsFingerPrintMode.png", "indoorsFingerPrintMode.png", "1080", "1920", "#0c92a1", "" ] } ] } [/block] When you press on 'MEASURE FINGERPRINT' you see the following dialog, if you change your mind you can press 'Cancel', then it will stop the measuring. [block:image] { "images": [ { "caption": "Measuring FingerPrint dialog", "image": [ "https://files.readme.io/xcyi91oFTom5nwremsEk_measuringcanelButton.png", "measuringcanelButton.png", "1080", "1920", "#633504", "" ] } ] } [/block] The location that you measured the fingerprint for will be marked with a white dot as shown in the screenshot, then move the cursor to the next location and repeat the process. [block:image] { "images": [ { "image": [ "https://files.readme.io/dnR10bnQj20Tdqn2uWaq_MarkedLocations.png", "MarkedLocations.png", "1080", "1920", "#129db3", "" ], "caption": "Marked Locations", "border": true } ] } [/block] To help you estimating a proper position for the next fingerprint we have included an option to show an equidistant grid with selectable unit distance. Use this to better estimate the distances on the map for your next fingerprint. The grid zooms and pans with the map. [block:image] { "images": [ { "image": [ "https://files.readme.io/ht87YhqS4S77M6LBW6pq_Distance%20grid%20helper.png", "Distance grid helper.png", "1080", "1920", "#d344be", "" ], "caption": "Distance Grid", "border": true } ] } [/block] After Measuring your fingerprint, the fingerprint measured will be uploaded immediately to the server, you will see the flowing message indicating that the upload started and upload finished: [block:image] { "images": [ { "image": [ "https://files.readme.io/fYqbrNV3THCX8pOvrOpe_StartedUpload.png", "StartedUpload.png", "1080", "1920", "#0f97aa", "" ], "caption": "Started uploading", "border": true } ] } [/block] After the upload is successfully finished you see this: [block:image] { "images": [ { "image": [ "https://files.readme.io/VfGcDTJoTleWXPvjE3kU_FinishedUpload.png", "FinishedUpload.png", "1080", "1920", "#0694a4", "" ], "caption": "Finished uploading", "border": true } ] } [/block] When uploading the fingerprint did not finish successfully, you will see a message saying 'pending uploads' and the number of not uploaded fingerprints as the following: [block:image] { "images": [ { "image": [ "https://files.readme.io/NvHyToepToaICyDdU40f_Pending%20uploads.png", "Pending uploads.png", "1080", "1920", "#169fb8", "" ], "caption": "Pending uploads" } ] } [/block] In case of an error while measuring you fingerprints you will see a message like the following and the fingerprint will not be uploaded: [block:image] { "images": [ { "image": [ "https://files.readme.io/hShmWaP1Sgm9JlZMMtWA_RadioDataErrorpng.png", "RadioDataErrorpng.png", "1080", "1920", "#0594a4", "" ], "caption": "No Radio Data Error" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c8209d","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"## Recording Data\n\nAfter pressing 'finish' the recording data validity is checked. So if there is some data missing you \nwill receive a warning message.\nThe data is checked for radio data, ground truth, acceleration, steps and rotation.\n\nAfter pressing 'ok' you can choose to upload or discard!\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/gW2nUxDPQUG6TepUWBO7_Screenshot_20151217-173846.png\",\n        \"Screenshot_20151217-173846.png\",\n        \"1080\",\n        \"1920\",\n        \"#5d3d0e\",\n        \"\"\n      ],\n      \"caption\": \"Missing Data\"\n    }\n  ]\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/abFvTcI8Q5ygKlCdK2ZE_Screenshot_20151217-181204.png\",\n        \"Screenshot_20151217-181204.png\",\n        \"1080\",\n        \"1920\",\n        \"#3bb6e4\",\n        \"\"\n      ],\n      \"caption\": \"Upload\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-12-17T16:46:49.674Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":6,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"recording-data-validity","sync_unique":"","title":"Recording data validity","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Recording data validity


## Recording Data After pressing 'finish' the recording data validity is checked. So if there is some data missing you will receive a warning message. The data is checked for radio data, ground truth, acceleration, steps and rotation. After pressing 'ok' you can choose to upload or discard! [block:image] { "images": [ { "image": [ "https://files.readme.io/gW2nUxDPQUG6TepUWBO7_Screenshot_20151217-173846.png", "Screenshot_20151217-173846.png", "1080", "1920", "#5d3d0e", "" ], "caption": "Missing Data" } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/abFvTcI8Q5ygKlCdK2ZE_Screenshot_20151217-181204.png", "Screenshot_20151217-181204.png", "1080", "1920", "#3bb6e4", "" ], "caption": "Upload" } ] } [/block]
## Recording Data After pressing 'finish' the recording data validity is checked. So if there is some data missing you will receive a warning message. The data is checked for radio data, ground truth, acceleration, steps and rotation. After pressing 'ok' you can choose to upload or discard! [block:image] { "images": [ { "image": [ "https://files.readme.io/gW2nUxDPQUG6TepUWBO7_Screenshot_20151217-173846.png", "Screenshot_20151217-173846.png", "1080", "1920", "#5d3d0e", "" ], "caption": "Missing Data" } ] } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/abFvTcI8Q5ygKlCdK2ZE_Screenshot_20151217-181204.png", "Screenshot_20151217-181204.png", "1080", "1920", "#3bb6e4", "" ], "caption": "Upload" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c8209e","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"After finishing recording or measuring fingerprints you might see a message\ntelling you the number of pending uploads indicating that some uploads failed you can upload  them by pressing on the upload button in the action bar  as the following:\n\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/ZYAEEkgPR6CqBRmsMo8e_UploadButton.png\",\n        \"UploadButton.png\",\n        \"1080\",\n        \"1920\",\n        \"#0695a5\",\n        \"\"\n      ],\n      \"caption\": \"Uploading\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-03-27T17:00:07.061Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":7,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"uploading-pending-uploads","sync_unique":"","title":"Uploading Pending uploads","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Uploading Pending uploads


After finishing recording or measuring fingerprints you might see a message telling you the number of pending uploads indicating that some uploads failed you can upload them by pressing on the upload button in the action bar as the following: [block:image] { "images": [ { "image": [ "https://files.readme.io/ZYAEEkgPR6CqBRmsMo8e_UploadButton.png", "UploadButton.png", "1080", "1920", "#0695a5", "" ], "caption": "Uploading" } ] } [/block]
After finishing recording or measuring fingerprints you might see a message telling you the number of pending uploads indicating that some uploads failed you can upload them by pressing on the upload button in the action bar as the following: [block:image] { "images": [ { "image": [ "https://files.readme.io/ZYAEEkgPR6CqBRmsMo8e_UploadButton.png", "UploadButton.png", "1080", "1920", "#0695a5", "" ], "caption": "Uploading" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c8209f","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"To generate recordings you have to press on the recording button as shown in the image below.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Recording 1\",\n      \"image\": [\n        \"https://files.readme.io/bf7936SLST2NNUXVPb8N_recording.png\",\n        \"recording.png\",\n        \"1080\",\n        \"1920\",\n        \"#0493a3\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nWhen you start a recording you will be asked to calibrate the compass. This allows us to accurately get your orientation during the recording.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Compass Calibration\",\n      \"image\": [\n        \"https://files.readme.io/N0EpNkBnQRe2bzOg4Cdl_campassCaibration.png\",\n        \"campassCaibration.png\",\n        \"1080\",\n        \"1920\",\n        \"#047979\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nWhen you press on the '**OK**' button the message will disappear. \n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Recording Modes\",\n  \"body\": \"You can do recordings in two modes:\\n  * Directly, while walking\\n  * By walking along \\\"Predrawn Paths\\\"\"\n}\n[/block]\nTo start a direct recording follow these steps:\n* Zoom in \n* Move the location cursor (orange pin) to the location you want to start recording for.\n* A black dot appears with a line between the last ground truth (the black dot) and the current cursor position is drawn.  \n* **Then** press \"**CONFIRM**\" as shown in the image below.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Recording 2\",\n      \"image\": [\n        \"https://files.readme.io/4wnGbnqQt2iRrZC10cqA_chosing_recording_mode.png\",\n        \"chosing_recording_mode.png\",\n        \"1080\",\n        \"1920\",\n        \"#0594a3\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nOnce you started the recording you will see the following screen: \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/nuP7NCD4QnaTK7GU7vNx_recording_mode_old_one_point.png\",\n        \"recording_mode_old_one_point.png\",\n        \"1080\",\n        \"1920\",\n        \"#0997a6\",\n        \"\"\n      ],\n      \"caption\": \"Recording 3\"\n    }\n  ]\n}\n[/block]\nYou should add multiple \"ground truth\" points during your walk by arranging the orange marker at your current position and pressing '**CONFIRM**'.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Create this \\\"Ground Truth\\\" points every time you:\\n* start walking (at the beginning of the recording, or when you had to stop and start walking again)\\n* stop walking (e.g. when you have to stop for entering your position or when something blocks your walking path or when you stop because entered an elevator)\\n* changed walking speed\\n* start changing floors (e.g. when an elevator starts to move, or when you stepped onto an escalator or staircase)\\n* reach the new floor (when you get off an elevator or escalator or staircase)\\n* change walking direction (each time you turn for any reason)\\n\\nYou can also create ground truth at any time during a recording for no reason as long as it's accurate. But try to avoid such ground truths.\",\n  \"title\": \"When to create Ground Truth points\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Tip\",\n  \"body\": \"It is important that you carefully select your position and create the ground truth at the exact time! Therefore anticipate what you will be doing during the recording and change the orange marker to the new position before you get there. This way you can hit the '**CONFIRM**' button at the right time without stopping - as soon as you reach the preselected position!\\nYou may also switch the view to the new floor before you get there, so that you can create a ground truth as soon as the elevator or escalator arrives at the new floor.\\n\\nCreating multiple shorter recordings (30 seconds) can be easier than creating one very long recording.\"\n}\n[/block]\nWalk the route that shows the bug or error that you want to capture.\nIf there is an area where you experience problems make one ore more extensive recordings there.\nYou may also create recordings that covered a whole building so we can debug the whole building.\n\nAfter finishing the recording of the desired route, you can upload these points to the server by pressing 'Finish'.  \n\nYou will end up with your desired recording route like the image bellow.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Recording 4\",\n      \"image\": [\n        \"https://files.readme.io/7JC0YPo4Rqu0Z9WfOwV4_recording_old_mode.png\",\n        \"recording_old_mode.png\",\n        \"1080\",\n        \"1920\",\n        \"#188b98\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\nTo upload the recording just enter your username and a comment and press \"**Upload**\", if you made a mistake, or are unhappy with your recording, pressing \"**Discard**\" will throw away the recording.\n[block:image]\n{\n  \"images\": [\n    {\n      \"caption\": \"Recording 5\",\n      \"image\": [\n        \"https://files.readme.io/P8Zlq0yYT7lTC5PtR3si_FinishRecording.png\",\n        \"FinishRecording.png\",\n        \"1080\",\n        \"1920\",\n        \"#3bb6e4\",\n        \"\"\n      ]\n    }\n  ]\n}\n[/block]\n## Recordings with Predrawn Paths:\n\n**Starting from version 3.11**, the mobile toolkit has a new recording mode to ease things a bit, you can start by drawing the route you are going to walk, before you actually walk. \n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/mxkjQqfzTAuFRtHntq9C_recording_mode_predraw_path.png\",\n        \"recording_mode_predraw_path.png\",\n        \"1080\",\n        \"1920\",\n        \"#0493a3\",\n        \"\"\n      ],\n      \"caption\": \"pressing predraw\"\n    }\n  ]\n}\n[/block]\nTo enter this mode tap on the \"Predraw Path\" button in the recording menu as shown above.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Floor switching\",\n  \"body\": \"Floor switching in \\\"Predraw Path\\\" mode is disabled.\"\n}\n[/block]\nTo start drawing the path you are going to walk:\n* Zoom in\n* Move the location cursor (orange pin) to the location you want to start a recording.\n* Tap on \"**MARK GROUNDTRUTH**\" to set the first ground truth\n* A white dot appears with a line between the ground truth (the white dot) and the current cursor position\n* Tap on \"**MARK GROUNDTRUTH**\" again to set more ground truths\n* Continue with the same process until you finish drawing your route.\n* Tap on \"**FINISH DRAWING**\" when you are done creating a path that you will walk on later.\n \n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Line between ground truths\",\n  \"body\": \"The line shown between the ground truths is exacly the line that you need to walk on. Avoid intersecting any obstacles while you create this predrawn path for ground truths. Obstacles might be any objects like desks, shelves or similar that are not on your map or even wall. Gennerally if you can not pass trough it while walking, the recording should also not pass through it.\"\n}\n[/block]\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/7nDxEiqATZm6STXJIeMM_recording_predraw.png\",\n        \"recording_predraw.png\",\n        \"1080\",\n        \"1920\",\n        \"#0a97a6\",\n        \"\"\n      ],\n      \"caption\": \"Predrawing path\"\n    }\n  ]\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"You have to create at least two ground truths to see 'finish drawing'.\",\n  \"title\": \"Create at least two ground truths\"\n}\n[/block]\nAfter you have finished drawing, you will see the screen below which centers the first ground truth. There will be a blue dot in the first ground truth, so you know where to start, even if there are other ground truths close to it.  \nTo start this recording follow the instructions below.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/btMWmZzKS62ERftvgBWD_start_walking_mode.png\",\n        \"start_walking_mode.png\",\n        \"1080\",\n        \"1920\",\n        \"#0796a5\",\n        \"\"\n      ],\n      \"caption\": \"recording start\"\n    }\n  ]\n}\n[/block]\n* Take your phone and go to the actual location where the first ground truth is.\n* Press \"**START**\", you will see the first ground truth is filled with black, similar to the image below.\n* The next ground truth you have to visit is now marked with a small blue circle, to continue your recording walk until you reach this marked ground truth.\n* When you reach the ground truth press \"**CONFIRM GROUNDTRUTH**\".\n* The map is now centered on the next ground truth.\n* You have to repeat these steps until you finish you route.\n  \nIn case you are not satisfied with your recording, you can press the \"**CANCEL**\" button to go back to the drawing mode. \n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/Bo8pNBVDT4a6WlKIa8si_walking_mode.png\",\n        \"walking_mode.png\",\n        \"1080\",\n        \"1920\",\n        \"#0796a5\",\n        \"\"\n      ],\n      \"caption\": \"filled dot\"\n    }\n  ]\n}\n[/block]\nWhen you have only one ground truth left in your predrawn path, you will see the \"**FINISH**\" button, so you can walk to the last ground truth and press \"**FINISH**\".\n\n\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/4MuyHTxjTQSAbhRl6yxd_walking_mode_finish.png\",\n        \"walking_mode_finish.png\",\n        \"1080\",\n        \"1920\",\n        \"#0594a3\",\n        \"\"\n      ],\n      \"caption\": \"finish\"\n    }\n  ]\n}\n[/block]\nTo upload the recording just enter your username and a comment and press \"**Upload**\", if you made any mistake, or are unhappy with your recording, pressing \"**Discard**\" will discard the recording.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/RiFGYfGXROOGmn4qXNmO_upload.png\",\n        \"upload.png\",\n        \"1080\",\n        \"1920\",\n        \"#3fb4ca\",\n        \"\"\n      ],\n      \"caption\": \"finish upload\"\n    }\n  ]\n}\n[/block]","category":"57e3bcc2378b341700c82093","createdAt":"2015-03-13T10:56:50.211Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":8,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"recording-used-for-debugging","sync_unique":"","title":"Recording (Used for SLAM and debugging)","type":"basic","updates":["556da91cd0f4740d00380d56","556de434e24c5a0d00703587"],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

Recording (Used for SLAM and debugging)


To generate recordings you have to press on the recording button as shown in the image below. [block:image] { "images": [ { "caption": "Recording 1", "image": [ "https://files.readme.io/bf7936SLST2NNUXVPb8N_recording.png", "recording.png", "1080", "1920", "#0493a3", "" ] } ] } [/block] When you start a recording you will be asked to calibrate the compass. This allows us to accurately get your orientation during the recording. [block:image] { "images": [ { "caption": "Compass Calibration", "image": [ "https://files.readme.io/N0EpNkBnQRe2bzOg4Cdl_campassCaibration.png", "campassCaibration.png", "1080", "1920", "#047979", "" ] } ] } [/block] When you press on the '**OK**' button the message will disappear. [block:callout] { "type": "info", "title": "Recording Modes", "body": "You can do recordings in two modes:\n * Directly, while walking\n * By walking along \"Predrawn Paths\"" } [/block] To start a direct recording follow these steps: * Zoom in * Move the location cursor (orange pin) to the location you want to start recording for. * A black dot appears with a line between the last ground truth (the black dot) and the current cursor position is drawn. * **Then** press "**CONFIRM**" as shown in the image below. [block:image] { "images": [ { "caption": "Recording 2", "image": [ "https://files.readme.io/4wnGbnqQt2iRrZC10cqA_chosing_recording_mode.png", "chosing_recording_mode.png", "1080", "1920", "#0594a3", "" ] } ] } [/block] Once you started the recording you will see the following screen: [block:image] { "images": [ { "image": [ "https://files.readme.io/nuP7NCD4QnaTK7GU7vNx_recording_mode_old_one_point.png", "recording_mode_old_one_point.png", "1080", "1920", "#0997a6", "" ], "caption": "Recording 3" } ] } [/block] You should add multiple "ground truth" points during your walk by arranging the orange marker at your current position and pressing '**CONFIRM**'. [block:callout] { "type": "warning", "body": "Create this \"Ground Truth\" points every time you:\n* start walking (at the beginning of the recording, or when you had to stop and start walking again)\n* stop walking (e.g. when you have to stop for entering your position or when something blocks your walking path or when you stop because entered an elevator)\n* changed walking speed\n* start changing floors (e.g. when an elevator starts to move, or when you stepped onto an escalator or staircase)\n* reach the new floor (when you get off an elevator or escalator or staircase)\n* change walking direction (each time you turn for any reason)\n\nYou can also create ground truth at any time during a recording for no reason as long as it's accurate. But try to avoid such ground truths.", "title": "When to create Ground Truth points" } [/block] [block:callout] { "type": "info", "title": "Tip", "body": "It is important that you carefully select your position and create the ground truth at the exact time! Therefore anticipate what you will be doing during the recording and change the orange marker to the new position before you get there. This way you can hit the '**CONFIRM**' button at the right time without stopping - as soon as you reach the preselected position!\nYou may also switch the view to the new floor before you get there, so that you can create a ground truth as soon as the elevator or escalator arrives at the new floor.\n\nCreating multiple shorter recordings (30 seconds) can be easier than creating one very long recording." } [/block] Walk the route that shows the bug or error that you want to capture. If there is an area where you experience problems make one ore more extensive recordings there. You may also create recordings that covered a whole building so we can debug the whole building. After finishing the recording of the desired route, you can upload these points to the server by pressing 'Finish'. You will end up with your desired recording route like the image bellow. [block:image] { "images": [ { "caption": "Recording 4", "image": [ "https://files.readme.io/7JC0YPo4Rqu0Z9WfOwV4_recording_old_mode.png", "recording_old_mode.png", "1080", "1920", "#188b98", "" ] } ] } [/block] To upload the recording just enter your username and a comment and press "**Upload**", if you made a mistake, or are unhappy with your recording, pressing "**Discard**" will throw away the recording. [block:image] { "images": [ { "caption": "Recording 5", "image": [ "https://files.readme.io/P8Zlq0yYT7lTC5PtR3si_FinishRecording.png", "FinishRecording.png", "1080", "1920", "#3bb6e4", "" ] } ] } [/block] ## Recordings with Predrawn Paths: **Starting from version 3.11**, the mobile toolkit has a new recording mode to ease things a bit, you can start by drawing the route you are going to walk, before you actually walk. [block:image] { "images": [ { "image": [ "https://files.readme.io/mxkjQqfzTAuFRtHntq9C_recording_mode_predraw_path.png", "recording_mode_predraw_path.png", "1080", "1920", "#0493a3", "" ], "caption": "pressing predraw" } ] } [/block] To enter this mode tap on the "Predraw Path" button in the recording menu as shown above. [block:callout] { "type": "warning", "title": "Floor switching", "body": "Floor switching in \"Predraw Path\" mode is disabled." } [/block] To start drawing the path you are going to walk: * Zoom in * Move the location cursor (orange pin) to the location you want to start a recording. * Tap on "**MARK GROUNDTRUTH**" to set the first ground truth * A white dot appears with a line between the ground truth (the white dot) and the current cursor position * Tap on "**MARK GROUNDTRUTH**" again to set more ground truths * Continue with the same process until you finish drawing your route. * Tap on "**FINISH DRAWING**" when you are done creating a path that you will walk on later. [block:callout] { "type": "info", "title": "Line between ground truths", "body": "The line shown between the ground truths is exacly the line that you need to walk on. Avoid intersecting any obstacles while you create this predrawn path for ground truths. Obstacles might be any objects like desks, shelves or similar that are not on your map or even wall. Gennerally if you can not pass trough it while walking, the recording should also not pass through it." } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/7nDxEiqATZm6STXJIeMM_recording_predraw.png", "recording_predraw.png", "1080", "1920", "#0a97a6", "" ], "caption": "Predrawing path" } ] } [/block] [block:callout] { "type": "warning", "body": "You have to create at least two ground truths to see 'finish drawing'.", "title": "Create at least two ground truths" } [/block] After you have finished drawing, you will see the screen below which centers the first ground truth. There will be a blue dot in the first ground truth, so you know where to start, even if there are other ground truths close to it. To start this recording follow the instructions below. [block:image] { "images": [ { "image": [ "https://files.readme.io/btMWmZzKS62ERftvgBWD_start_walking_mode.png", "start_walking_mode.png", "1080", "1920", "#0796a5", "" ], "caption": "recording start" } ] } [/block] * Take your phone and go to the actual location where the first ground truth is. * Press "**START**", you will see the first ground truth is filled with black, similar to the image below. * The next ground truth you have to visit is now marked with a small blue circle, to continue your recording walk until you reach this marked ground truth. * When you reach the ground truth press "**CONFIRM GROUNDTRUTH**". * The map is now centered on the next ground truth. * You have to repeat these steps until you finish you route. In case you are not satisfied with your recording, you can press the "**CANCEL**" button to go back to the drawing mode. [block:image] { "images": [ { "image": [ "https://files.readme.io/Bo8pNBVDT4a6WlKIa8si_walking_mode.png", "walking_mode.png", "1080", "1920", "#0796a5", "" ], "caption": "filled dot" } ] } [/block] When you have only one ground truth left in your predrawn path, you will see the "**FINISH**" button, so you can walk to the last ground truth and press "**FINISH**". [block:image] { "images": [ { "image": [ "https://files.readme.io/4MuyHTxjTQSAbhRl6yxd_walking_mode_finish.png", "walking_mode_finish.png", "1080", "1920", "#0594a3", "" ], "caption": "finish" } ] } [/block] To upload the recording just enter your username and a comment and press "**Upload**", if you made any mistake, or are unhappy with your recording, pressing "**Discard**" will discard the recording. [block:image] { "images": [ { "image": [ "https://files.readme.io/RiFGYfGXROOGmn4qXNmO_upload.png", "upload.png", "1080", "1920", "#3fb4ca", "" ], "caption": "finish upload" } ] } [/block]
To generate recordings you have to press on the recording button as shown in the image below. [block:image] { "images": [ { "caption": "Recording 1", "image": [ "https://files.readme.io/bf7936SLST2NNUXVPb8N_recording.png", "recording.png", "1080", "1920", "#0493a3", "" ] } ] } [/block] When you start a recording you will be asked to calibrate the compass. This allows us to accurately get your orientation during the recording. [block:image] { "images": [ { "caption": "Compass Calibration", "image": [ "https://files.readme.io/N0EpNkBnQRe2bzOg4Cdl_campassCaibration.png", "campassCaibration.png", "1080", "1920", "#047979", "" ] } ] } [/block] When you press on the '**OK**' button the message will disappear. [block:callout] { "type": "info", "title": "Recording Modes", "body": "You can do recordings in two modes:\n * Directly, while walking\n * By walking along \"Predrawn Paths\"" } [/block] To start a direct recording follow these steps: * Zoom in * Move the location cursor (orange pin) to the location you want to start recording for. * A black dot appears with a line between the last ground truth (the black dot) and the current cursor position is drawn. * **Then** press "**CONFIRM**" as shown in the image below. [block:image] { "images": [ { "caption": "Recording 2", "image": [ "https://files.readme.io/4wnGbnqQt2iRrZC10cqA_chosing_recording_mode.png", "chosing_recording_mode.png", "1080", "1920", "#0594a3", "" ] } ] } [/block] Once you started the recording you will see the following screen: [block:image] { "images": [ { "image": [ "https://files.readme.io/nuP7NCD4QnaTK7GU7vNx_recording_mode_old_one_point.png", "recording_mode_old_one_point.png", "1080", "1920", "#0997a6", "" ], "caption": "Recording 3" } ] } [/block] You should add multiple "ground truth" points during your walk by arranging the orange marker at your current position and pressing '**CONFIRM**'. [block:callout] { "type": "warning", "body": "Create this \"Ground Truth\" points every time you:\n* start walking (at the beginning of the recording, or when you had to stop and start walking again)\n* stop walking (e.g. when you have to stop for entering your position or when something blocks your walking path or when you stop because entered an elevator)\n* changed walking speed\n* start changing floors (e.g. when an elevator starts to move, or when you stepped onto an escalator or staircase)\n* reach the new floor (when you get off an elevator or escalator or staircase)\n* change walking direction (each time you turn for any reason)\n\nYou can also create ground truth at any time during a recording for no reason as long as it's accurate. But try to avoid such ground truths.", "title": "When to create Ground Truth points" } [/block] [block:callout] { "type": "info", "title": "Tip", "body": "It is important that you carefully select your position and create the ground truth at the exact time! Therefore anticipate what you will be doing during the recording and change the orange marker to the new position before you get there. This way you can hit the '**CONFIRM**' button at the right time without stopping - as soon as you reach the preselected position!\nYou may also switch the view to the new floor before you get there, so that you can create a ground truth as soon as the elevator or escalator arrives at the new floor.\n\nCreating multiple shorter recordings (30 seconds) can be easier than creating one very long recording." } [/block] Walk the route that shows the bug or error that you want to capture. If there is an area where you experience problems make one ore more extensive recordings there. You may also create recordings that covered a whole building so we can debug the whole building. After finishing the recording of the desired route, you can upload these points to the server by pressing 'Finish'. You will end up with your desired recording route like the image bellow. [block:image] { "images": [ { "caption": "Recording 4", "image": [ "https://files.readme.io/7JC0YPo4Rqu0Z9WfOwV4_recording_old_mode.png", "recording_old_mode.png", "1080", "1920", "#188b98", "" ] } ] } [/block] To upload the recording just enter your username and a comment and press "**Upload**", if you made a mistake, or are unhappy with your recording, pressing "**Discard**" will throw away the recording. [block:image] { "images": [ { "caption": "Recording 5", "image": [ "https://files.readme.io/P8Zlq0yYT7lTC5PtR3si_FinishRecording.png", "FinishRecording.png", "1080", "1920", "#3bb6e4", "" ] } ] } [/block] ## Recordings with Predrawn Paths: **Starting from version 3.11**, the mobile toolkit has a new recording mode to ease things a bit, you can start by drawing the route you are going to walk, before you actually walk. [block:image] { "images": [ { "image": [ "https://files.readme.io/mxkjQqfzTAuFRtHntq9C_recording_mode_predraw_path.png", "recording_mode_predraw_path.png", "1080", "1920", "#0493a3", "" ], "caption": "pressing predraw" } ] } [/block] To enter this mode tap on the "Predraw Path" button in the recording menu as shown above. [block:callout] { "type": "warning", "title": "Floor switching", "body": "Floor switching in \"Predraw Path\" mode is disabled." } [/block] To start drawing the path you are going to walk: * Zoom in * Move the location cursor (orange pin) to the location you want to start a recording. * Tap on "**MARK GROUNDTRUTH**" to set the first ground truth * A white dot appears with a line between the ground truth (the white dot) and the current cursor position * Tap on "**MARK GROUNDTRUTH**" again to set more ground truths * Continue with the same process until you finish drawing your route. * Tap on "**FINISH DRAWING**" when you are done creating a path that you will walk on later. [block:callout] { "type": "info", "title": "Line between ground truths", "body": "The line shown between the ground truths is exacly the line that you need to walk on. Avoid intersecting any obstacles while you create this predrawn path for ground truths. Obstacles might be any objects like desks, shelves or similar that are not on your map or even wall. Gennerally if you can not pass trough it while walking, the recording should also not pass through it." } [/block] [block:image] { "images": [ { "image": [ "https://files.readme.io/7nDxEiqATZm6STXJIeMM_recording_predraw.png", "recording_predraw.png", "1080", "1920", "#0a97a6", "" ], "caption": "Predrawing path" } ] } [/block] [block:callout] { "type": "warning", "body": "You have to create at least two ground truths to see 'finish drawing'.", "title": "Create at least two ground truths" } [/block] After you have finished drawing, you will see the screen below which centers the first ground truth. There will be a blue dot in the first ground truth, so you know where to start, even if there are other ground truths close to it. To start this recording follow the instructions below. [block:image] { "images": [ { "image": [ "https://files.readme.io/btMWmZzKS62ERftvgBWD_start_walking_mode.png", "start_walking_mode.png", "1080", "1920", "#0796a5", "" ], "caption": "recording start" } ] } [/block] * Take your phone and go to the actual location where the first ground truth is. * Press "**START**", you will see the first ground truth is filled with black, similar to the image below. * The next ground truth you have to visit is now marked with a small blue circle, to continue your recording walk until you reach this marked ground truth. * When you reach the ground truth press "**CONFIRM GROUNDTRUTH**". * The map is now centered on the next ground truth. * You have to repeat these steps until you finish you route. In case you are not satisfied with your recording, you can press the "**CANCEL**" button to go back to the drawing mode. [block:image] { "images": [ { "image": [ "https://files.readme.io/Bo8pNBVDT4a6WlKIa8si_walking_mode.png", "walking_mode.png", "1080", "1920", "#0796a5", "" ], "caption": "filled dot" } ] } [/block] When you have only one ground truth left in your predrawn path, you will see the "**FINISH**" button, so you can walk to the last ground truth and press "**FINISH**". [block:image] { "images": [ { "image": [ "https://files.readme.io/4MuyHTxjTQSAbhRl6yxd_walking_mode_finish.png", "walking_mode_finish.png", "1080", "1920", "#0594a3", "" ], "caption": "finish" } ] } [/block] To upload the recording just enter your username and a comment and press "**Upload**", if you made any mistake, or are unhappy with your recording, pressing "**Discard**" will discard the recording. [block:image] { "images": [ { "image": [ "https://files.readme.io/RiFGYfGXROOGmn4qXNmO_upload.png", "upload.png", "1080", "1920", "#3fb4ca", "" ], "caption": "finish upload" } ] } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820cd","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"With the 3.10 release we have announced that our SLAM Engine™ is up and running!\nSLAM (Simultaneous Localization and Mapping) Engine™ is a technology which significantly reduces the amount of time needed to map a building. You just need to walk around the venue with the mobile toolkit at a regular pace and record ground truths whenever you change directions. \nFor details on how to do recordings please check out the [Recording (Used for SLAM and debugging)](doc:recording-used-for-debugging) section.\nOnce you are done with recording you can create a SLAM Request over [support.indoo.rs](http://support.indoo.rs) with your API key and building ID so we can generate the map for you.\n\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Only one type of recording device\",\n  \"body\": \"The current version of the SLAM Engine supports a single type of device per recording session so make sure that when you create slam job recordings, that they all are done using the same phone type (Android versions do not matter).\"\n}\n[/block]\n**Note:** Make sure you have set the position and rotation of your building in MMT (https://my.indoo.rs/javadoc/mmt_guide/ - section Create New Building)","category":"57e3bcc2378b341700c82095","createdAt":"2016-01-20T17:02:53.992Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":0,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"slam-in-a-nutshell","sync_unique":"","title":"SLAM in a nutshell","type":"basic","updates":["56a888b02036420d002d2222"],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

SLAM in a nutshell


With the 3.10 release we have announced that our SLAM Engine™ is up and running! SLAM (Simultaneous Localization and Mapping) Engine™ is a technology which significantly reduces the amount of time needed to map a building. You just need to walk around the venue with the mobile toolkit at a regular pace and record ground truths whenever you change directions. For details on how to do recordings please check out the [Recording (Used for SLAM and debugging)](doc:recording-used-for-debugging) section. Once you are done with recording you can create a SLAM Request over [support.indoo.rs](http://support.indoo.rs) with your API key and building ID so we can generate the map for you. [block:callout] { "type": "warning", "title": "Only one type of recording device", "body": "The current version of the SLAM Engine supports a single type of device per recording session so make sure that when you create slam job recordings, that they all are done using the same phone type (Android versions do not matter)." } [/block] **Note:** Make sure you have set the position and rotation of your building in MMT (https://my.indoo.rs/javadoc/mmt_guide/ - section Create New Building)
With the 3.10 release we have announced that our SLAM Engine™ is up and running! SLAM (Simultaneous Localization and Mapping) Engine™ is a technology which significantly reduces the amount of time needed to map a building. You just need to walk around the venue with the mobile toolkit at a regular pace and record ground truths whenever you change directions. For details on how to do recordings please check out the [Recording (Used for SLAM and debugging)](doc:recording-used-for-debugging) section. Once you are done with recording you can create a SLAM Request over [support.indoo.rs](http://support.indoo.rs) with your API key and building ID so we can generate the map for you. [block:callout] { "type": "warning", "title": "Only one type of recording device", "body": "The current version of the SLAM Engine supports a single type of device per recording session so make sure that when you create slam job recordings, that they all are done using the same phone type (Android versions do not matter)." } [/block] **Note:** Make sure you have set the position and rotation of your building in MMT (https://my.indoo.rs/javadoc/mmt_guide/ - section Create New Building)
{"__v":0,"_id":"57e3bcc2378b341700c820a0","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"* You can now include the indoo.rs SDK in your Swift projects\n* The indoo.rs SDK for Android is now delivered as an .aar for easier usage in Android Studio\n* Building object is extended with latitude longitude, rotation and description information.\n* On Android IndoorsLocationListener's delegate callback method leftBuilding is now deprecated.\n* Several bug fixes and increase in stability  \n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"API change\",\n  \"body\": \"In order to support Swift, iOS SDK public API has changed. You can see full change log [here](/v4.2.0/docs/getting-started-with-indoors-ios-sdk)\"\n}\n[/block]","category":"57e3bcc2378b341700c82096","createdAt":"2015-08-25T13:28:30.297Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":0,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"360","sync_unique":"","title":"4.2.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

4.2.0


* You can now include the indoo.rs SDK in your Swift projects * The indoo.rs SDK for Android is now delivered as an .aar for easier usage in Android Studio * Building object is extended with latitude longitude, rotation and description information. * On Android IndoorsLocationListener's delegate callback method leftBuilding is now deprecated. * Several bug fixes and increase in stability [block:callout] { "type": "warning", "title": "API change", "body": "In order to support Swift, iOS SDK public API has changed. You can see full change log [here](/v4.2.0/docs/getting-started-with-indoors-ios-sdk)" } [/block]
* You can now include the indoo.rs SDK in your Swift projects * The indoo.rs SDK for Android is now delivered as an .aar for easier usage in Android Studio * Building object is extended with latitude longitude, rotation and description information. * On Android IndoorsLocationListener's delegate callback method leftBuilding is now deprecated. * Several bug fixes and increase in stability [block:callout] { "type": "warning", "title": "API change", "body": "In order to support Swift, iOS SDK public API has changed. You can see full change log [here](/v4.2.0/docs/getting-started-with-indoors-ios-sdk)" } [/block]
{"__v":0,"_id":"57e3bcc2378b341700c820d5","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"* You can now disable Kalman filter that we use for improving accuracy in some venues.\n* Stabilisation filter can also be disabled, and time before Stabilisation filter kicks in can be changed.","category":"57e3bcc2378b341700c82096","createdAt":"2016-06-27T14:54:06.265Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":1,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"410","sync_unique":"","title":"4.1.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

4.1.0


* You can now disable Kalman filter that we use for improving accuracy in some venues. * Stabilisation filter can also be disabled, and time before Stabilisation filter kicks in can be changed.
* You can now disable Kalman filter that we use for improving accuracy in some venues. * Stabilisation filter can also be disabled, and time before Stabilisation filter kicks in can be changed.
{"__v":0,"_id":"57e3bcc2378b341700c820d6","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"- Fixed a bug on iOS where routes might not be displayed correctly","category":"57e3bcc2378b341700c82096","createdAt":"2016-03-30T15:27:09.469Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":2,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"402","sync_unique":"","title":"4.0.2","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

4.0.2


- Fixed a bug on iOS where routes might not be displayed correctly
- Fixed a bug on iOS where routes might not be displayed correctly
{"__v":0,"_id":"57e3bcc2378b341700c820d7","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"* We’ve implemented a new Kalman filter that improves the accuracy up to 15% on existing maps\n* Mobile Toolkit has a new feature to draw the recording path in advance and walk through it\n* Fixed an issue with Mobile toolkit  in which the mobile toolkit sometimes did not record all ground truths for recordings. \n* iOS option to ‘alwaysDownloadNewBuildingVersion' is now set to false by default in SDK. This was   causing problems with bundled maps.\n* Several bug fixes and stability improvements","category":"57e3bcc2378b341700c82096","createdAt":"2016-02-09T13:11:20.123Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":3,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"400","sync_unique":"","title":"4.0.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

4.0.0


* We’ve implemented a new Kalman filter that improves the accuracy up to 15% on existing maps * Mobile Toolkit has a new feature to draw the recording path in advance and walk through it * Fixed an issue with Mobile toolkit in which the mobile toolkit sometimes did not record all ground truths for recordings. * iOS option to ‘alwaysDownloadNewBuildingVersion' is now set to false by default in SDK. This was causing problems with bundled maps. * Several bug fixes and stability improvements
* We’ve implemented a new Kalman filter that improves the accuracy up to 15% on existing maps * Mobile Toolkit has a new feature to draw the recording path in advance and walk through it * Fixed an issue with Mobile toolkit in which the mobile toolkit sometimes did not record all ground truths for recordings. * iOS option to ‘alwaysDownloadNewBuildingVersion' is now set to false by default in SDK. This was causing problems with bundled maps. * Several bug fixes and stability improvements
{"__v":0,"_id":"57e3bcc2378b341700c820d8","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"* You can now cancel building downloads for Viewer and SDK. \n* You can now limit the location updates to snap to predefined routes even when not navigating and you can tweak the distance the dot is allowed to go astray !\n* Fixed a bug in the MMT where some predefined routes were not deleted.\n* You will notice the dot not moving when you are not, thanks to our updated stabilization filter.\n* Indoors.framework and IndoorsSurface.framework joined in a single instance of IndoorsSDK.framework.\n* Mobile toolkit vibrates when measuring fingerprints is finished.\n* Show wheel of patience when calculating routes on iOS Viewer.\n* The example app (MyFirstIndoorsAppIOS) is now available as a public repository: https://bitbucket.org/indoors/myfirstindoorsappios/src \n* Several bug fixes.","category":"57e3bcc2378b341700c82096","createdAt":"2015-11-26T08:55:25.981Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":4,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"380","sync_unique":"","title":"3.8.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

3.8.0


* You can now cancel building downloads for Viewer and SDK. * You can now limit the location updates to snap to predefined routes even when not navigating and you can tweak the distance the dot is allowed to go astray ! * Fixed a bug in the MMT where some predefined routes were not deleted. * You will notice the dot not moving when you are not, thanks to our updated stabilization filter. * Indoors.framework and IndoorsSurface.framework joined in a single instance of IndoorsSDK.framework. * Mobile toolkit vibrates when measuring fingerprints is finished. * Show wheel of patience when calculating routes on iOS Viewer. * The example app (MyFirstIndoorsAppIOS) is now available as a public repository: https://bitbucket.org/indoors/myfirstindoorsappios/src * Several bug fixes.
* You can now cancel building downloads for Viewer and SDK. * You can now limit the location updates to snap to predefined routes even when not navigating and you can tweak the distance the dot is allowed to go astray ! * Fixed a bug in the MMT where some predefined routes were not deleted. * You will notice the dot not moving when you are not, thanks to our updated stabilization filter. * Indoors.framework and IndoorsSurface.framework joined in a single instance of IndoorsSDK.framework. * Mobile toolkit vibrates when measuring fingerprints is finished. * Show wheel of patience when calculating routes on iOS Viewer. * The example app (MyFirstIndoorsAppIOS) is now available as a public repository: https://bitbucket.org/indoors/myfirstindoorsappios/src * Several bug fixes.
{"__v":0,"_id":"57e3bcc2378b341700c820d9","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"* You can now draw your own routes for most prominent areas and let MMT generate the rest. As a result, you will have a much cleaner and lighter routing graph which will speed up routing to take max. 5 seconds on even the biggest buildings\n* We made the surface zoom level and position public and restorable via api and tackled some performance issues with zooming on iOS\n* We added a Stabilization Filter based on walking and moving events\n* Fixed a bug where reset to factory defaults didn't clear the building cache in iOS Viewer\n* Fixed \"Delete application\" in the account manager\n* Allow user to not show the position dot - iOS\n* Fixed that a listener was not deallocated on iOS\n* We deprecated the \"connected\" delegate method in IndoorsServiceDelegate\n* Added an API to get SDK version info\n\nKnown Issue:\nDrawing of routes in MMT doesn't work on Mac computers. We are working on a fix for it\n\nNote:\nThe latest xcode7 Bitcode isn't yet supported by our SDK. Support will come in our future release.","category":"57e3bcc2378b341700c82096","createdAt":"2015-11-26T08:54:59.544Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":5,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"370","sync_unique":"","title":"3.7.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

3.7.0


* You can now draw your own routes for most prominent areas and let MMT generate the rest. As a result, you will have a much cleaner and lighter routing graph which will speed up routing to take max. 5 seconds on even the biggest buildings * We made the surface zoom level and position public and restorable via api and tackled some performance issues with zooming on iOS * We added a Stabilization Filter based on walking and moving events * Fixed a bug where reset to factory defaults didn't clear the building cache in iOS Viewer * Fixed "Delete application" in the account manager * Allow user to not show the position dot - iOS * Fixed that a listener was not deallocated on iOS * We deprecated the "connected" delegate method in IndoorsServiceDelegate * Added an API to get SDK version info Known Issue: Drawing of routes in MMT doesn't work on Mac computers. We are working on a fix for it Note: The latest xcode7 Bitcode isn't yet supported by our SDK. Support will come in our future release.
* You can now draw your own routes for most prominent areas and let MMT generate the rest. As a result, you will have a much cleaner and lighter routing graph which will speed up routing to take max. 5 seconds on even the biggest buildings * We made the surface zoom level and position public and restorable via api and tackled some performance issues with zooming on iOS * We added a Stabilization Filter based on walking and moving events * Fixed a bug where reset to factory defaults didn't clear the building cache in iOS Viewer * Fixed "Delete application" in the account manager * Allow user to not show the position dot - iOS * Fixed that a listener was not deallocated on iOS * We deprecated the "connected" delegate method in IndoorsServiceDelegate * Added an API to get SDK version info Known Issue: Drawing of routes in MMT doesn't work on Mac computers. We are working on a fix for it Note: The latest xcode7 Bitcode isn't yet supported by our SDK. Support will come in our future release.
{"__v":0,"_id":"57e3bcc2378b341700c820da","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"* The viewer now includes our interactor SDK!\n* It is now possible to run the SDK without the Locator service on iOS\n* It is possible to add beacons to a map that already contains fingerprints\n* Moved unpacking of pre-bundled buildings to a background thread to avoid issues on iOS\n* Fixed a crash when Restarting the SDK too quickly\n* The Mobile Toolkit no longer has issues with special characters in building names\n* Fixed the routing dialog in landscape mode in the viewer on iOS\n* Fixed uploading a building from a saved idm to the cloud when the building was deleted in the meantime\n* Fixed blurry labels in some zoom cases on iOS","category":"57e3bcc2378b341700c82096","createdAt":"2015-11-26T08:54:40.320Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":6,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"360-1","sync_unique":"","title":"3.6.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

3.6.0


* The viewer now includes our interactor SDK! * It is now possible to run the SDK without the Locator service on iOS * It is possible to add beacons to a map that already contains fingerprints * Moved unpacking of pre-bundled buildings to a background thread to avoid issues on iOS * Fixed a crash when Restarting the SDK too quickly * The Mobile Toolkit no longer has issues with special characters in building names * Fixed the routing dialog in landscape mode in the viewer on iOS * Fixed uploading a building from a saved idm to the cloud when the building was deleted in the meantime * Fixed blurry labels in some zoom cases on iOS
* The viewer now includes our interactor SDK! * It is now possible to run the SDK without the Locator service on iOS * It is possible to add beacons to a map that already contains fingerprints * Moved unpacking of pre-bundled buildings to a background thread to avoid issues on iOS * Fixed a crash when Restarting the SDK too quickly * The Mobile Toolkit no longer has issues with special characters in building names * Fixed the routing dialog in landscape mode in the viewer on iOS * Fixed uploading a building from a saved idm to the cloud when the building was deleted in the meantime * Fixed blurry labels in some zoom cases on iOS
{"__v":0,"_id":"57e3bcc2378b341700c820db","api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"body":"* We have rewritten parts of the core Locator that bring huge accuracy and latency improvements.\n* GPS fallback now works with Proximity maps.\n* Changed zone searching in the Viewer on Android to be more user friendly and display a list.\n* Clicking on the app icon for the Mobile Toolkit in the notification bar now shows app info.\n* When the map is zoomed out to show the whole building, it's no longer locked to the center of the screen.\n* Selecting a zone in a building without a position no longer shows a route from zone to the top left\n* Fixed a bug where the IndoorsSurfaceFragment continuously displays \"loading\".\n* Fixed a crash during 3rd or 4th route navigation.\n* Viewer now highlights zones when entering them again.\n* Deleting beacons from the MMT no longer deletes all fingerprints.\n* Removed Zone Fencing option from the Viewer menu\n* New Icon for building load menu.\n* Added an option to run the Surface SDK without the Locator.","category":"57e3bcc2378b341700c82096","createdAt":"2015-07-22T13:54:00.699Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":7,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"350","sync_unique":"","title":"3.5.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

3.5.0


* We have rewritten parts of the core Locator that bring huge accuracy and latency improvements. * GPS fallback now works with Proximity maps. * Changed zone searching in the Viewer on Android to be more user friendly and display a list. * Clicking on the app icon for the Mobile Toolkit in the notification bar now shows app info. * When the map is zoomed out to show the whole building, it's no longer locked to the center of the screen. * Selecting a zone in a building without a position no longer shows a route from zone to the top left * Fixed a bug where the IndoorsSurfaceFragment continuously displays "loading". * Fixed a crash during 3rd or 4th route navigation. * Viewer now highlights zones when entering them again. * Deleting beacons from the MMT no longer deletes all fingerprints. * Removed Zone Fencing option from the Viewer menu * New Icon for building load menu. * Added an option to run the Surface SDK without the Locator.
* We have rewritten parts of the core Locator that bring huge accuracy and latency improvements. * GPS fallback now works with Proximity maps. * Changed zone searching in the Viewer on Android to be more user friendly and display a list. * Clicking on the app icon for the Mobile Toolkit in the notification bar now shows app info. * When the map is zoomed out to show the whole building, it's no longer locked to the center of the screen. * Selecting a zone in a building without a position no longer shows a route from zone to the top left * Fixed a bug where the IndoorsSurfaceFragment continuously displays "loading". * Fixed a crash during 3rd or 4th route navigation. * Viewer now highlights zones when entering them again. * Deleting beacons from the MMT no longer deletes all fingerprints. * Removed Zone Fencing option from the Viewer menu * New Icon for building load menu. * Added an option to run the Surface SDK without the Locator.
{"__v":0,"_id":"57e3bcc2378b341700c820dc","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"* Fixed an issue with downloading buildings that were already cached on the device","category":"57e3bcc2378b341700c82096","createdAt":"2015-08-25T13:26:51.045Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":8,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"341","sync_unique":"","title":"3.4.1","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

3.4.1


* Fixed an issue with downloading buildings that were already cached on the device
* Fixed an issue with downloading buildings that were already cached on the device
{"__v":0,"_id":"57e3bcc2378b341700c820dd","api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"body":"* You are now able to configure the location update interval which allows simple tweaking of the locator to provide either faster location updates or more accurate results.\n* The Viewer now notifies the user if downloading a building fails because of no internet connection\n* The building Id for the building has now been made constant. Different revisions are still kept in the database but under a constant identifier\n* Smoother load progress bar\n* Prettier location and navigation icons\n* Various crashes","category":"57e3bcc2378b341700c82096","createdAt":"2015-08-25T13:27:10.498Z","excerpt":"","githubsync":"","hidden":false,"isReference":false,"link_external":false,"link_url":"","order":9,"parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","slug":"340","sync_unique":"","title":"3.4.0","type":"basic","updates":[],"user":"54e5a4a0d3ab670d00f3af54","version":"57e3bcc1378b341700c8208f","childrenPages":[]}

3.4.0


* You are now able to configure the location update interval which allows simple tweaking of the locator to provide either faster location updates or more accurate results. * The Viewer now notifies the user if downloading a building fails because of no internet connection * The building Id for the building has now been made constant. Different revisions are still kept in the database but under a constant identifier * Smoother load progress bar * Prettier location and navigation icons * Various crashes
* You are now able to configure the location update interval which allows simple tweaking of the locator to provide either faster location updates or more accurate results. * The Viewer now notifies the user if downloading a building fails because of no internet connection * The building Id for the building has now been made constant. Different revisions are still kept in the database but under a constant identifier * Smoother load progress bar * Prettier location and navigation icons * Various crashes