{"_id":"59ca4b164bec1e0010fe4b4c","category":"59ca4b164bec1e0010fe4b38","user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-04-06T16:03:59.885Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"method":"get","results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"- iOS SDK: reduce size by two thirds\n- iOS SDK: exclude modulemap by default\n- Android SDK: publish on Maven Central\n- Android SDK: Background Locator\n- Android SDK: improve rendering of Routing\n- Cordova: expose Path Snapping","excerpt":"","slug":"changelog","type":"basic","title":"4.8.0","__v":0,"childrenPages":[]}

4.8.0


- iOS SDK: reduce size by two thirds - iOS SDK: exclude modulemap by default - Android SDK: publish on Maven Central - Android SDK: Background Locator - Android SDK: improve rendering of Routing - Cordova: expose Path Snapping
- iOS SDK: reduce size by two thirds - iOS SDK: exclude modulemap by default - Android SDK: publish on Maven Central - Android SDK: Background Locator - Android SDK: improve rendering of Routing - Cordova: expose Path Snapping
{"_id":"59ca4b174bec1e0010fe4b5a","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-17T08:11:15.974Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","status":200,"language":"json","code":"{}"},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"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.","excerpt":"","slug":"getting-started-with-indoors-android-guide","type":"basic","title":"Getting Started with the indoo.rs Android-SDK","__v":0,"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.
{"_id":"59ca4b174bec1e0010fe4b5b","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:24:57.419Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"code":"{}","name":"","status":400,"language":"json"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"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).","excerpt":"","slug":"sample-project","type":"basic","title":"Sample Project","__v":0,"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).
{"_id":"59ca4b174bec1e0010fe4b5c","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:24:25.470Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"code":"{}","name":"","status":400,"language":"json"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"Hosted on Maven Central\",\n  \"body\": \"Starting with version 4.8.0 the SDK is deployed on maven central\"\n}\n[/block]\n## Integrating SDK in gradle\nPlease add the ``mavenCentral`` repository 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        mavenCentral()\\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}\\n\\ndef indoorsVersion=\\\"4.8.0\\\"\\n\\ndependencies{    \\n    compile group: 'com.customlbs.android', name: 'indoors-library-surface', version: indoorsVersion, ext: 'aar', classifier: 'release'\\n    compile 'com.google.guava:guava:18.0'\\n    compile 'org.slf4j:slf4j-api:1.7.0'\\n}\",\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.BLUETOOTH\\\" />\\n    <uses-permission android:name=\\\"android.permission.BLUETOOTH_ADMIN\\\" /> \\n    <uses-permission android:name=\\\"android.permission.ACCESS_COARSE_LOCATION\\\"/>\\n\\t\\t<!-- or ACCESS_FINE_LOCATION -->\\n\\n\\t\\t<!-- only needed if wifi localization is used: -->\\n    <uses-permission android:name=\\\"android.permission.ACCESS_WIFI_STATE\\\" />\\n    <uses-permission android:name=\\\"android.permission.CHANGE_WIFI_STATE\\\" />\\n\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\nThe permissions for ``android.permission.INTERNET`` and ``android.permission.ACCESS_NETWORK_STATE`` are implicitly given by integrating the SDK.\n\nIf you do not want them because you use the ``forceOffline`` mode you can remove them in your App like this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"<uses-permission android:name=\\\"android.permission.INTERNET\\\" tools:node=\\\"remove\\\"/>\\n<uses-permission android:name=\\\"android.permission.ACCESS_NETWORK_STATE\\\" tools:node=\\\"remove\\\"/>\",\n      \"language\": \"xml\"\n    }\n  ]\n}\n[/block]\n## Integrating SDK in code\n\nOne more thing you have to include 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]","excerpt":"","slug":"integrating-indoors-into-an-existing-app","type":"basic","title":"Integrating indoo.rs into an existing App","__v":0,"childrenPages":[]}

Integrating indoo.rs into an existing App


[block:callout] { "type": "danger", "title": "Hosted on Maven Central", "body": "Starting with version 4.8.0 the SDK is deployed on maven central" } [/block] ## Integrating SDK in gradle Please add the ``mavenCentral`` repository 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 mavenCentral()\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}\n\ndef indoorsVersion=\"4.8.0\"\n\ndependencies{ \n compile group: 'com.customlbs.android', name: 'indoors-library-surface', version: indoorsVersion, ext: 'aar', classifier: 'release'\n compile 'com.google.guava:guava:18.0'\n compile 'org.slf4j:slf4j-api:1.7.0'\n}", "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.BLUETOOTH\" />\n <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" /> \n <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n\t\t<!-- or ACCESS_FINE_LOCATION -->\n\n\t\t<!-- only needed if wifi localization is used: -->\n <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n", "language": "xml" } ] } [/block] The permissions for ``android.permission.INTERNET`` and ``android.permission.ACCESS_NETWORK_STATE`` are implicitly given by integrating the SDK. If you do not want them because you use the ``forceOffline`` mode you can remove them in your App like this: [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.INTERNET\" tools:node=\"remove\"/>\n<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" tools:node=\"remove\"/>", "language": "xml" } ] } [/block] ## Integrating SDK in code One more thing you have to include 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": "Hosted on Maven Central", "body": "Starting with version 4.8.0 the SDK is deployed on maven central" } [/block] ## Integrating SDK in gradle Please add the ``mavenCentral`` repository 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 mavenCentral()\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}\n\ndef indoorsVersion=\"4.8.0\"\n\ndependencies{ \n compile group: 'com.customlbs.android', name: 'indoors-library-surface', version: indoorsVersion, ext: 'aar', classifier: 'release'\n compile 'com.google.guava:guava:18.0'\n compile 'org.slf4j:slf4j-api:1.7.0'\n}", "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.BLUETOOTH\" />\n <uses-permission android:name=\"android.permission.BLUETOOTH_ADMIN\" /> \n <uses-permission android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n\t\t<!-- or ACCESS_FINE_LOCATION -->\n\n\t\t<!-- only needed if wifi localization is used: -->\n <uses-permission android:name=\"android.permission.ACCESS_WIFI_STATE\" />\n <uses-permission android:name=\"android.permission.CHANGE_WIFI_STATE\" />\n", "language": "xml" } ] } [/block] The permissions for ``android.permission.INTERNET`` and ``android.permission.ACCESS_NETWORK_STATE`` are implicitly given by integrating the SDK. If you do not want them because you use the ``forceOffline`` mode you can remove them in your App like this: [block:code] { "codes": [ { "code": "<uses-permission android:name=\"android.permission.INTERNET\" tools:node=\"remove\"/>\n<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" tools:node=\"remove\"/>", "language": "xml" } ] } [/block] ## Integrating SDK in code One more thing you have to include 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]
{"_id":"59ca4b174bec1e0010fe4b5d","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:32:00.975Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"This is useful if you're working on an app for a remote venue (e.g. a shopping mall, 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]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Changes in 4.6.0\",\n  \"body\": \"Previously the Evaluation mode only emulated a random position.\\nSince version 4.6.0 you have to supply a simulation file that indicates which positions are returned.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"Simulation file\"\n}\n[/block]\nThe simulation file needs to be bundled with the App so the SDK knows which positions to report.\nEvery position consists of the x/y coordinates (in mm from top/left), z which is the floor level, the accuracy (in mm) and a relative timestamp (in ms).\n\nThis file needs to be put in your App's assets folder with a specific name: ``simulation_<BUILDINGID>.json``\n\nFor example if the building ID is 3424:\n``assets/simulation_3424.json``\n\nYou can either create the simulation file manually or use the [Evaluation Tool](https://my.indoo.rs/javadoc/mmt_guide/#MMTToolsOverview) in MMT. We recommend the second option.\n\nThe format is [GeoJson](http://geojson.org/) and you can find an example on the right:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"{\\n  \\\"features\\\": [\\n    {\\n      \\\"geometry\\\": {\\n        \\\"coordinate\\\": [\\n          50827,\\n          17897\\n        ],\\n        \\\"type\\\": \\\"Point\\\"\\n      },\\n      \\\"type\\\": \\\"Feature\\\",\\n      \\\"properties\\\": {\\n        \\\"t\\\": 0,\\n        \\\"accuracy\\\": 3000,\\n        \\\"floor\\\": 0\\n      }\\n    },\\n    {\\n      \\\"geometry\\\": {\\n        \\\"coordinate\\\": [\\n          45989,\\n          17850\\n        ],\\n        \\\"type\\\": \\\"Point\\\"\\n      },\\n      \\\"type\\\": \\\"Feature\\\",\\n      \\\"properties\\\": {\\n        \\\"t\\\": 1912,\\n        \\\"accuracy\\\": 3000,\\n        \\\"floor\\\": 0\\n      }\\n    },\\n    {\\n      \\\"geometry\\\": {\\n        \\\"coordinate\\\": [\\n          45707,\\n          11790\\n        ],\\n        \\\"type\\\": \\\"Point\\\"\\n      },\\n      \\\"type\\\": \\\"Feature\\\",\\n      \\\"properties\\\": {\\n        \\\"t\\\": 5088,\\n        \\\"accuracy\\\": 3000,\\n        \\\"floor\\\": 0\\n      }\\n    }\\n  ],\\n  \\\"type\\\": \\\"FeatureCollection\\\"\\n}\",\n      \"language\": \"json\",\n      \"name\": \"simulation_3424.json\"\n    }\n  ],\n  \"sidebar\": true\n}\n[/block]","excerpt":"","slug":"evaluation-mode","type":"basic","title":"Evaluation Mode","__v":0,"childrenPages":[]}

Evaluation Mode


This is useful if you're working on an app for a remote venue (e.g. a shopping mall, event venue, etc.) but still want to have some position displayed on the map: [block:code] { "codes": [ { "code": "indoorsBuilder.setEvaluationMode(true);", "language": "java" } ] } [/block] [block:callout] { "type": "warning", "title": "Changes in 4.6.0", "body": "Previously the Evaluation mode only emulated a random position.\nSince version 4.6.0 you have to supply a simulation file that indicates which positions are returned." } [/block] [block:api-header] { "title": "Simulation file" } [/block] The simulation file needs to be bundled with the App so the SDK knows which positions to report. Every position consists of the x/y coordinates (in mm from top/left), z which is the floor level, the accuracy (in mm) and a relative timestamp (in ms). This file needs to be put in your App's assets folder with a specific name: ``simulation_<BUILDINGID>.json`` For example if the building ID is 3424: ``assets/simulation_3424.json`` You can either create the simulation file manually or use the [Evaluation Tool](https://my.indoo.rs/javadoc/mmt_guide/#MMTToolsOverview) in MMT. We recommend the second option. The format is [GeoJson](http://geojson.org/) and you can find an example on the right: [block:code] { "codes": [ { "code": "{\n \"features\": [\n {\n \"geometry\": {\n \"coordinate\": [\n 50827,\n 17897\n ],\n \"type\": \"Point\"\n },\n \"type\": \"Feature\",\n \"properties\": {\n \"t\": 0,\n \"accuracy\": 3000,\n \"floor\": 0\n }\n },\n {\n \"geometry\": {\n \"coordinate\": [\n 45989,\n 17850\n ],\n \"type\": \"Point\"\n },\n \"type\": \"Feature\",\n \"properties\": {\n \"t\": 1912,\n \"accuracy\": 3000,\n \"floor\": 0\n }\n },\n {\n \"geometry\": {\n \"coordinate\": [\n 45707,\n 11790\n ],\n \"type\": \"Point\"\n },\n \"type\": \"Feature\",\n \"properties\": {\n \"t\": 5088,\n \"accuracy\": 3000,\n \"floor\": 0\n }\n }\n ],\n \"type\": \"FeatureCollection\"\n}", "language": "json", "name": "simulation_3424.json" } ], "sidebar": true } [/block]
This is useful if you're working on an app for a remote venue (e.g. a shopping mall, event venue, etc.) but still want to have some position displayed on the map: [block:code] { "codes": [ { "code": "indoorsBuilder.setEvaluationMode(true);", "language": "java" } ] } [/block] [block:callout] { "type": "warning", "title": "Changes in 4.6.0", "body": "Previously the Evaluation mode only emulated a random position.\nSince version 4.6.0 you have to supply a simulation file that indicates which positions are returned." } [/block] [block:api-header] { "title": "Simulation file" } [/block] The simulation file needs to be bundled with the App so the SDK knows which positions to report. Every position consists of the x/y coordinates (in mm from top/left), z which is the floor level, the accuracy (in mm) and a relative timestamp (in ms). This file needs to be put in your App's assets folder with a specific name: ``simulation_<BUILDINGID>.json`` For example if the building ID is 3424: ``assets/simulation_3424.json`` You can either create the simulation file manually or use the [Evaluation Tool](https://my.indoo.rs/javadoc/mmt_guide/#MMTToolsOverview) in MMT. We recommend the second option. The format is [GeoJson](http://geojson.org/) and you can find an example on the right: [block:code] { "codes": [ { "code": "{\n \"features\": [\n {\n \"geometry\": {\n \"coordinate\": [\n 50827,\n 17897\n ],\n \"type\": \"Point\"\n },\n \"type\": \"Feature\",\n \"properties\": {\n \"t\": 0,\n \"accuracy\": 3000,\n \"floor\": 0\n }\n },\n {\n \"geometry\": {\n \"coordinate\": [\n 45989,\n 17850\n ],\n \"type\": \"Point\"\n },\n \"type\": \"Feature\",\n \"properties\": {\n \"t\": 1912,\n \"accuracy\": 3000,\n \"floor\": 0\n }\n },\n {\n \"geometry\": {\n \"coordinate\": [\n 45707,\n 11790\n ],\n \"type\": \"Point\"\n },\n \"type\": \"Feature\",\n \"properties\": {\n \"t\": 5088,\n \"accuracy\": 3000,\n \"floor\": 0\n }\n }\n ],\n \"type\": \"FeatureCollection\"\n}", "language": "json", "name": "simulation_3424.json" } ], "sidebar": true } [/block]
{"_id":"59ca4b174bec1e0010fe4b5e","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:33:35.578Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":4,"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 are 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 distance from 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, just call the same method you used to display it with a null value:\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]","excerpt":"","slug":"routing","type":"basic","title":"Routing","__v":0,"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 are 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 distance from 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, just call the same method you used to display it with a null value: [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 are 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 distance from 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, just call the same method you used to display it with a null value: [block:code] { "codes": [ { "code": "void cancelRoute(){\n indoorsFragment.getSurfaceState().setRoutingPath(null);\n indoorsFragment.updateSurface();\n}", "language": "java" } ] } [/block]
{"_id":"59ca4b174bec1e0010fe4b5f","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-28T14:19:00.302Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"## Path Snapping for routing\nAs described in section [Routing], it is possible to enable path snapping .For further control you can also set the threshold (maximum distance) for snapping.\nAfter connecting to the indoors service you can use the following sdk methods:\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 connecting to the indoors service (e.g. in the buildingLoaded method), you can use the following sdk methods:\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]","excerpt":"","slug":"path-snapping-1","type":"basic","title":"Path Snapping","__v":0,"childrenPages":[]}

Path Snapping


## Path Snapping for routing As described in section [Routing], it is possible to enable path snapping .For further control you can also set the threshold (maximum distance) for snapping. After connecting 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 connecting to the indoors service (e.g. in the buildingLoaded method), 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 you can also set the threshold (maximum distance) for snapping. After connecting 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 connecting to the indoors service (e.g. in the buildingLoaded method), 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]
{"_id":"59ca4b174bec1e0010fe4b60","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-01-22T09:37:51.544Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","language":"json","status":200,"name":""},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"Dot on Rails feature can enhance user experience of the dot movement, when enabled. The dot will stay on the predefined path, and will not jump through walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif) you can see how this actually works.\n\n### Enabling/Disabling Dot on Rails:\nDot on rails is enabled by default. We recommend to also ***enable [Path Snapping](doc:path-snapping-1)*** and create predrawn paths which makes the animation look better.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"....\\nIndoorsSurfaceFactory.Builder surfaceBuilder = new indoorsSurfaceFactory.Builder()  \\t\\t\\t\\nsurfaceBuilder.setDotOnRailsEnabled(false);\\n....\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n### Jumping Distance:\nLike path snapping, Dot on Rails feature has its 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]","excerpt":"","slug":"dot-on-rails-1","type":"basic","title":"Dot on rails","__v":0,"childrenPages":[]}

Dot on rails


Dot on Rails feature can enhance user experience of the dot movement, when enabled. The dot will stay on the predefined path, and will not jump through walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif) you can see how this actually works. ### Enabling/Disabling Dot on Rails: Dot on rails is enabled by default. We recommend to also ***enable [Path Snapping](doc:path-snapping-1)*** and create predrawn paths which makes the animation look better. [block:code] { "codes": [ { "code": "....\nIndoorsSurfaceFactory.Builder surfaceBuilder = new indoorsSurfaceFactory.Builder() \t\t\t\nsurfaceBuilder.setDotOnRailsEnabled(false);\n....", "language": "java" } ] } [/block] ### Jumping Distance: Like path snapping, Dot on Rails feature has its 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 feature can enhance user experience of the dot movement, when enabled. The dot will stay on the predefined path, and will not jump through walls. [Here](http://indoo.rs/wp-content/uploads/2016/01/dotOnRails.gif) you can see how this actually works. ### Enabling/Disabling Dot on Rails: Dot on rails is enabled by default. We recommend to also ***enable [Path Snapping](doc:path-snapping-1)*** and create predrawn paths which makes the animation look better. [block:code] { "codes": [ { "code": "....\nIndoorsSurfaceFactory.Builder surfaceBuilder = new indoorsSurfaceFactory.Builder() \t\t\t\nsurfaceBuilder.setDotOnRailsEnabled(false);\n....", "language": "java" } ] } [/block] ### Jumping Distance: Like path snapping, Dot on Rails feature has its 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]
{"_id":"59ca4b174bec1e0010fe4b61","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":["57895460f55bf80e00d0c2e1"],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:44:50.368Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":7,"body":"You can use zones for identification of rooms, shops, or more generally, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, 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 users to the zone they select.\n\nYou can get the zones from the Indoors class:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().getZones(building, new ZoneCallback() {\\n\\t@Override\\n\\tpublic void setZones(ArrayList<Zone> zones) {\\n\\t}\\n});\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"zones","type":"basic","title":"Zones","__v":0,"childrenPages":[]}

Zones


You can use zones for identification of rooms, shops, or more generally, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route users to the zone they select. You can get the zones from the Indoors class: [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().getZones(building, new ZoneCallback() {\n\t@Override\n\tpublic void setZones(ArrayList<Zone> zones) {\n\t}\n});", "language": "java" } ] } [/block]
You can use zones for identification of rooms, shops, or more generally, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route users to the zone they select. You can get the zones from the Indoors class: [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().getZones(building, new ZoneCallback() {\n\t@Override\n\tpublic void setZones(ArrayList<Zone> zones) {\n\t}\n});", "language": "java" } ] } [/block]
{"_id":"59ca4b174bec1e0010fe4b62","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:35:57.884Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":"","settings":""},"isReference":false,"order":8,"body":"Depending on your specific use case, the user might only be interested to know in which room / shop he is currently located. If that is 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 use case might require you to simply show all available zones: \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 shown 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]","excerpt":"","slug":"styling","type":"basic","title":"Styling","__v":0,"childrenPages":[]}

Styling


Depending on your specific use case, the user might only be interested to know in which room / shop he is currently located. If that is 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 use case might require you to simply show all available zones: [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 shown 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 use case, the user might only be interested to know in which room / shop he is currently located. If that is 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 use case might require you to simply show all available zones: [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 shown 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]
{"_id":"59ca4b174bec1e0010fe4b63","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-09-07T07:12:11.777Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"auth":"required","params":[],"url":""},"isReference":false,"order":9,"body":"Allow users of your app to interact with the map by registering a click listener:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsSurfaceFragment.registerOnSurfaceClickListener(this);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nMake sure to implement the **IndoorsSurface.OnSurfaceClickListener** interface.","excerpt":"","slug":"reacting-to-clicks","type":"basic","title":"Reacting to clicks","__v":0,"childrenPages":[]}

Reacting to clicks


Allow users of your app to interact with the map by registering a click listener: [block:code] { "codes": [ { "code": "indoorsSurfaceFragment.registerOnSurfaceClickListener(this);", "language": "java" } ] } [/block] Make sure to implement the **IndoorsSurface.OnSurfaceClickListener** interface.
Allow users of your app to interact with the map by registering a click listener: [block:code] { "codes": [ { "code": "indoorsSurfaceFragment.registerOnSurfaceClickListener(this);", "language": "java" } ] } [/block] Make sure to implement the **IndoorsSurface.OnSurfaceClickListener** interface.
{"_id":"59ca4b174bec1e0010fe4b64","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:46:57.060Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"isReference":false,"order":10,"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]","excerpt":"","slug":"overlays","type":"basic","title":"Overlays","__v":0,"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]
{"_id":"59ca4b174bec1e0010fe4b65","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:50:37.313Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":11,"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 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). 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]","excerpt":"","slug":"map-with-app","type":"basic","title":"Map with App","__v":0,"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 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). 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 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). 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]
{"_id":"59ca4b174bec1e0010fe4b66","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:51:38.690Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":12,"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(), true);\\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.","excerpt":"","slug":"localisation-without-ui","type":"basic","title":"Localization without UI","__v":0,"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(), true);\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(), true);\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.
{"_id":"59ca4b174bec1e0010fe4b67","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:53:42.505Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":"","settings":""},"isReference":false,"order":13,"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 * you set no / a wrong rotation for your building in the MMT!","excerpt":"","slug":"gps-coordinates","type":"basic","title":"GPS Coordinates","__v":0,"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 * 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 * you set no / a wrong rotation for your building in the MMT!
{"_id":"59ca4b174bec1e0010fe4b68","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T08:56:56.562Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"code":"{}","name":"","status":400,"language":"json"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":14,"body":"Android allows you to run your service in the foreground if needed, this will add a notification icon in your status bar with your ticker text. Our SDK allows you to enable or disable this using the method **setForegroundService**\n\nPlease visit the [Android Guidelines](http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29) for more information what a foreground service does exactly.\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]","excerpt":"","slug":"enabledisable-foreground-service","type":"basic","title":"Enable/Disable Foreground Service","__v":0,"childrenPages":[]}

Enable/Disable Foreground Service


Android allows you to run your service in the foreground if needed, this will add a notification icon in your status bar with your ticker text. Our SDK allows you to enable or disable this using the method **setForegroundService** Please visit the [Android Guidelines](http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29) for more information what a foreground service does exactly. [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 add a notification icon in your status bar with your ticker text. Our SDK allows you to enable or disable this using the method **setForegroundService** Please visit the [Android Guidelines](http://developer.android.com/reference/android/app/Service.html#startForeground%28int,%20android.app.Notification%29) for more information what a foreground service does exactly. [block:code] { "codes": [ { "code": "\t\tindoors = IndoorsFactory.getInstance();\n\t\tindoors.setForegroundService(true, \"your ticker text\"));", "language": "java" } ] } [/block]
{"_id":"59ca4b174bec1e0010fe4b69","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-07-02T11:38:45.472Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"isReference":false,"order":15,"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 android:name=\\\"android.permission.ACCESS_COARSE_LOCATION\\\"/>\\n<!-- or ACCESS_FINE_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 is needed to scan for iBeacons, 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 localization.\n\n### ACCESS_COARSE_LOCATION (REQUIRED FOR Target API 21):\nGenerally used to access GPS. Our SDK requires this in case if GPS parameters settings in MMT is enabled (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 21 or above, it is required to have ACCESS_FINE_LOCATION 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 it is not needed anymore.\"\n}\n[/block]","excerpt":"","slug":"indoors-sdk-manifest-permissions","type":"basic","title":"Indoors SDK Manifest Permissions","__v":0,"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 android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n<!-- or ACCESS_FINE_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 is needed to scan for iBeacons, 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 localization. ### ACCESS_COARSE_LOCATION (REQUIRED FOR Target API 21): Generally used to access GPS. Our SDK requires this in case if GPS parameters settings in MMT is enabled (please take a look at our MMT guide for more information). [block:callout] { "type": "warning", "body": "If you are targeting API 21 or above, it is required to have ACCESS_FINE_LOCATION 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 it is not needed 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 android:name=\"android.permission.ACCESS_COARSE_LOCATION\"/>\n<!-- or ACCESS_FINE_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 is needed to scan for iBeacons, 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 localization. ### ACCESS_COARSE_LOCATION (REQUIRED FOR Target API 21): Generally used to access GPS. Our SDK requires this in case if GPS parameters settings in MMT is enabled (please take a look at our MMT guide for more information). [block:callout] { "type": "warning", "body": "If you are targeting API 21 or above, it is required to have ACCESS_FINE_LOCATION 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 it is not needed anymore." } [/block]
{"_id":"59ca4b174bec1e0010fe4b6a","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-06-06T16:46:54.831Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"code":"{}","language":"json","status":400,"name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":16,"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\": \"It is not enough to just have the permission for Location access - the location services must also 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 is 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 take a look at the sample app [which you can find in the Downloads and Documentation section on my.indoo.rs](https://my.indoo.rs/#/tools)","excerpt":"for Android 6, API 23, Marshmallow","slug":"runtime-permissions","type":"basic","title":"Runtime Permissions","__v":0,"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": "It is not enough to just have the permission for Location access - the location services must also 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 is 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 take a look at 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": "It is not enough to just have the permission for Location access - the location services must also 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 is 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 take a look at the sample app [which you can find in the Downloads and Documentation section on my.indoo.rs](https://my.indoo.rs/#/tools)
{"_id":"59ca4b174bec1e0010fe4b6b","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-07-14T17:21:36.504Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":17,"body":"This is useful in case you do not want to start localization, but you want to show the Indoors Fragment. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"indoorsBuilder.setRunLocalization(false);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nBy calling **setRunLocalization** method with **false** parameter 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\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 localization 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##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 Localization\"\n}\n[/block]","excerpt":"This section describes the usage of Indoors Fragment without starting localization","slug":"ui-without-localisation","type":"basic","title":"UI Without Localization","__v":0,"childrenPages":[]}

UI Without Localization

This section describes the usage of Indoors Fragment without starting localization

This is useful in case you do not want to start localization, but you want to show the Indoors Fragment. [block:code] { "codes": [ { "code": "indoorsBuilder.setRunLocalization(false);", "language": "java" } ] } [/block] By calling **setRunLocalization** method with **false** parameter 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 localization 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 Localization" } [/block]
This is useful in case you do not want to start localization, but you want to show the Indoors Fragment. [block:code] { "codes": [ { "code": "indoorsBuilder.setRunLocalization(false);", "language": "java" } ] } [/block] By calling **setRunLocalization** method with **false** parameter 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 localization 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 Localization" } [/block]
{"_id":"59ca4b174bec1e0010fe4b6d","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-09T12:22:37.468Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":19,"body":"In some cases you may 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]","excerpt":"","slug":"get-and-set-visible-map-area-android","type":"basic","title":"Get and set visible map area","__v":0,"childrenPages":[]}

Get and set visible map area


In some cases you may 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 cases you may 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]
{"_id":"59ca4b174bec1e0010fe4b6e","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-11T13:56:40.040Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"name":"","status":400,"language":"json","code":"{}"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":20,"body":"If you want to know whether 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      \"language\": \"java\"\n    },\n    {\n      \"code\": \"\",\n      \"language\": \"text\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"user-interaction-callback","type":"basic","title":"User interaction Callback","__v":0,"childrenPages":[]}

User interaction Callback


If you want to know whether 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});", "language": "java" }, { "code": "", "language": "text" } ] } [/block]
If you want to know whether 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});", "language": "java" }, { "code": "", "language": "text" } ] } [/block]
{"_id":"59ca4b174bec1e0010fe4b6f","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-14T10:22:54.546Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":21,"body":"[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"1. SDK current Version\"\n}\n[/block]\nTo get the current SDK version, after connecting to indoors service, you can call  ***\"getCurrentVersion\"***, the method returns a string.\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]","excerpt":"","slug":"sdk-version","type":"basic","title":"SDK Version","__v":0,"childrenPages":[]}

SDK Version


[block:api-header] { "type": "basic", "title": "1. SDK current Version" } [/block] To get the current SDK version, after connecting to indoors service, you can call ***"getCurrentVersion"***, the method returns a string. [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 current SDK version, after connecting to indoors service, you can call ***"getCurrentVersion"***, the method returns a string. [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]
{"_id":"59ca4b174bec1e0010fe4b70","category":"59ca4b164bec1e0010fe4b39","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-02-12T10:55:48.211Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"status":400,"name":"","code":"{}","language":"json"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":22,"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)","excerpt":"","slug":"building-download","type":"basic","title":"Building Download","__v":0,"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)
{"_id":"59ca4b174bec1e0010fe4b71","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-11-03T14:19:54.685Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":23,"body":"If you need to customize the background color around the map in the IndoorsSurface, you can set it with the following lines of code. This 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]","excerpt":"","slug":"changing-the-background-color-of-the-map","type":"basic","title":"Changing the background color of the map","__v":0,"childrenPages":[]}

Changing the background color of the map


If you need to customize the background color around the map in the IndoorsSurface, you can set it with the following lines of code. This 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 need to customize the background color around the map in the IndoorsSurface, you can set it with the following lines of code. This 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]
{"_id":"59ca4b174bec1e0010fe4b73","category":"59ca4b164bec1e0010fe4b39","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-03-24T17:21:42.922Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","language":"json","status":200,"name":""},{"language":"json","status":400,"name":"","code":"{}"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":25,"body":"The **Kalman filter** is used to improve localization 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 **Stabilization 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 stabilization filter to kick in. The minimum value is 4000 ms, maximum is 20000 ms.\nBecause for some venues the Stabilization filter doesn't yield the best results it is disabled by default and can be enabled on demand.\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(true);\\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 filter is **enabled** and the Stabilization filter is **disabled**.\"\n}\n[/block]\nSince version 4.8.0, we have introduced a new setting to improve the localization stability. If you exprience localization \"jumps\", you can set a limit on the distance between two position updates. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().setSmallJumpDistance(2.0);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIn this example the distance is set to 2 meters. By default it is unlimited, setting a limit is purely optional.\nIn case if there are areas in your building where radio signal is unstable and the blue dot sometimes gets stuck, you should allow it to catch up in bigger jumps:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().setBigJumpDistance(5.0);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIf you never experience the dot being stuck, you can set the big jump value to the same one as small jump. However, keep in mind that you either have to set both distances, or none (in this case the additional stability feature is disabled). Both settings should be applied inside _connected()_ method of IndoorsServiceCallback.\n\nIf you limit the jump distance, we also recommend to disable *dotOnRails* feature, especially in cases when your building has small rooms.","excerpt":"This section describes how to configure the localization parameters for stabilization filter and kalman filter in indoors.","slug":"using-stabilization-filter-and-kalman-filter","type":"basic","title":"Using Kalman and Stabilization Filter","__v":0,"childrenPages":[]}

Using Kalman and Stabilization 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 localization 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 **Stabilization 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 stabilization filter to kick in. The minimum value is 4000 ms, maximum is 20000 ms. Because for some venues the Stabilization filter doesn't yield the best results it is disabled by default and can be enabled on demand. 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(true);\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 filter is **enabled** and the Stabilization filter is **disabled**." } [/block] Since version 4.8.0, we have introduced a new setting to improve the localization stability. If you exprience localization "jumps", you can set a limit on the distance between two position updates. [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setSmallJumpDistance(2.0);", "language": "java" } ] } [/block] In this example the distance is set to 2 meters. By default it is unlimited, setting a limit is purely optional. In case if there are areas in your building where radio signal is unstable and the blue dot sometimes gets stuck, you should allow it to catch up in bigger jumps: [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setBigJumpDistance(5.0);", "language": "java" } ] } [/block] If you never experience the dot being stuck, you can set the big jump value to the same one as small jump. However, keep in mind that you either have to set both distances, or none (in this case the additional stability feature is disabled). Both settings should be applied inside _connected()_ method of IndoorsServiceCallback. If you limit the jump distance, we also recommend to disable *dotOnRails* feature, especially in cases when your building has small rooms.
The **Kalman filter** is used to improve localization 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 **Stabilization 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 stabilization filter to kick in. The minimum value is 4000 ms, maximum is 20000 ms. Because for some venues the Stabilization filter doesn't yield the best results it is disabled by default and can be enabled on demand. 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(true);\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 filter is **enabled** and the Stabilization filter is **disabled**." } [/block] Since version 4.8.0, we have introduced a new setting to improve the localization stability. If you exprience localization "jumps", you can set a limit on the distance between two position updates. [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setSmallJumpDistance(2.0);", "language": "java" } ] } [/block] In this example the distance is set to 2 meters. By default it is unlimited, setting a limit is purely optional. In case if there are areas in your building where radio signal is unstable and the blue dot sometimes gets stuck, you should allow it to catch up in bigger jumps: [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setBigJumpDistance(5.0);", "language": "java" } ] } [/block] If you never experience the dot being stuck, you can set the big jump value to the same one as small jump. However, keep in mind that you either have to set both distances, or none (in this case the additional stability feature is disabled). Both settings should be applied inside _connected()_ method of IndoorsServiceCallback. If you limit the jump distance, we also recommend to disable *dotOnRails* feature, especially in cases when your building has small rooms.
{"_id":"59ca539268585a00103f4c44","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-09-26T13:18:10.364Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":26,"body":"General idea: you need a service that runs in foreground and therefore does not get killed by the system. This service constantly receives position updates from the SDK. Visualization is done independently in an activity.\n\nPlease refer also to sections “[Localization without UI](https://indoors.readme.io/docs/localisation-without-ui)” and “[UI without localization](https://indoors.readme.io/docs/ui-without-localisation)” for the service and activity setup, respectively.\n[block:api-header]\n{\n  \"title\": \"Activity\"\n}\n[/block]\nMake sure you have user permission to access location and since Android Marshmallow – that the location is enabled on the phone. If you are not using *IndoorsSurfaceFragment* for visualization, skip to the “Service” paragraph.\n\nIn *onCreate* of the activity start the service:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Intent startIntent = new Intent(MainActivity.this, ForegroundLocationService.class);\\nstartIntent.setAction(Constants.ACTION.START_FOREGROUND_ACTION);\\nstartService(startIntent);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nInitialize SDK as usual and create IndoorsSurfaceFragment if you are using it for visualization.\n\nCreate a ServiceConnection:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"private ServiceConnection serviceConnection = new ServiceConnection() {\\n  @Override\\n  public void onServiceConnected(ComponentName className, IBinder service) {\\n    bound = true;\\n  }\\n\\n  @Override\\n  public void onServiceDisconnected(ComponentName arg0) {\\n    bound = false;\\n  }\\n};\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nOnce the service is created, bind to it *onStart* of the activity\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"Intent intent = new Intent(MainActivity.this, ForegroundLocationService.class);\\nbindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);\\nbound = true;\\t\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nand unbind *onStop*\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"if (bound) {\\n\\tunbindService(serviceConnection);\\n\\tbound = false;\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"Service\"\n}\n[/block]\nThe service should implement *IndoorsServiceCallback* and *IndoorsLocationListener*.\nMake sure the CPU stays awake for constant position calculation in *onCreate*:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"PowerManager powerManager = (PowerManager) getApplicationContext().getSystemService(POWER_SERVICE);\\nPowerManager.WakeLock wakeLock = \\tpowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \\\"TAG\\\");\\nwakeLock.acquire();\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nInitialize the SDK:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.createInstance(this, \\\"your-api-key\\\", this, false);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nWhen the SDK was successfully initialized:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void connected() {\\n    indoors = IndoorsFactory.getInstance();\\n    indoors.registerLocationListener(this);\\n    boolean startLocating = true;\\n    indoors.setLocatedCloudBuilding(buildingId, new LocalizationParameters(), startLocating);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nAdditionally, in the same method you may introduce battery saving options (described in chapter \"[Battery saving options](https://indoors.readme.io/docs/battery-saving-options)\").\n\nWhen you run a service in foreground, you are obliged to show a notification to the user. Here is how to start the service:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic int onStartCommand(Intent intent, int flags, int startId) {\\n    // important - the string should be the same as in your activity when you start the service\\n    if (intent.getAction().equals(\\\"your string to start action\\\") ) {\\n        // parameters - your id and a notification you created\\n        startForeground(101, notification);\\n    } else if (intent.getAction().equals(\\\"your string to stop service\\\")) {\\n        stopForeground(true);\\n        stopSelf();\\n    }\\n    return START_STICKY;\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nNote: you may add an intent to stop service to the notification itself.\n\nMake sure to shut down the SDK when your service stops:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"@Override\\npublic void onDestroy() {\\n    indoors.removeLocationListener(this);\\n    IndoorsFactory.releaseInstance(this);\\n}\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nIf you wish to do something with the position coordinates (e.g. send them to your server), you can do it in *positionUpdated* method of *IndoorsLocationListener* (you need to implement it).","excerpt":"","slug":"constant-localization-without-a-running-app","type":"basic","title":"Constant localization without a running app","__v":0,"parentDoc":null,"childrenPages":[]}

Constant localization without a running app


General idea: you need a service that runs in foreground and therefore does not get killed by the system. This service constantly receives position updates from the SDK. Visualization is done independently in an activity. Please refer also to sections “[Localization without UI](https://indoors.readme.io/docs/localisation-without-ui)” and “[UI without localization](https://indoors.readme.io/docs/ui-without-localisation)” for the service and activity setup, respectively. [block:api-header] { "title": "Activity" } [/block] Make sure you have user permission to access location and since Android Marshmallow – that the location is enabled on the phone. If you are not using *IndoorsSurfaceFragment* for visualization, skip to the “Service” paragraph. In *onCreate* of the activity start the service: [block:code] { "codes": [ { "code": "Intent startIntent = new Intent(MainActivity.this, ForegroundLocationService.class);\nstartIntent.setAction(Constants.ACTION.START_FOREGROUND_ACTION);\nstartService(startIntent);", "language": "java" } ] } [/block] Initialize SDK as usual and create IndoorsSurfaceFragment if you are using it for visualization. Create a ServiceConnection: [block:code] { "codes": [ { "code": "private ServiceConnection serviceConnection = new ServiceConnection() {\n @Override\n public void onServiceConnected(ComponentName className, IBinder service) {\n bound = true;\n }\n\n @Override\n public void onServiceDisconnected(ComponentName arg0) {\n bound = false;\n }\n};", "language": "java" } ] } [/block] Once the service is created, bind to it *onStart* of the activity [block:code] { "codes": [ { "code": "Intent intent = new Intent(MainActivity.this, ForegroundLocationService.class);\nbindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);\nbound = true;\t", "language": "java" } ] } [/block] and unbind *onStop* [block:code] { "codes": [ { "code": "if (bound) {\n\tunbindService(serviceConnection);\n\tbound = false;\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "Service" } [/block] The service should implement *IndoorsServiceCallback* and *IndoorsLocationListener*. Make sure the CPU stays awake for constant position calculation in *onCreate*: [block:code] { "codes": [ { "code": "PowerManager powerManager = (PowerManager) getApplicationContext().getSystemService(POWER_SERVICE);\nPowerManager.WakeLock wakeLock = \tpowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"TAG\");\nwakeLock.acquire();", "language": "java" } ] } [/block] Initialize the SDK: [block:code] { "codes": [ { "code": "IndoorsFactory.createInstance(this, \"your-api-key\", this, false);", "language": "java" } ] } [/block] When the SDK was successfully initialized: [block:code] { "codes": [ { "code": "@Override\npublic void connected() {\n indoors = IndoorsFactory.getInstance();\n indoors.registerLocationListener(this);\n boolean startLocating = true;\n indoors.setLocatedCloudBuilding(buildingId, new LocalizationParameters(), startLocating);\n}", "language": "java" } ] } [/block] Additionally, in the same method you may introduce battery saving options (described in chapter "[Battery saving options](https://indoors.readme.io/docs/battery-saving-options)"). When you run a service in foreground, you are obliged to show a notification to the user. Here is how to start the service: [block:code] { "codes": [ { "code": "@Override\npublic int onStartCommand(Intent intent, int flags, int startId) {\n // important - the string should be the same as in your activity when you start the service\n if (intent.getAction().equals(\"your string to start action\") ) {\n // parameters - your id and a notification you created\n startForeground(101, notification);\n } else if (intent.getAction().equals(\"your string to stop service\")) {\n stopForeground(true);\n stopSelf();\n }\n return START_STICKY;\n}", "language": "java" } ] } [/block] Note: you may add an intent to stop service to the notification itself. Make sure to shut down the SDK when your service stops: [block:code] { "codes": [ { "code": "@Override\npublic void onDestroy() {\n indoors.removeLocationListener(this);\n IndoorsFactory.releaseInstance(this);\n}", "language": "java" } ] } [/block] If you wish to do something with the position coordinates (e.g. send them to your server), you can do it in *positionUpdated* method of *IndoorsLocationListener* (you need to implement it).
General idea: you need a service that runs in foreground and therefore does not get killed by the system. This service constantly receives position updates from the SDK. Visualization is done independently in an activity. Please refer also to sections “[Localization without UI](https://indoors.readme.io/docs/localisation-without-ui)” and “[UI without localization](https://indoors.readme.io/docs/ui-without-localisation)” for the service and activity setup, respectively. [block:api-header] { "title": "Activity" } [/block] Make sure you have user permission to access location and since Android Marshmallow – that the location is enabled on the phone. If you are not using *IndoorsSurfaceFragment* for visualization, skip to the “Service” paragraph. In *onCreate* of the activity start the service: [block:code] { "codes": [ { "code": "Intent startIntent = new Intent(MainActivity.this, ForegroundLocationService.class);\nstartIntent.setAction(Constants.ACTION.START_FOREGROUND_ACTION);\nstartService(startIntent);", "language": "java" } ] } [/block] Initialize SDK as usual and create IndoorsSurfaceFragment if you are using it for visualization. Create a ServiceConnection: [block:code] { "codes": [ { "code": "private ServiceConnection serviceConnection = new ServiceConnection() {\n @Override\n public void onServiceConnected(ComponentName className, IBinder service) {\n bound = true;\n }\n\n @Override\n public void onServiceDisconnected(ComponentName arg0) {\n bound = false;\n }\n};", "language": "java" } ] } [/block] Once the service is created, bind to it *onStart* of the activity [block:code] { "codes": [ { "code": "Intent intent = new Intent(MainActivity.this, ForegroundLocationService.class);\nbindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);\nbound = true;\t", "language": "java" } ] } [/block] and unbind *onStop* [block:code] { "codes": [ { "code": "if (bound) {\n\tunbindService(serviceConnection);\n\tbound = false;\n}", "language": "java" } ] } [/block] [block:api-header] { "title": "Service" } [/block] The service should implement *IndoorsServiceCallback* and *IndoorsLocationListener*. Make sure the CPU stays awake for constant position calculation in *onCreate*: [block:code] { "codes": [ { "code": "PowerManager powerManager = (PowerManager) getApplicationContext().getSystemService(POWER_SERVICE);\nPowerManager.WakeLock wakeLock = \tpowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"TAG\");\nwakeLock.acquire();", "language": "java" } ] } [/block] Initialize the SDK: [block:code] { "codes": [ { "code": "IndoorsFactory.createInstance(this, \"your-api-key\", this, false);", "language": "java" } ] } [/block] When the SDK was successfully initialized: [block:code] { "codes": [ { "code": "@Override\npublic void connected() {\n indoors = IndoorsFactory.getInstance();\n indoors.registerLocationListener(this);\n boolean startLocating = true;\n indoors.setLocatedCloudBuilding(buildingId, new LocalizationParameters(), startLocating);\n}", "language": "java" } ] } [/block] Additionally, in the same method you may introduce battery saving options (described in chapter "[Battery saving options](https://indoors.readme.io/docs/battery-saving-options)"). When you run a service in foreground, you are obliged to show a notification to the user. Here is how to start the service: [block:code] { "codes": [ { "code": "@Override\npublic int onStartCommand(Intent intent, int flags, int startId) {\n // important - the string should be the same as in your activity when you start the service\n if (intent.getAction().equals(\"your string to start action\") ) {\n // parameters - your id and a notification you created\n startForeground(101, notification);\n } else if (intent.getAction().equals(\"your string to stop service\")) {\n stopForeground(true);\n stopSelf();\n }\n return START_STICKY;\n}", "language": "java" } ] } [/block] Note: you may add an intent to stop service to the notification itself. Make sure to shut down the SDK when your service stops: [block:code] { "codes": [ { "code": "@Override\npublic void onDestroy() {\n indoors.removeLocationListener(this);\n IndoorsFactory.releaseInstance(this);\n}", "language": "java" } ] } [/block] If you wish to do something with the position coordinates (e.g. send them to your server), you can do it in *positionUpdated* method of *IndoorsLocationListener* (you need to implement it).
{"_id":"59ca54944bec1e0010fe6207","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","category":"59ca4b164bec1e0010fe4b39","user":"54e5a4a0d3ab670d00f3af54","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-09-26T13:22:28.715Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":27,"body":"Since bluetooth scanning and position calculation can be quite energy demanding when used for a long time (hours), three methods were introduced in version 4.8.0 to improve battery lifetime. \n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"However, be aware that all of them come with the price of less accuracy - so only use them if you really have to! In most cases (unless your app is supposed to run the whole day, for example) you should not modify these settings.\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"The following methods have to be called inside _connected()_ method of IndoorsServiceCallback to make sure they are applied before a building is loaded.\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().useSensors(boolean);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nAllows to disable phone sensors usage (like magnetic and gyroscope). Sensors are enabled by default (*boolean = true*).\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().setBluetoothScanningMode(int);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nPossible values:  *ScanSettings.SCAN_MODE_LOW_LATENCY*,  *ScanSettings.SCAN_MODE_BALANCED*,  *ScanSettings.SCAN_MODE_LOW_POWER*.\nDefault value - *ScanSettings.SCAN_MODE_LOW_LATENCY* which assures the highest accuracy.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"IndoorsFactory.getInstance().setDutyCycle(int);\",\n      \"language\": \"java\"\n    }\n  ]\n}\n[/block]\nThis defines how often the position is calculated in milliseconds, default value is 100.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"TO BE USED WITH EXTREME CARE!\"\n}\n[/block]\nMay save a lot of battery, but will result in latency for position updates. E.g., setting the value to 5000 means that the position is calculated only every 5 seconds.","excerpt":"","slug":"battery-saving-options","type":"basic","title":"Battery saving options","__v":0,"parentDoc":null,"childrenPages":[]}

Battery saving options


Since bluetooth scanning and position calculation can be quite energy demanding when used for a long time (hours), three methods were introduced in version 4.8.0 to improve battery lifetime. [block:callout] { "type": "danger", "body": "However, be aware that all of them come with the price of less accuracy - so only use them if you really have to! In most cases (unless your app is supposed to run the whole day, for example) you should not modify these settings." } [/block] [block:callout] { "type": "warning", "body": "The following methods have to be called inside _connected()_ method of IndoorsServiceCallback to make sure they are applied before a building is loaded." } [/block] [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().useSensors(boolean);", "language": "java" } ] } [/block] Allows to disable phone sensors usage (like magnetic and gyroscope). Sensors are enabled by default (*boolean = true*). [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setBluetoothScanningMode(int);", "language": "java" } ] } [/block] Possible values: *ScanSettings.SCAN_MODE_LOW_LATENCY*, *ScanSettings.SCAN_MODE_BALANCED*, *ScanSettings.SCAN_MODE_LOW_POWER*. Default value - *ScanSettings.SCAN_MODE_LOW_LATENCY* which assures the highest accuracy. [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setDutyCycle(int);", "language": "java" } ] } [/block] This defines how often the position is calculated in milliseconds, default value is 100. [block:callout] { "type": "danger", "title": "TO BE USED WITH EXTREME CARE!" } [/block] May save a lot of battery, but will result in latency for position updates. E.g., setting the value to 5000 means that the position is calculated only every 5 seconds.
Since bluetooth scanning and position calculation can be quite energy demanding when used for a long time (hours), three methods were introduced in version 4.8.0 to improve battery lifetime. [block:callout] { "type": "danger", "body": "However, be aware that all of them come with the price of less accuracy - so only use them if you really have to! In most cases (unless your app is supposed to run the whole day, for example) you should not modify these settings." } [/block] [block:callout] { "type": "warning", "body": "The following methods have to be called inside _connected()_ method of IndoorsServiceCallback to make sure they are applied before a building is loaded." } [/block] [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().useSensors(boolean);", "language": "java" } ] } [/block] Allows to disable phone sensors usage (like magnetic and gyroscope). Sensors are enabled by default (*boolean = true*). [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setBluetoothScanningMode(int);", "language": "java" } ] } [/block] Possible values: *ScanSettings.SCAN_MODE_LOW_LATENCY*, *ScanSettings.SCAN_MODE_BALANCED*, *ScanSettings.SCAN_MODE_LOW_POWER*. Default value - *ScanSettings.SCAN_MODE_LOW_LATENCY* which assures the highest accuracy. [block:code] { "codes": [ { "code": "IndoorsFactory.getInstance().setDutyCycle(int);", "language": "java" } ] } [/block] This defines how often the position is calculated in milliseconds, default value is 100. [block:callout] { "type": "danger", "title": "TO BE USED WITH EXTREME CARE!" } [/block] May save a lot of battery, but will result in latency for position updates. E.g., setting the value to 5000 means that the position is calculated only every 5 seconds.
{"_id":"59ca4b174bec1e0010fe4b74","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-25T09:53:22.801Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"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 a 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 following 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]\n\n[block:api-header]\n{\n  \"title\": \"Integrating the SDK into a Swift-Framework\"\n}\n[/block]\nIn order to use the SDK within your own framework written in Swift, download and add \"IndoorsSDK.framework\" to \"Linked Frameworks and Libraries\" in your framework's target.\n[block:image]\n{\n  \"images\": [\n    {\n      \"image\": [\n        \"https://files.readme.io/1849dad-Linked_framework.png\",\n        \"Linked framework.png\",\n        1760,\n        328,\n        \"#dddfde\"\n      ]\n    }\n  ]\n}\n[/block]\nNow open your framework header and add \"@import IndoorsSDK\" to it.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"#import <UIKit/UIKit.h>\\n\\n//! Project version number for MyFramework.\\nFOUNDATION_EXPORT double MyFrameworkVersionNumber;\\n\\n//! Project version string for MyFramework.\\nFOUNDATION_EXPORT const unsigned char MyFrameworkVersionString[];\\n\\n// In this header, you should import all the public headers of your framework using statements like #import <MyFramework/PublicHeader.h>\\n\\n@import IndoorsSDK;\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nIf you would compile now, you would get a \"Module 'IndoorsSDK' not found\" error, because the SDK is delivered as a static library and your project needs some information about the module it represents. Therefore IndoorsSDK.framework contains a modulemap in a subfolder called \"Modules\". Hence, as a last step you need to make your project aware of this modulemap, by adding the path to the SDK's root directory to the project setting \"Swift Compiler - Search Paths\" -> \"Import Paths\". \nIf you put the downloaded framework in your projects root directory, this is what the setting should look like: *$(PROJECT_DIR)/IndoorsSDK.framework/Modules* \n\nNow you can compile your project and start using the SDK in your framework code.","excerpt":"","slug":"getting-started-with-indoors-ios-sdk","type":"basic","title":"Getting Started with indoo.rs SDK","__v":0,"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 a 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 following 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] [block:api-header] { "title": "Integrating the SDK into a Swift-Framework" } [/block] In order to use the SDK within your own framework written in Swift, download and add "IndoorsSDK.framework" to "Linked Frameworks and Libraries" in your framework's target. [block:image] { "images": [ { "image": [ "https://files.readme.io/1849dad-Linked_framework.png", "Linked framework.png", 1760, 328, "#dddfde" ] } ] } [/block] Now open your framework header and add "@import IndoorsSDK" to it. [block:code] { "codes": [ { "code": "#import <UIKit/UIKit.h>\n\n//! Project version number for MyFramework.\nFOUNDATION_EXPORT double MyFrameworkVersionNumber;\n\n//! Project version string for MyFramework.\nFOUNDATION_EXPORT const unsigned char MyFrameworkVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <MyFramework/PublicHeader.h>\n\n@import IndoorsSDK;", "language": "objectivec" } ] } [/block] If you would compile now, you would get a "Module 'IndoorsSDK' not found" error, because the SDK is delivered as a static library and your project needs some information about the module it represents. Therefore IndoorsSDK.framework contains a modulemap in a subfolder called "Modules". Hence, as a last step you need to make your project aware of this modulemap, by adding the path to the SDK's root directory to the project setting "Swift Compiler - Search Paths" -> "Import Paths". If you put the downloaded framework in your projects root directory, this is what the setting should look like: *$(PROJECT_DIR)/IndoorsSDK.framework/Modules* Now you can compile your project and start using the SDK in your framework code.
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 a 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 following 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] [block:api-header] { "title": "Integrating the SDK into a Swift-Framework" } [/block] In order to use the SDK within your own framework written in Swift, download and add "IndoorsSDK.framework" to "Linked Frameworks and Libraries" in your framework's target. [block:image] { "images": [ { "image": [ "https://files.readme.io/1849dad-Linked_framework.png", "Linked framework.png", 1760, 328, "#dddfde" ] } ] } [/block] Now open your framework header and add "@import IndoorsSDK" to it. [block:code] { "codes": [ { "code": "#import <UIKit/UIKit.h>\n\n//! Project version number for MyFramework.\nFOUNDATION_EXPORT double MyFrameworkVersionNumber;\n\n//! Project version string for MyFramework.\nFOUNDATION_EXPORT const unsigned char MyFrameworkVersionString[];\n\n// In this header, you should import all the public headers of your framework using statements like #import <MyFramework/PublicHeader.h>\n\n@import IndoorsSDK;", "language": "objectivec" } ] } [/block] If you would compile now, you would get a "Module 'IndoorsSDK' not found" error, because the SDK is delivered as a static library and your project needs some information about the module it represents. Therefore IndoorsSDK.framework contains a modulemap in a subfolder called "Modules". Hence, as a last step you need to make your project aware of this modulemap, by adding the path to the SDK's root directory to the project setting "Swift Compiler - Search Paths" -> "Import Paths". If you put the downloaded framework in your projects root directory, this is what the setting should look like: *$(PROJECT_DIR)/IndoorsSDK.framework/Modules* Now you can compile your project and start using the SDK in your framework code.
{"_id":"59ca4b174bec1e0010fe4b75","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:28:03.319Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","status":200,"language":"json","code":"{}"},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"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.","excerpt":"","slug":"integrating-indoors-into-an-existing-app-1","type":"basic","title":"Load and display your building","__v":0,"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.
{"_id":"59ca4b174bec1e0010fe4b76","category":"59ca4b164bec1e0010fe4b3a","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-07T09:18:40.286Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"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]","excerpt":"","slug":"get-indoors-sdk-version-info","type":"basic","title":"indoo.rs SDK version info","__v":0,"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]
{"_id":"59ca4b174bec1e0010fe4b77","category":"59ca4b164bec1e0010fe4b3a","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:40:28.767Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"This is useful if you are working on an app for a remote venue (e.g. a shopping mall, 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 network is 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]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"Previously the Evaluation mode only emulated a random position.\\nSince version 4.6.0 you have to supply a simulation file which indicates which positions are returned.\",\n  \"title\": \"Changes in 4.6.0\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"title\": \"Simulation file\"\n}\n[/block]\nThe simulation file needs to be bundled with the App as part of the main-bundle so the SDK knows which positions to report.\n\nThis file must have a specific name: **simulation_<BUILDINGID>.json**\n\n*For example if the building ID is 3424*:\n``simulation_3424.json``\n\nYou can either create the simulation file manually or use the [Evaluation Tool](https://my.indoo.rs/javadoc/mmt_guide/#MMTToolsOverview) in MMT. We recommend the second option.\n\nFor more information on the format see the [Android section](doc:evaluation-mode).","excerpt":"","slug":"evaluation-mode-1","type":"basic","title":"Evaluation Mode","__v":0,"childrenPages":[]}

Evaluation Mode


This is useful if you are working on an app for a remote venue (e.g. a shopping mall, 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 network is 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] [block:callout] { "type": "warning", "body": "Previously the Evaluation mode only emulated a random position.\nSince version 4.6.0 you have to supply a simulation file which indicates which positions are returned.", "title": "Changes in 4.6.0" } [/block] [block:api-header] { "title": "Simulation file" } [/block] The simulation file needs to be bundled with the App as part of the main-bundle so the SDK knows which positions to report. This file must have a specific name: **simulation_<BUILDINGID>.json** *For example if the building ID is 3424*: ``simulation_3424.json`` You can either create the simulation file manually or use the [Evaluation Tool](https://my.indoo.rs/javadoc/mmt_guide/#MMTToolsOverview) in MMT. We recommend the second option. For more information on the format see the [Android section](doc:evaluation-mode).
This is useful if you are working on an app for a remote venue (e.g. a shopping mall, 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 network is 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] [block:callout] { "type": "warning", "body": "Previously the Evaluation mode only emulated a random position.\nSince version 4.6.0 you have to supply a simulation file which indicates which positions are returned.", "title": "Changes in 4.6.0" } [/block] [block:api-header] { "title": "Simulation file" } [/block] The simulation file needs to be bundled with the App as part of the main-bundle so the SDK knows which positions to report. This file must have a specific name: **simulation_<BUILDINGID>.json** *For example if the building ID is 3424*: ``simulation_3424.json`` You can either create the simulation file manually or use the [Evaluation Tool](https://my.indoo.rs/javadoc/mmt_guide/#MMTToolsOverview) in MMT. We recommend the second option. For more information on the format see the [Android section](doc:evaluation-mode).
{"_id":"59ca4b174bec1e0010fe4b78","category":"59ca4b164bec1e0010fe4b3a","user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:43:04.393Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":4,"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, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, 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]","excerpt":"","slug":"routing-1","type":"basic","title":"Routing","__v":0,"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, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, 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, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, 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]
{"_id":"59ca4b174bec1e0010fe4b79","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-09-23T09:13:28.859Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"## Path Snapping for routing\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 \"path snapping\": the calculated position snaps to the shown route if it is within a certain distance from 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. Recommended values are between 1000 and 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## Path Snapping for predefined routes\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 **after your building was loaded** 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. Recommended values are between 1000 and 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]\n\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"All methods shown above are only allowed to be called after your building was loaded.\"\n}\n[/block]","excerpt":"","slug":"path-snapping","type":"basic","title":"Path Snapping","__v":0,"childrenPages":[]}

Path Snapping


## Path Snapping for routing 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 "path snapping": the calculated position snaps to the shown route if it is within a certain distance from 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. Recommended values are between 1000 and 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] ## Path Snapping for predefined routes 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 **after your building was loaded** 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. Recommended values are between 1000 and 20000 millimetres. [block:code] { "codes": [ { "code": "[[Indoors instance] setPredefinedRouteSnappingMaxDistance:maxDistance];", "language": "objectivec" }, { "code": "Indoors.instance().setPredefinedRouteSnappingMaxDistance(maxDistance)", "language": "swift", "name": "Swift" } ] } [/block] [block:callout] { "type": "danger", "body": "All methods shown above are only allowed to be called after your building was loaded." } [/block]
## Path Snapping for routing 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 "path snapping": the calculated position snaps to the shown route if it is within a certain distance from 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. Recommended values are between 1000 and 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] ## Path Snapping for predefined routes 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 **after your building was loaded** 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. Recommended values are between 1000 and 20000 millimetres. [block:code] { "codes": [ { "code": "[[Indoors instance] setPredefinedRouteSnappingMaxDistance:maxDistance];", "language": "objectivec" }, { "code": "Indoors.instance().setPredefinedRouteSnappingMaxDistance(maxDistance)", "language": "swift", "name": "Swift" } ] } [/block] [block:callout] { "type": "danger", "body": "All methods shown above are only allowed to be called after your building was loaded." } [/block]
{"_id":"59ca4b174bec1e0010fe4b7a","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-01-22T09:37:10.171Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"Dot on Rails feature can enhance user experience of the dot movement, when enabled. The dot will stay on the predefined path, and will not jump through 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 that allows to turn this feature on or off. By default it is enabled. For the best experience you should also enable path snapping.\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 its 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]","excerpt":"","slug":"dot-on-rails","type":"basic","title":"Dot on Rails","__v":0,"childrenPages":[]}

Dot on Rails


Dot on Rails feature can enhance user experience of the dot movement, when enabled. The dot will stay on the predefined path, and will not jump through 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 that allows to turn this feature on or off. By default it is enabled. For the best experience you should also enable path snapping. [block:code] { "codes": [ { "code": "@property (nonatomic) BOOL enableDotOnRails;", "language": "objectivec", "name": "iOS" } ] } [/block] Like path snapping, Dot on Rails feature has its 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 feature can enhance user experience of the dot movement, when enabled. The dot will stay on the predefined path, and will not jump through 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 that allows to turn this feature on or off. By default it is enabled. For the best experience you should also enable path snapping. [block:code] { "codes": [ { "code": "@property (nonatomic) BOOL enableDotOnRails;", "language": "objectivec", "name": "iOS" } ] } [/block] Like path snapping, Dot on Rails feature has its 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]
{"_id":"59ca4b174bec1e0010fe4b7b","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:46:54.480Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":7,"body":"You can use zones for identification of rooms, shops, or more generally, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, 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 users to the zone they select.\n\nYou can see 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]","excerpt":"","slug":"zones-1","type":"basic","title":"Zones","__v":0,"childrenPages":[]}

Zones


You can use zones for identification of rooms, shops, or more generally, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route users to the zone they select. You can see 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, any area of interest. If a user enters a zone, you could show a notification and offer a discount in a shop, for example. Another way to use zones is to show a list of zones (e.g. shops in a shopping mall) and directly route users to the zone they select. You can see 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]
{"_id":"59ca4b174bec1e0010fe4b7c","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:47:48.820Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[{"name":"","status":200,"language":"json","code":"{}"},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"isReference":false,"order":8,"body":"Depending on your specific use case, the user might only be interested to know in which room / shop he is currently located. If that is 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:\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]\nPlease also see the header documentation for more customisation options.\n\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]","excerpt":"","slug":"styling-1","type":"basic","title":"Styling","__v":0,"childrenPages":[]}

Styling


Depending on your specific use case, the user might only be interested to know in which room / shop he is currently located. If that is 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: [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] Please also see the header documentation for more customisation options. 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 is currently located. If that is 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: [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] Please also see the header documentation for more customisation options. 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]
{"_id":"59ca4b174bec1e0010fe4b7d","category":"59ca4b164bec1e0010fe4b3a","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-09-07T07:11:28.308Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":9,"body":"Allow users of your app to interact with the map by registering a click listener:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"_singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapRecognized:)];\\n_singleTapRecognizer.enabled = YES;\\n_singleTapRecognizer.delegate = self;\\n[_indoorsSurfaceViewController.surfaceView.mapScrollView addGestureRecognizer:_singleTapRecognizer];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nIn order to convert screen coordinates to building coordinates, do this:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"CGPoint locationInView = [recognizer locationInView:_indoorsSurfaceViewController.surfaceView.mapScrollView];\\nIDSCoordinate *coordinate = [_indoorsSurfaceViewController.surfaceView.mapScrollView coordinateForPoint:locationInView];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"reacting-on-clicks","type":"basic","title":"Reacting to clicks","__v":0,"childrenPages":[]}

Reacting to clicks


Allow users of your app to interact with the map by registering a click listener: [block:code] { "codes": [ { "code": "_singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapRecognized:)];\n_singleTapRecognizer.enabled = YES;\n_singleTapRecognizer.delegate = self;\n[_indoorsSurfaceViewController.surfaceView.mapScrollView addGestureRecognizer:_singleTapRecognizer];", "language": "objectivec" } ] } [/block] In order to convert screen coordinates to building coordinates, do this: [block:code] { "codes": [ { "code": "CGPoint locationInView = [recognizer locationInView:_indoorsSurfaceViewController.surfaceView.mapScrollView];\nIDSCoordinate *coordinate = [_indoorsSurfaceViewController.surfaceView.mapScrollView coordinateForPoint:locationInView];", "language": "objectivec" } ] } [/block]
Allow users of your app to interact with the map by registering a click listener: [block:code] { "codes": [ { "code": "_singleTapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(singleTapRecognized:)];\n_singleTapRecognizer.enabled = YES;\n_singleTapRecognizer.delegate = self;\n[_indoorsSurfaceViewController.surfaceView.mapScrollView addGestureRecognizer:_singleTapRecognizer];", "language": "objectivec" } ] } [/block] In order to convert screen coordinates to building coordinates, do this: [block:code] { "codes": [ { "code": "CGPoint locationInView = [recognizer locationInView:_indoorsSurfaceViewController.surfaceView.mapScrollView];\nIDSCoordinate *coordinate = [_indoorsSurfaceViewController.surfaceView.mapScrollView coordinateForPoint:locationInView];", "language": "objectivec" } ] } [/block]
{"_id":"59ca4b174bec1e0010fe4b7e","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:49:37.363Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":10,"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!","excerpt":"","slug":"overlays-1","type":"basic","title":"Overlays","__v":0,"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!
{"_id":"59ca4b174bec1e0010fe4b7f","category":"59ca4b164bec1e0010fe4b3a","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-12-23T10:01:23.083Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[{"language":"json","status":200,"name":"","code":"{}"},{"status":400,"name":"","code":"{}","language":"json"}]},"auth":"required","params":[],"url":""},"isReference":false,"order":11,"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 the point of interest to the annotation. Position determine how will the annotation be oriented around the coordinate. Position values are: ISAnnotationViewPositionTop, ISAnnotationViewPositionRigh, ISAnnotationViewPositionBottom, ISAnnotationViewPositionLeft and ISAnnotationViewPositionCenter.","excerpt":"","slug":"annotations","type":"basic","title":"Annotations","__v":0,"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 the point of interest to the annotation. Position determine how will the 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 the point of interest to the annotation. Position determine how will the annotation be oriented around the coordinate. Position values are: ISAnnotationViewPositionTop, ISAnnotationViewPositionRigh, ISAnnotationViewPositionBottom, ISAnnotationViewPositionLeft and ISAnnotationViewPositionCenter.
{"_id":"59ca4b174bec1e0010fe4b80","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":["5840043fc0507319000634b2"],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:50:03.921Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"name":"","status":400,"language":"json","code":"{}"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":12,"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 execute the curl command inside the project folder\"\n}\n[/block]\nThe resulting file needs to have an \".idp\" file extension. Now drag this file into your XCode-project and 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). 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\nIf you do not 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]","excerpt":"","slug":"map-with-app-1","type":"basic","title":"Map with App","__v":0,"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 execute the curl command inside the project folder" } [/block] The resulting file needs to have an ".idp" file extension. Now drag this file into your XCode-project and 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). 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. If you do not 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 execute the curl command inside the project folder" } [/block] The resulting file needs to have an ".idp" file extension. Now drag this file into your XCode-project and 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). 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. If you do not 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]
{"_id":"59ca4b174bec1e0010fe4b81","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:51:04.851Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":"","settings":""},"isReference":false,"order":13,"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 use cases.","excerpt":"","slug":"background-only-localization","type":"basic","title":"Background only localization","__v":0,"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 use cases.
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 use cases.
{"_id":"59ca4b174bec1e0010fe4b82","category":"59ca4b164bec1e0010fe4b3a","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:51:35.402Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"language":"json","code":"{}","name":"","status":200},{"code":"{}","name":"","status":400,"language":"json"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":14,"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.","excerpt":"","slug":"localization-without-ui","type":"basic","title":"Localization without UI","__v":0,"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.
{"_id":"59ca4b174bec1e0010fe4b83","category":"59ca4b164bec1e0010fe4b3a","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-07-07T17:25:02.305Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"name":"","status":400,"language":"json","code":"{}"}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":15,"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]","excerpt":"","slug":"ui-without-localization","type":"basic","title":"UI without localization","__v":0,"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]
{"_id":"59ca4b174bec1e0010fe4b84","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-02-12T10:57:10.538Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"name":"","code":"{}","language":"json"},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":16,"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]","excerpt":"","slug":"building-download-1","type":"basic","title":"Building Download","__v":0,"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]
{"_id":"59ca4b174bec1e0010fe4b85","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-13T09:52:25.567Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":17,"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 did not set an origin for your building in the MMT.\n   \nb) You set no / a wrong rotation for your building in the MMT!","excerpt":"","slug":"gps-coordinates-1","type":"basic","title":"GPS Coordinates","__v":0,"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 did not set an origin for your building in the MMT. b) 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 did not set an origin for your building in the MMT. b) You set no / a wrong rotation for your building in the MMT!
{"_id":"59ca4b174bec1e0010fe4b86","category":"59ca4b164bec1e0010fe4b3a","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-08-31T15:35:58.957Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":18,"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]","excerpt":"","slug":"get-and-set-visible-map-area","type":"basic","title":"Get and set visible map area","__v":0,"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]
{"_id":"59ca4b174bec1e0010fe4b87","category":"59ca4b164bec1e0010fe4b3a","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-03-30T13:17:45.508Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":19,"body":"The Kalman filter is used to improve localization 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 Stabilization 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 stabilization filter to kick in. Minimum value is 4000 ms, maximum is 20000 ms.\nBecause for some venues the Stabilization filter doesn't yield the best results it is disabled by default and can be enabled on demand.\n\nTo enable/disable stabilization 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]\n\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"title\": \"Enabling/disabling Stabilization filter and setting time\",\n  \"body\": \"Make sure to set this values before you start with the building download.\"\n}\n[/block]\nSince version 4.8.0, we have introduced a new setting to improve the localization stability. If you exprience localization \"jumps\", you can set a limit on the distance between two position updates.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setSmallJumpDistance:2.0];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nIn this example the distance is set to 2 meters. By default it is unlimited, setting a limit is purely optional.\n\nIn case if there are areas in your building where radio signal is unstable and the blue dot sometimes gets stuck, you should allow it to catch up in bigger jumps:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setBigJumpDistance:5.0];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nIf you never experience the dot being stuck, you can set the big jump value to the same one as  the small jump. However, keep in mind that you either have to set both distances, or none (in this case the additional stability feature is disabled). These settings should be applied before loading the building.\n\nIf you limit the jump distance, we also recommend to disable *dotOnRails* feature, especially in cases when your building has small rooms.","excerpt":"","slug":"using-stabilization-filter-and-kalman-filter-1","type":"basic","title":"Using Kalman and Stabilization filter","__v":0,"childrenPages":[]}

Using Kalman and Stabilization filter


The Kalman filter is used to improve localization 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 Stabilization 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 stabilization filter to kick in. Minimum value is 4000 ms, maximum is 20000 ms. Because for some venues the Stabilization filter doesn't yield the best results it is disabled by default and can be enabled on demand. To enable/disable stabilization 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] [block:callout] { "type": "warning", "title": "Enabling/disabling Stabilization filter and setting time", "body": "Make sure to set this values before you start with the building download." } [/block] Since version 4.8.0, we have introduced a new setting to improve the localization stability. If you exprience localization "jumps", you can set a limit on the distance between two position updates. [block:code] { "codes": [ { "code": "[[Indoors instance] setSmallJumpDistance:2.0];", "language": "objectivec" } ] } [/block] In this example the distance is set to 2 meters. By default it is unlimited, setting a limit is purely optional. In case if there are areas in your building where radio signal is unstable and the blue dot sometimes gets stuck, you should allow it to catch up in bigger jumps: [block:code] { "codes": [ { "code": "[[Indoors instance] setBigJumpDistance:5.0];", "language": "objectivec" } ] } [/block] If you never experience the dot being stuck, you can set the big jump value to the same one as the small jump. However, keep in mind that you either have to set both distances, or none (in this case the additional stability feature is disabled). These settings should be applied before loading the building. If you limit the jump distance, we also recommend to disable *dotOnRails* feature, especially in cases when your building has small rooms.
The Kalman filter is used to improve localization 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 Stabilization 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 stabilization filter to kick in. Minimum value is 4000 ms, maximum is 20000 ms. Because for some venues the Stabilization filter doesn't yield the best results it is disabled by default and can be enabled on demand. To enable/disable stabilization 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] [block:callout] { "type": "warning", "title": "Enabling/disabling Stabilization filter and setting time", "body": "Make sure to set this values before you start with the building download." } [/block] Since version 4.8.0, we have introduced a new setting to improve the localization stability. If you exprience localization "jumps", you can set a limit on the distance between two position updates. [block:code] { "codes": [ { "code": "[[Indoors instance] setSmallJumpDistance:2.0];", "language": "objectivec" } ] } [/block] In this example the distance is set to 2 meters. By default it is unlimited, setting a limit is purely optional. In case if there are areas in your building where radio signal is unstable and the blue dot sometimes gets stuck, you should allow it to catch up in bigger jumps: [block:code] { "codes": [ { "code": "[[Indoors instance] setBigJumpDistance:5.0];", "language": "objectivec" } ] } [/block] If you never experience the dot being stuck, you can set the big jump value to the same one as the small jump. However, keep in mind that you either have to set both distances, or none (in this case the additional stability feature is disabled). These settings should be applied before loading the building. If you limit the jump distance, we also recommend to disable *dotOnRails* feature, especially in cases when your building has small rooms.
{"_id":"59d24aa0ab9629001088a254","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","category":"59ca4b164bec1e0010fe4b3a","user":"54e5a4a0d3ab670d00f3af54","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-10-02T14:18:08.891Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":999,"body":"Since constant position calculation can be quite energy demanding when running for a long time (hours), two methods were introduced in version 4.8.0 to improve battery lifetime.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"However, be aware that they come with the price of less accuracy - so only use them if you really have to! In most cases (unless your app is supposed to run the whole day, for example) you should not modify these settings.\"\n}\n[/block]\n\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoorce instance] useSensors:NO];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nAllows to disable phone sensors usage (like magnetic and gyroscope). Sensors are enabled by default.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"[[Indoors instance] setDutyCycle:1000];\",\n      \"language\": \"objectivec\"\n    }\n  ]\n}\n[/block]\nDefines how often the position is calculated in milliseconds, default value is 100.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"title\": \"TO BE USED WITH EXTREME CARE!\"\n}\n[/block]\nMay save a lot of battery, but will result in latency for position updates. E.g., setting the value to 5000 means that the position is calculated only every 5 seconds.\n\nThese settings should be applied before loading the building.","excerpt":"","slug":"battery-saving-options-1","type":"basic","title":"Battery saving options","__v":0,"childrenPages":[]}

Battery saving options


Since constant position calculation can be quite energy demanding when running for a long time (hours), two methods were introduced in version 4.8.0 to improve battery lifetime. [block:callout] { "type": "danger", "body": "However, be aware that they come with the price of less accuracy - so only use them if you really have to! In most cases (unless your app is supposed to run the whole day, for example) you should not modify these settings." } [/block] [block:code] { "codes": [ { "code": "[[Indoorce instance] useSensors:NO];", "language": "objectivec" } ] } [/block] Allows to disable phone sensors usage (like magnetic and gyroscope). Sensors are enabled by default. [block:code] { "codes": [ { "code": "[[Indoors instance] setDutyCycle:1000];", "language": "objectivec" } ] } [/block] Defines how often the position is calculated in milliseconds, default value is 100. [block:callout] { "type": "danger", "title": "TO BE USED WITH EXTREME CARE!" } [/block] May save a lot of battery, but will result in latency for position updates. E.g., setting the value to 5000 means that the position is calculated only every 5 seconds. These settings should be applied before loading the building.
Since constant position calculation can be quite energy demanding when running for a long time (hours), two methods were introduced in version 4.8.0 to improve battery lifetime. [block:callout] { "type": "danger", "body": "However, be aware that they come with the price of less accuracy - so only use them if you really have to! In most cases (unless your app is supposed to run the whole day, for example) you should not modify these settings." } [/block] [block:code] { "codes": [ { "code": "[[Indoorce instance] useSensors:NO];", "language": "objectivec" } ] } [/block] Allows to disable phone sensors usage (like magnetic and gyroscope). Sensors are enabled by default. [block:code] { "codes": [ { "code": "[[Indoors instance] setDutyCycle:1000];", "language": "objectivec" } ] } [/block] Defines how often the position is calculated in milliseconds, default value is 100. [block:callout] { "type": "danger", "title": "TO BE USED WITH EXTREME CARE!" } [/block] May save a lot of battery, but will result in latency for position updates. E.g., setting the value to 5000 means that the position is calculated only every 5 seconds. These settings should be applied before loading the building.
{"_id":"59ca4b164bec1e0010fe4b45","category":"59ca4b164bec1e0010fe4b3b","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-09-19T13:24:53.451Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"Before you start using indoo.rs, go to [my.indoo.rs](https://my.indoo.rs/) to register. After having successfully set up your account and uploading your building map, you can now start using the Mobile Toolkit.\n\nDownload the Mobile Toolkit on you Android device [here](https://play.google.com/store/apps/details?id=com.customlbs.android.mmt&hl=en). You need it in order to convert your building map into a radio map.\n\nOpen the Mobile Toolkit and log in, using the credentials you obtained from my.indoo.rs.\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%2FPG8X2v-BtpI%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DPG8X2v-BtpI&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FPG8X2v-BtpI%2Fhqdefault.jpg&key=f2aa6fc3595946d0afc3d76cbbd25dc3&type=text%2Fhtml&schema=youtube\\\" width=\\\"854\\\" height=\\\"480\\\" scrolling=\\\"no\\\" frameborder=\\\"0\\\" allowfullscreen></iframe>\",\n  \"url\": \"https://www.youtube.com/watch?v=PG8X2v-BtpI\",\n  \"title\": \"indoo.rs Mobile Toolkit Quick Guide for Indoor Positioning\",\n  \"favicon\": \"https://s.ytimg.com/yts/img/favicon-vfl8qSV2F.ico\",\n  \"image\": \"https://i.ytimg.com/vi/PG8X2v-BtpI/hqdefault.jpg\"\n}\n[/block]","excerpt":"","slug":"getting-started-with-indoors-mobile-toolkit","type":"basic","title":"Getting Started with indoo.rs Mobile Toolkit","__v":0,"childrenPages":[]}

Getting Started with indoo.rs Mobile Toolkit


Before you start using indoo.rs, go to [my.indoo.rs](https://my.indoo.rs/) to register. After having successfully set up your account and uploading your building map, you can now start using the Mobile Toolkit. Download the Mobile Toolkit on you Android device [here](https://play.google.com/store/apps/details?id=com.customlbs.android.mmt&hl=en). You need it in order to convert your building map into a radio map. Open the Mobile Toolkit and log in, using the credentials you obtained from my.indoo.rs. [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FPG8X2v-BtpI%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DPG8X2v-BtpI&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FPG8X2v-BtpI%2Fhqdefault.jpg&key=f2aa6fc3595946d0afc3d76cbbd25dc3&type=text%2Fhtml&schema=youtube\" width=\"854\" height=\"480\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://www.youtube.com/watch?v=PG8X2v-BtpI", "title": "indoo.rs Mobile Toolkit Quick Guide for Indoor Positioning", "favicon": "https://s.ytimg.com/yts/img/favicon-vfl8qSV2F.ico", "image": "https://i.ytimg.com/vi/PG8X2v-BtpI/hqdefault.jpg" } [/block]
Before you start using indoo.rs, go to [my.indoo.rs](https://my.indoo.rs/) to register. After having successfully set up your account and uploading your building map, you can now start using the Mobile Toolkit. Download the Mobile Toolkit on you Android device [here](https://play.google.com/store/apps/details?id=com.customlbs.android.mmt&hl=en). You need it in order to convert your building map into a radio map. Open the Mobile Toolkit and log in, using the credentials you obtained from my.indoo.rs. [block:embed] { "html": "<iframe class=\"embedly-embed\" src=\"//cdn.embedly.com/widgets/media.html?src=https%3A%2F%2Fwww.youtube.com%2Fembed%2FPG8X2v-BtpI%3Ffeature%3Doembed&url=http%3A%2F%2Fwww.youtube.com%2Fwatch%3Fv%3DPG8X2v-BtpI&image=https%3A%2F%2Fi.ytimg.com%2Fvi%2FPG8X2v-BtpI%2Fhqdefault.jpg&key=f2aa6fc3595946d0afc3d76cbbd25dc3&type=text%2Fhtml&schema=youtube\" width=\"854\" height=\"480\" scrolling=\"no\" frameborder=\"0\" allowfullscreen></iframe>", "url": "https://www.youtube.com/watch?v=PG8X2v-BtpI", "title": "indoo.rs Mobile Toolkit Quick Guide for Indoor Positioning", "favicon": "https://s.ytimg.com/yts/img/favicon-vfl8qSV2F.ico", "image": "https://i.ytimg.com/vi/PG8X2v-BtpI/hqdefault.jpg" } [/block]
{"_id":"59ca4b164bec1e0010fe4b46","category":"59ca4b164bec1e0010fe4b3b","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-04-28T07:59:18.645Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"auth":"required","params":[],"url":""},"isReference":false,"order":1,"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.","excerpt":"","slug":"positioning-ibeacons-for-fingerprinting","type":"basic","title":"Positioning iBeacons for fingerprinting","__v":0,"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.
{"_id":"59ca4b164bec1e0010fe4b47","category":"59ca4b164bec1e0010fe4b3b","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-08-17T11:05:39.284Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"After logging in successfully, you will see the list of buildings you have created (to create a building please visit our [guide](https://my.indoo.rs/javadoc/mmt_guide/)).\n\nFirst, choose your application from the list. Then, select the building you need to take measurements for.\n[block:callout]\n{\n  \"type\": \"danger\",\n  \"body\": \"After the map has been loaded, you will see a \\\"health indicator\\\" symbol. If any important permissions or sensors are missing, it will be red (yellow in case of inaccurate sensors and green if everything is ok). Click it to enable all the necessary settings.\\n\\nGrant the necessary permissions and calibrate your phone if needed. If all smileys are green, you’re good to move on to the next step. On some devices, “Magnetic Field” won’t turn green even after calibrating - that is fine and you can still proceed to stage 3.\",\n  \"title\": \"Important\"\n}\n[/block]","excerpt":"","slug":"selecting-your-building","type":"basic","title":"Selecting your building","__v":0,"childrenPages":[]}

Selecting your building


After logging in successfully, you will see the list of buildings you have created (to create a building please visit our [guide](https://my.indoo.rs/javadoc/mmt_guide/)). First, choose your application from the list. Then, select the building you need to take measurements for. [block:callout] { "type": "danger", "body": "After the map has been loaded, you will see a \"health indicator\" symbol. If any important permissions or sensors are missing, it will be red (yellow in case of inaccurate sensors and green if everything is ok). Click it to enable all the necessary settings.\n\nGrant the necessary permissions and calibrate your phone if needed. If all smileys are green, you’re good to move on to the next step. On some devices, “Magnetic Field” won’t turn green even after calibrating - that is fine and you can still proceed to stage 3.", "title": "Important" } [/block]
After logging in successfully, you will see the list of buildings you have created (to create a building please visit our [guide](https://my.indoo.rs/javadoc/mmt_guide/)). First, choose your application from the list. Then, select the building you need to take measurements for. [block:callout] { "type": "danger", "body": "After the map has been loaded, you will see a \"health indicator\" symbol. If any important permissions or sensors are missing, it will be red (yellow in case of inaccurate sensors and green if everything is ok). Click it to enable all the necessary settings.\n\nGrant the necessary permissions and calibrate your phone if needed. If all smileys are green, you’re good to move on to the next step. On some devices, “Magnetic Field” won’t turn green even after calibrating - that is fine and you can still proceed to stage 3.", "title": "Important" } [/block]
{"_id":"59ca4b164bec1e0010fe4b48","category":"59ca4b164bec1e0010fe4b3b","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-08-17T11:06:42.376Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"body":"Before making a recording, pre-draw the path that you plan to walk on the map.\n\n- Zoom into the map.\n- Move the location marker (orange balloon) to the point on the map where you’d like to start your recordings later.  \n- Tap “Add point” and move the marker to add the next point. Keep in mind that you must walk straigth between each two points, so if there is a turn or obstacle, add a point right before it.\n- Keep drawing until you have specified the whole path you are going to walk.\n- If you misplaced a point, press \"remove\".\n- Press “Finish drawing”.\n[block:callout]\n{\n  \"type\": \"info\",\n  \"body\": \"Create these \\\"Groundtruth\\\" 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)\\nYou can also add additional ground truths on straight path segments, but do not place them closer than 4 meters to each other.\",\n  \"title\": \"When to add points (gound truths)\"\n}\n[/block]\n\n[block:callout]\n{\n  \"type\": \"info\",\n  \"title\": \"Line between ground truths\",\n  \"body\": \"The line shown between the ground truths is exactly the line that you need to walk on. Avoid intersecting any obstacles while you create the predrawn path. Obstacles might be any objects like desks, shelves or similar that are not on your map or even wall. Generally if you can not pass through it while walking, the drawn path should also not cross it.\"\n}\n[/block]","excerpt":"","slug":"drawing-a-path-to-walk-and-measure","type":"basic","title":"Drawing a path to walk and measure","__v":0,"childrenPages":[]}

Drawing a path to walk and measure


Before making a recording, pre-draw the path that you plan to walk on the map. - Zoom into the map. - Move the location marker (orange balloon) to the point on the map where you’d like to start your recordings later. - Tap “Add point” and move the marker to add the next point. Keep in mind that you must walk straigth between each two points, so if there is a turn or obstacle, add a point right before it. - Keep drawing until you have specified the whole path you are going to walk. - If you misplaced a point, press "remove". - Press “Finish drawing”. [block:callout] { "type": "info", "body": "Create these \"Groundtruth\" 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)\nYou can also add additional ground truths on straight path segments, but do not place them closer than 4 meters to each other.", "title": "When to add points (gound truths)" } [/block] [block:callout] { "type": "info", "title": "Line between ground truths", "body": "The line shown between the ground truths is exactly the line that you need to walk on. Avoid intersecting any obstacles while you create the predrawn path. Obstacles might be any objects like desks, shelves or similar that are not on your map or even wall. Generally if you can not pass through it while walking, the drawn path should also not cross it." } [/block]
Before making a recording, pre-draw the path that you plan to walk on the map. - Zoom into the map. - Move the location marker (orange balloon) to the point on the map where you’d like to start your recordings later. - Tap “Add point” and move the marker to add the next point. Keep in mind that you must walk straigth between each two points, so if there is a turn or obstacle, add a point right before it. - Keep drawing until you have specified the whole path you are going to walk. - If you misplaced a point, press "remove". - Press “Finish drawing”. [block:callout] { "type": "info", "body": "Create these \"Groundtruth\" 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)\nYou can also add additional ground truths on straight path segments, but do not place them closer than 4 meters to each other.", "title": "When to add points (gound truths)" } [/block] [block:callout] { "type": "info", "title": "Line between ground truths", "body": "The line shown between the ground truths is exactly the line that you need to walk on. Avoid intersecting any obstacles while you create the predrawn path. Obstacles might be any objects like desks, shelves or similar that are not on your map or even wall. Generally if you can not pass through it while walking, the drawn path should also not cross it." } [/block]
{"_id":"59ca4b164bec1e0010fe4b49","category":"59ca4b164bec1e0010fe4b3b","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-08-17T11:07:48.975Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":4,"body":"After you have drawn the path you are now ready to take recordings. Ideally you will make at least 10 normal steps between each groundtruth. Try to keep one recording round between a half to 4 minutes.\n\n- Stand exactly at the location marked by the first point of your drawn path\n- Press “Start” and walk along the path you have drawn at a steady pace. Make sure your mobile device is held normally (not too still!), so the steps you take will actually be recorded. \n- Press “Confirm” each time you have reached the next marked point. Don’t stop, and keep walking along your path.\n- After you’ve confirmed the last ground truth, press “Finish”.\n- Enter a name and a comment about the recording for easy inspection later on, and upload the recording to your my.indoo.rs account.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"In order to get good accuracy, you need to cover each area at least twice.\",\n  \"title\": \"Important\"\n}\n[/block]","excerpt":"","slug":"take-recordings","type":"basic","title":"Take recordings","__v":0,"childrenPages":[]}

Take recordings


After you have drawn the path you are now ready to take recordings. Ideally you will make at least 10 normal steps between each groundtruth. Try to keep one recording round between a half to 4 minutes. - Stand exactly at the location marked by the first point of your drawn path - Press “Start” and walk along the path you have drawn at a steady pace. Make sure your mobile device is held normally (not too still!), so the steps you take will actually be recorded. - Press “Confirm” each time you have reached the next marked point. Don’t stop, and keep walking along your path. - After you’ve confirmed the last ground truth, press “Finish”. - Enter a name and a comment about the recording for easy inspection later on, and upload the recording to your my.indoo.rs account. [block:callout] { "type": "warning", "body": "In order to get good accuracy, you need to cover each area at least twice.", "title": "Important" } [/block]
After you have drawn the path you are now ready to take recordings. Ideally you will make at least 10 normal steps between each groundtruth. Try to keep one recording round between a half to 4 minutes. - Stand exactly at the location marked by the first point of your drawn path - Press “Start” and walk along the path you have drawn at a steady pace. Make sure your mobile device is held normally (not too still!), so the steps you take will actually be recorded. - Press “Confirm” each time you have reached the next marked point. Don’t stop, and keep walking along your path. - After you’ve confirmed the last ground truth, press “Finish”. - Enter a name and a comment about the recording for easy inspection later on, and upload the recording to your my.indoo.rs account. [block:callout] { "type": "warning", "body": "In order to get good accuracy, you need to cover each area at least twice.", "title": "Important" } [/block]
{"_id":"59ca4b164bec1e0010fe4b4a","category":"59ca4b164bec1e0010fe4b3b","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-03-27T17:00:07.061Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","name":"","status":200,"language":"json"},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"body":"After finishing recording you might see a message telling you that there are pending uploads. This usually happens if no network was available. Once you have a stable connection again, press \"Upload\" button in the top bar to retry uploading the recordings.","excerpt":"","slug":"uploading-pending-uploads","type":"basic","title":"Pending uploads","__v":0,"childrenPages":[]}

Pending uploads


After finishing recording you might see a message telling you that there are pending uploads. This usually happens if no network was available. Once you have a stable connection again, press "Upload" button in the top bar to retry uploading the recordings.
After finishing recording you might see a message telling you that there are pending uploads. This usually happens if no network was available. Once you have a stable connection again, press "Upload" button in the top bar to retry uploading the recordings.
{"_id":"59ca4b164bec1e0010fe4b4b","category":"59ca4b164bec1e0010fe4b3b","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-08-17T11:15:40.401Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":6,"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. \n\nNow that you took recordings for your building you are ready to turn this data into a map that can be used for localization. To do this, head to my.indoo.rs, select your Application and Building and choose \"SLAM\". Click \"Start new job\" to start our algorithms crunching your data into a map. After that is done, you can upload a new version of your building with just one click on the \"Upload to cloud\"-button next to your completed job.\n[block:callout]\n{\n  \"type\": \"info\",\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]","excerpt":"","slug":"run-a-slam-job","type":"basic","title":"Run a SLAM job","__v":0,"childrenPages":[]}

Run a SLAM job


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. Now that you took recordings for your building you are ready to turn this data into a map that can be used for localization. To do this, head to my.indoo.rs, select your Application and Building and choose "SLAM". Click "Start new job" to start our algorithms crunching your data into a map. After that is done, you can upload a new version of your building with just one click on the "Upload to cloud"-button next to your completed job. [block:callout] { "type": "info", "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]
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. Now that you took recordings for your building you are ready to turn this data into a map that can be used for localization. To do this, head to my.indoo.rs, select your Application and Building and choose "SLAM". Click "Start new job" to start our algorithms crunching your data into a map. After that is done, you can upload a new version of your building with just one click on the "Upload to cloud"-button next to your completed job. [block:callout] { "type": "info", "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]
{"_id":"59ccfbd533dd99001a597d0d","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","category":"59ca4b164bec1e0010fe4b3d","user":"54e5a4a0d3ab670d00f3af54","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-09-28T13:40:37.522Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"- consistent routing experience on Android and iOS\n- remove Crittercism on iOS","excerpt":"","slug":"470","type":"basic","title":"4.7.0","__v":0,"parentDoc":null,"childrenPages":[]}

4.7.0


- consistent routing experience on Android and iOS - remove Crittercism on iOS
- consistent routing experience on Android and iOS - remove Crittercism on iOS
{"_id":"59ca4b164bec1e0010fe4b4d","category":"59ca4b164bec1e0010fe4b3d","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-06-28T07:58:18.339Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":1,"body":"* SDK now requires location-permission from API level 21 onward!\n* Improve Evaluation Mode\n* Allow conversion from GPS to building coordinate on iOS\n* Show that user has to switch floors when routing goes to different floor\n* Expose a \"middle of zone\" reference implementation\n* Add a delay for orientation changes","excerpt":"","slug":"460-1","type":"basic","title":"4.6.0","__v":0,"childrenPages":[]}

4.6.0


* SDK now requires location-permission from API level 21 onward! * Improve Evaluation Mode * Allow conversion from GPS to building coordinate on iOS * Show that user has to switch floors when routing goes to different floor * Expose a "middle of zone" reference implementation * Add a delay for orientation changes
* SDK now requires location-permission from API level 21 onward! * Improve Evaluation Mode * Allow conversion from GPS to building coordinate on iOS * Show that user has to switch floors when routing goes to different floor * Expose a "middle of zone" reference implementation * Add a delay for orientation changes
{"_id":"59ca4b164bec1e0010fe4b4e","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2017-02-03T10:15:15.822Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"* Removed some 3rd party dependencies from Android Navigation SDK\n* Changed Viewer and SDK default settings for some localization parameters to improve user experience\n* New cordova plugin for the Navigation SDK\n* ARM 64-bit support for the Android Navigation SDK\n* Improved performance of Analytics dashboard\n* Bugfix: Beacons are added to every floor (MMT)\n* Bugfix: Sometimes a wrong tile was displayed when zooming in (Android Navigation SDK)","excerpt":"","slug":"440","type":"basic","title":"4.4.0","__v":0,"childrenPages":[]}

4.4.0


* Removed some 3rd party dependencies from Android Navigation SDK * Changed Viewer and SDK default settings for some localization parameters to improve user experience * New cordova plugin for the Navigation SDK * ARM 64-bit support for the Android Navigation SDK * Improved performance of Analytics dashboard * Bugfix: Beacons are added to every floor (MMT) * Bugfix: Sometimes a wrong tile was displayed when zooming in (Android Navigation SDK)
* Removed some 3rd party dependencies from Android Navigation SDK * Changed Viewer and SDK default settings for some localization parameters to improve user experience * New cordova plugin for the Navigation SDK * ARM 64-bit support for the Android Navigation SDK * Improved performance of Analytics dashboard * Bugfix: Beacons are added to every floor (MMT) * Bugfix: Sometimes a wrong tile was displayed when zooming in (Android Navigation SDK)
{"_id":"59ca4b164bec1e0010fe4b4f","category":"59ca4b164bec1e0010fe4b3d","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-10-14T09:51:50.096Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","status":200,"language":"json","code":"{}"},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":3,"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
{"_id":"59ca4b164bec1e0010fe4b50","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-08-25T13:28:30.297Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"code":"{}","language":"json","status":200,"name":""},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":4,"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]","excerpt":"","slug":"360","type":"basic","title":"4.2.0","__v":0,"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]
{"_id":"59ca4b164bec1e0010fe4b51","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-06-27T14:54:06.265Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":5,"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.","excerpt":"","slug":"410","type":"basic","title":"4.1.0","__v":0,"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.
{"_id":"59ca4b164bec1e0010fe4b52","category":"59ca4b164bec1e0010fe4b3d","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-03-30T15:27:09.469Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"auth":"required","params":[],"url":""},"isReference":false,"order":6,"body":"- Fixed a bug on iOS where routes might not be displayed correctly","excerpt":"","slug":"402","type":"basic","title":"4.0.2","__v":0,"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
{"_id":"59ca4b164bec1e0010fe4b53","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2016-02-09T13:11:20.123Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":7,"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","excerpt":"","slug":"400","type":"basic","title":"4.0.0","__v":0,"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
{"_id":"59ca4b164bec1e0010fe4b54","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-11-26T08:55:25.981Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":8,"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* Several bug fixes.","excerpt":"","slug":"380","type":"basic","title":"3.8.0","__v":0,"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. * 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. * Several bug fixes.
{"_id":"59ca4b164bec1e0010fe4b55","category":"59ca4b164bec1e0010fe4b3d","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-11-26T08:54:59.544Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"language":"json","code":"{}","name":"","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":9,"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.","excerpt":"","slug":"370","type":"basic","title":"3.7.0","__v":0,"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.
{"_id":"59ca4b164bec1e0010fe4b56","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-11-26T08:54:40.320Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":10,"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","excerpt":"","slug":"360-1","type":"basic","title":"3.6.0","__v":0,"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
{"_id":"59ca4b164bec1e0010fe4b57","category":"59ca4b164bec1e0010fe4b3d","user":"54e5a4a0d3ab670d00f3af54","project":"54e5ed7fd3ab670d00f3afec","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-07-22T13:54:00.699Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"status":200,"language":"json","code":"{}","name":""},{"status":400,"language":"json","code":"{}","name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":11,"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.","excerpt":"","slug":"350","type":"basic","title":"3.5.0","__v":0,"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.
{"_id":"59ca4b164bec1e0010fe4b58","category":"59ca4b164bec1e0010fe4b3d","parentDoc":null,"project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-08-25T13:26:51.045Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"code":"{}","language":"json","status":400,"name":""}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":12,"body":"* Fixed an issue with downloading buildings that were already cached on the device","excerpt":"","slug":"341","type":"basic","title":"3.4.1","__v":0,"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
{"_id":"59ca4b164bec1e0010fe4b59","category":"59ca4b164bec1e0010fe4b3d","project":"54e5ed7fd3ab670d00f3afec","user":"54e5a4a0d3ab670d00f3af54","parentDoc":null,"version":"59ca4b164bec1e0010fe4b37","updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-08-25T13:27:10.498Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[{"name":"","code":"{}","language":"json","status":200},{"name":"","code":"{}","language":"json","status":400}]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":13,"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","excerpt":"","slug":"340","type":"basic","title":"3.4.0","__v":0,"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