├── .gitignore ├── .tool-versions ├── Basic ├── build.gradle ├── debug.keystore ├── proguard-rules.pro └── src │ ├── ar │ ├── AndroidManifest.xml │ ├── assets │ │ ├── .DS_Store │ │ ├── models │ │ │ ├── IA_AR_ad_framed.png │ │ │ ├── andy.obj │ │ │ ├── andy.png │ │ │ ├── andy_shadow.obj │ │ │ ├── andy_shadow.png │ │ │ ├── arrow.obj │ │ │ ├── arrow_stylish.obj │ │ │ ├── finish.obj │ │ │ ├── finish.png │ │ │ ├── sneakers-25-off.png │ │ │ ├── trigrid.png │ │ │ ├── voucher-coffee.png │ │ │ └── white2x2pixels.png │ │ └── shaders │ │ │ ├── ar_object.frag │ │ │ ├── ar_object.vert │ │ │ ├── background_show_depth_color_visualization.frag │ │ │ ├── background_show_depth_color_visualization.vert │ │ │ ├── border_effect.frag │ │ │ ├── floor_plan.frag │ │ │ ├── floor_plan.vert │ │ │ ├── object.frag │ │ │ ├── object.vert │ │ │ ├── plane.frag │ │ │ ├── plane.vert │ │ │ ├── point_cloud.frag │ │ │ ├── point_cloud.vert │ │ │ ├── screenquad.frag │ │ │ └── screenquad.vert │ └── java │ │ └── com │ │ └── indooratlas │ │ └── android │ │ └── sdk │ │ └── examples │ │ └── ar │ │ ├── ThirdPartyAr.java │ │ ├── WayfindingAr.java │ │ ├── WayfindingSession.java │ │ ├── helpers │ │ ├── CameraPermissionHelper.java │ │ ├── DisplayRotationHelper.java │ │ ├── FullScreenHelper.java │ │ ├── SnackbarHelper.java │ │ ├── TapHelper.java │ │ └── TrackingStateHelper.java │ │ ├── rendering │ │ ├── BitmapRenderer.java │ │ ├── BitmapSignRenderer.java │ │ ├── BorderEffect.java │ │ ├── ObjectRenderer.java │ │ └── ShaderUtil.java │ │ └── wrapper │ │ └── Api.java │ ├── arCore │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── indooratlas │ │ │ └── android │ │ │ └── sdk │ │ │ └── examples │ │ │ └── ar │ │ │ ├── rendering │ │ │ ├── BackgroundRenderer.java │ │ │ ├── PlaneRenderer.java │ │ │ ├── PointCloudRenderer.java │ │ │ └── Texture.java │ │ │ └── wrapper │ │ │ ├── ArCore.java │ │ │ └── Implementation.java │ └── res │ │ └── values │ │ └── strings.xml │ ├── arEngine │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── indooratlas │ │ │ └── android │ │ │ └── sdk │ │ │ └── examples │ │ │ └── ar │ │ │ └── wrapper │ │ │ ├── ArEngine.java │ │ │ ├── ConnectAppMarketActivity.java │ │ │ ├── Implementation.java │ │ │ ├── MatrixUtil.java │ │ │ └── TextureDisplay.java │ └── res │ │ ├── layout │ │ └── activity_connection_app_market.xml │ │ └── values │ │ └── strings.xml │ ├── lite │ └── java │ │ └── com │ │ └── indooratlas │ │ └── android │ │ └── sdk │ │ └── examples │ │ └── ar │ │ ├── ThirdPartyAr.java │ │ ├── WayfindingAr.java │ │ └── wrapper │ │ ├── Api.java │ │ └── Implementation.java │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── indooratlas │ │ └── android │ │ └── sdk │ │ └── examples │ │ ├── ListExamplesActivity.java │ │ ├── SdkExample.java │ │ ├── credentials │ │ └── CredentialsFromCodeActivity.java │ │ ├── foregroundservice │ │ ├── ForegroundService.java │ │ └── MainActivity.java │ │ ├── geofence │ │ └── GeofenceMapsOverlayActivity.java │ │ ├── googlemapsindoor │ │ └── GoogleMapsIndoorActivity.java │ │ ├── imageview │ │ ├── BlueDotView.java │ │ ├── ImageViewActivity.java │ │ └── SmoothEstimate.java │ │ ├── locationsettings │ │ └── LocationSettingsActivity.java │ │ ├── lockfloor │ │ └── LockFloorActivity.java │ │ ├── mapsoverlay │ │ └── MapsOverlayActivity.java │ │ ├── orientation │ │ ├── GLPrimitive.java │ │ ├── GLTools.java │ │ ├── OrientationActivity.java │ │ └── OrientationRenderer.java │ │ ├── regions │ │ └── RegionsActivity.java │ │ ├── simple │ │ └── SimpleActivity.java │ │ ├── systemgeofence │ │ ├── GeofenceReceiver.java │ │ └── MainActivity.java │ │ ├── utils │ │ └── ExampleUtils.java │ │ └── wayfinding │ │ └── WayfindingOverlayActivity.java │ └── res │ ├── anim │ └── notify_change.xml │ ├── drawable-hdpi │ ├── ic_gps_fixed_white_18dp.png │ ├── ic_launcher.png │ └── ic_person_outline_white_36dp.png │ ├── drawable-mdpi │ ├── ic_launcher.png │ └── ic_person_outline_white_36dp.png │ ├── drawable-xhdpi │ ├── ic_launcher.png │ ├── ic_person_outline_white_36dp.png │ ├── map_blue_dot.png │ └── map_red_dot.png │ ├── drawable-xxhdpi │ ├── ic_launcher.png │ └── ic_person_outline_white_36dp.png │ ├── drawable-xxxhdpi │ └── ic_person_outline_white_36dp.png │ ├── drawable │ └── circle.xml │ ├── layout │ ├── activity_ar.xml │ ├── activity_foreground.xml │ ├── activity_image_view.xml │ ├── activity_location_settings.xml │ ├── activity_lockfloor.xml │ ├── activity_main.xml │ ├── activity_maps.xml │ ├── activity_maps_rotate.xml │ ├── activity_orientation.xml │ ├── activity_regions.xml │ ├── activity_simple.xml │ ├── activity_system_geofence.xml │ ├── location_request_dialog.xml │ ├── preference_googlemaps.xml │ ├── text_only.xml │ └── toolbar.xml │ ├── menu │ └── menu_simple.xml │ ├── raw │ └── panorama.jpg │ ├── values-w820dp │ └── dimens.xml │ ├── values │ ├── arrays.xml │ ├── colors.xml │ ├── dimens.xml │ ├── google_maps_api.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── filepaths.xml ├── LICENSE.md ├── README.md ├── build.gradle ├── example-screenshots ├── AR-wayfinding-ad.jpg ├── device-radio-and-location-settings_11.jpg ├── foreground-service_14.png ├── geofences_10.jpg ├── geofences_10.png ├── googlemaps - overlay_04.jpg ├── imageview_02.jpg ├── open-street-map_08.jpg ├── orientation_09.jpg ├── platform_geofence_example_15.png ├── regions_07.jpg ├── set-credentials_06.jpg ├── sharelocation-05.jpg ├── simple_01.jpg └── wayfinding_12.jpg ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | local.properties 3 | # Intellij project files 4 | *.iml 5 | *.ipr 6 | *.iws 7 | .idea/ 8 | build/ 9 | .gradle 10 | -------------------------------------------------------------------------------- /.tool-versions: -------------------------------------------------------------------------------- 1 | java temurin-17.0.12+7 2 | -------------------------------------------------------------------------------- /Basic/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'com.jaredsburrows.license' 3 | 4 | android { 5 | compileSdk 35 6 | 7 | // note: use gradle.properties in project root level to set your api credentials 8 | def apiKey = project.properties['indoorAtlasApiKey'] ?: "api-key-not-set" 9 | def apiSecret = project.properties['indoorAtlasApiSecret'] ?: "api-secret-not-set" 10 | def backgroundReportEndPoint = project.properties['backgroundReportEndPoint'] ?: "" 11 | 12 | buildFeatures { 13 | buildConfig = true 14 | } 15 | 16 | defaultConfig { 17 | applicationId "com.indooratlas.android.sdk.examples" 18 | minSdkVersion 24 19 | targetSdkVersion 34 20 | versionCode 1 21 | versionName "1.0" 22 | // avoid getting errors from malformed string resources if secret contains '%' chars 23 | resValue "string", "indooratlas_api_key", apiKey 24 | resValue "string", "indooratlas_api_secret", apiSecret.replaceAll("%", "\\\\u0025") 25 | resValue "string", "background_report_endpoint", backgroundReportEndPoint 26 | buildConfigField "boolean", "ENABLE_AR", "false" 27 | } 28 | 29 | flavorDimensions "arCapability", "arVariant" 30 | 31 | signingConfigs { 32 | debug { 33 | storeFile file("debug.keystore") 34 | storePassword "android" 35 | keyAlias "sdk_debug" 36 | keyPassword "android" 37 | } 38 | } 39 | 40 | buildTypes { 41 | debug { 42 | debuggable true 43 | } 44 | release { 45 | signingConfig signingConfigs.debug 46 | minifyEnabled true 47 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 48 | } 49 | } 50 | lintOptions { 51 | abortOnError false 52 | } 53 | 54 | productFlavors { 55 | lite { // without AR 56 | dimension "arCapability" 57 | } 58 | ar { // with AR 59 | dimension "arCapability" 60 | buildConfigField "boolean", "ENABLE_AR", "true" 61 | } 62 | 63 | arCore { // use ARCore for AR 64 | dimension "arVariant" 65 | } 66 | arEngine { // use AR Engine for AR 67 | dimension "arVariant" 68 | // This actually adds the repository to all variants, but as long as 69 | // you don't depend on anything there, it should not affect the build 70 | // i.e., the app does not ship with any Huawei code unless the arEngine 71 | // variant is used 72 | repositories { 73 | maven { 74 | // For Huawei AR Engine 75 | url 'https://developer.huawei.com/repo/' 76 | } 77 | } 78 | } 79 | noAr { // dummy AR choice to be used with "lite" (= no AR) 80 | dimension "arVariant" 81 | } 82 | } 83 | namespace 'com.indooratlas.android.sdk.examples' 84 | 85 | android.variantFilter { variant -> 86 | def name1 = variant.getFlavors().get(0).name 87 | def name2 = variant.getFlavors().get(1).name 88 | if (name1.equals('lite') == name2.startsWith('ar')) { 89 | variant.setIgnore(true); 90 | } 91 | } 92 | 93 | } 94 | 95 | dependencies { 96 | 97 | implementation "com.indooratlas.android:indooratlas-android-sdk:3.7.1@aar" 98 | //noinspection GradleCompatible 99 | implementation 'androidx.appcompat:appcompat:1.0.0' 100 | //noinspection GradleCompatible 101 | implementation 'com.google.android.material:material:1.0.0' 102 | //noinspection GradleDependency 103 | implementation 'com.google.android.gms:play-services-maps:19.2.0' 104 | implementation 'com.google.android.gms:play-services-location:16.0.0' 105 | 106 | implementation 'com.google.maps.android:android-maps-utils:3.13.0' 107 | implementation 'com.squareup.picasso:picasso:2.5.2' 108 | implementation "com.squareup.okhttp3:okhttp:4.9.3" 109 | 110 | //noinspection GradleDependency 111 | implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0' 112 | implementation 'androidx.constraintlayout:constraintlayout:1.1.3' 113 | 114 | // ARCore (Google Play Services for AR) library. 115 | arCoreImplementation 'com.google.ar:core:1.47.0' 116 | 117 | // Huawei AR Engine 118 | arEngineImplementation 'com.huawei.hms:arenginesdk:2.13.0.4' 119 | 120 | // Obj - a simple Wavefront OBJ file loader. Used by both AR modes 121 | // https://github.com/javagl/Obj 122 | arImplementation 'de.javagl:obj:0.2.1' 123 | 124 | implementation 'com.jakewharton.timber:timber:4.7.1' 125 | } 126 | -------------------------------------------------------------------------------- /Basic/debug.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/debug.keystore -------------------------------------------------------------------------------- /Basic/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Applications/android-sdk-macosx/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | # This example uses Picasso, see: https://github.com/square/picasso/blob/master/README.md 20 | -dontwarn com.squareup.okhttp.** 21 | 22 | -dontwarn org.apache.http.** 23 | -dontwarn android.net.http.** 24 | -keep class com.google.android.gms.** { *; } 25 | -dontwarn com.google.android.gms.** 26 | -dontwarn java.nio.** 27 | -dontwarn org.codehaus.mojo.animal_sniffer.IgnoreJRERequirement 28 | -------------------------------------------------------------------------------- /Basic/src/ar/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/.DS_Store -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/IA_AR_ad_framed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/IA_AR_ad_framed.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/andy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/andy.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/andy_shadow.obj: -------------------------------------------------------------------------------- 1 | # This file uses centimeters as units for non-parametric coordinates. 2 | 3 | g default 4 | v -0.100000 -0.000000 0.100000 5 | v 0.100000 -0.000000 0.100000 6 | v -0.100000 0.000000 -0.100000 7 | v 0.100000 0.000000 -0.100000 8 | vt 0.000000 0.000000 9 | vt 1.000000 0.000000 10 | vt 0.000000 1.000000 11 | vt 1.000000 1.000000 12 | vn 0.000000 1.000000 0.000000 13 | vn 0.000000 1.000000 0.000000 14 | vn 0.000000 1.000000 0.000000 15 | vn 0.000000 1.000000 0.000000 16 | s off 17 | g AndyBlobShadow_GEO 18 | f 4/4/1 3/3/2 1/1/3 2/2/4 19 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/andy_shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/andy_shadow.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/arrow.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.79 (sub 0) OBJ File: 'arrow.blend' 2 | # www.blender.org 3 | mtllib arrow.mtl 4 | o Curve.001 5 | v -0.051080 -0.287953 0.037420 6 | v -0.051080 0.009798 0.037420 7 | v -0.173824 0.009798 0.037420 8 | v -0.003112 0.304726 0.037420 9 | v 0.170422 0.009798 0.037420 10 | v 0.047679 0.009798 0.037420 11 | v 0.047679 -0.287953 0.037420 12 | v -0.051080 -0.287953 -0.037580 13 | v -0.051080 0.009798 -0.037580 14 | v -0.173824 0.009798 -0.037580 15 | v -0.003112 0.304726 -0.037580 16 | v 0.170422 0.009798 -0.037580 17 | v 0.047679 0.009798 -0.037580 18 | v 0.047679 -0.287953 -0.037580 19 | vt 0 0 20 | vt 0 0 21 | vt 0 0 22 | vt 0 0 23 | vt 0 0 24 | vt 0 0 25 | vt 0 0 26 | vt 0 0 27 | vt 0 0 28 | vt 0 0 29 | vt 0 0 30 | vt 0 0 31 | vt 0 0 32 | vt 0 0 33 | vn 0.0000 -0.0000 1.0000 34 | vn -0.0000 0.0000 -1.0000 35 | vn 0.0000 -1.0000 0.0000 36 | vn 0.8619 0.5071 0.0000 37 | vn 1.0000 0.0000 0.0000 38 | vn -1.0000 0.0000 0.0000 39 | vn -0.8655 0.5010 0.0000 40 | usemtl Material.002 41 | s off 42 | f 2//1 4//1 3//1 43 | f 7//1 2//1 1//1 44 | f 7//1 4//1 2//1 45 | f 7//1 6//1 4//1 46 | f 6//1 5//1 4//1 47 | f 9//2 10//2 11//2 48 | f 14//2 8//2 9//2 49 | f 14//2 9//2 11//2 50 | f 14//2 11//2 13//2 51 | f 13//2 11//2 12//2 52 | f 5//3 6//3 13//3 12//3 53 | f 4//4 5//4 12//4 11//4 54 | f 6//5 7//5 14//5 13//5 55 | f 1//6 2//6 9//6 8//6 56 | f 7//3 1//3 8//3 14//3 57 | f 2//3 3//3 10//3 9//3 58 | f 3//7 4//7 11//7 10//7 59 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/arrow_stylish.obj: -------------------------------------------------------------------------------- 1 | # Blender v2.91.0 OBJ File: 'arrow-yellow.blend' 2 | # www.blender.org 3 | mtllib arrow-yellow1.mtl 4 | o icon_positionArrow.001_icon_positionArrow 5 | v -0.151619 -0.191035 -0.000000 6 | v -0.151619 -0.194138 -0.000000 7 | v -0.150474 -0.198154 -0.000000 8 | v -0.135433 -0.206733 -0.000000 9 | v -0.147368 -0.202717 -0.000000 10 | v -0.131019 -0.205090 -0.000000 11 | v -0.124970 -0.202352 -0.000000 12 | v -0.105352 -0.191583 -0.000000 13 | v -0.134289 -0.139379 -0.000000 14 | v 0.140371 -0.164021 -0.000000 15 | v 0.084948 -0.006133 -0.000000 16 | v 0.086746 -0.182274 -0.000000 17 | v 0.007946 0.209069 0.000000 18 | v -0.008730 0.207609 0.000000 19 | v 0.009907 0.207061 0.000000 20 | v -0.001373 0.212902 0.000000 21 | v -0.004153 0.211625 0.000000 22 | v 0.001406 0.212537 0.000000 23 | v 0.012196 0.203228 0.000000 24 | v -0.012490 0.201403 0.000000 25 | v 0.015302 0.196292 0.000000 26 | v -0.015597 0.194649 0.000000 27 | v -0.019357 0.185523 0.000000 28 | v 0.025275 0.168547 0.000000 29 | v -0.029657 0.158509 0.000000 30 | v -0.087695 -0.005038 -0.000000 31 | v 0.144621 -0.176981 -0.000000 32 | v 0.108327 -0.194686 -0.000000 33 | v 0.148381 -0.191035 -0.000000 34 | v 0.124185 -0.203082 -0.000000 35 | v 0.131215 -0.206368 -0.000000 36 | v 0.148381 -0.193956 -0.000000 37 | v 0.138899 -0.206368 -0.000000 38 | v 0.147237 -0.199067 -0.000000 39 | v 0.143967 -0.203812 -0.000000 40 | v 0.133995 -0.206915 -0.000000 41 | v -0.000883 -0.128975 -0.000000 42 | v -0.143117 -0.205820 -0.000000 43 | v -0.139520 -0.207098 -0.000000 44 | v -0.150474 -0.198154 -0.060000 45 | v -0.151619 -0.194138 -0.060000 46 | v -0.151619 -0.191035 -0.060000 47 | v -0.147368 -0.202717 -0.060000 48 | v -0.135433 -0.206733 -0.060000 49 | v -0.131019 -0.205090 -0.060000 50 | v -0.134289 -0.139379 -0.060000 51 | v -0.105352 -0.191583 -0.060000 52 | v -0.124970 -0.202352 -0.060000 53 | v 0.086746 -0.182274 -0.060000 54 | v 0.084948 -0.006133 -0.060000 55 | v 0.140371 -0.164021 -0.060000 56 | v 0.009907 0.207061 -0.060000 57 | v -0.008730 0.207609 -0.060000 58 | v 0.007946 0.209069 -0.060000 59 | v 0.001406 0.212537 -0.060000 60 | v -0.004153 0.211625 -0.060000 61 | v -0.001373 0.212902 -0.060000 62 | v 0.012196 0.203228 -0.060000 63 | v -0.012490 0.201403 -0.060000 64 | v 0.015302 0.196292 -0.060000 65 | v -0.015597 0.194649 -0.060000 66 | v -0.019357 0.185523 -0.060000 67 | v 0.025275 0.168547 -0.060000 68 | v -0.029657 0.158509 -0.060000 69 | v -0.087695 -0.005038 -0.060000 70 | v 0.108327 -0.194686 -0.060000 71 | v 0.144621 -0.176981 -0.060000 72 | v 0.131215 -0.206368 -0.060000 73 | v 0.124185 -0.203082 -0.060000 74 | v 0.148381 -0.191035 -0.060000 75 | v 0.147237 -0.199067 -0.060000 76 | v 0.138899 -0.206368 -0.060000 77 | v 0.148381 -0.193956 -0.060000 78 | v 0.143967 -0.203812 -0.060000 79 | v 0.133995 -0.206915 -0.060000 80 | v -0.000883 -0.128975 -0.060000 81 | v -0.143117 -0.205820 -0.060000 82 | v -0.139520 -0.207098 -0.060000 83 | vn 0.0000 -0.0000 1.0000 84 | vn -0.0000 0.0000 -1.0000 85 | vn -0.5896 -0.8077 0.0000 86 | vn -0.8267 -0.5627 0.0000 87 | vn -0.9617 -0.2741 0.0000 88 | vn -1.0000 0.0000 0.0000 89 | vn -0.9481 0.3181 0.0000 90 | vn -0.9448 0.3277 0.0000 91 | vn -0.9424 0.3344 0.0000 92 | vn -0.9344 0.3563 0.0000 93 | vn -0.9246 0.3809 0.0000 94 | vn -0.9085 0.4179 0.0000 95 | vn -0.8553 0.5182 0.0000 96 | vn -0.6594 0.7518 0.0000 97 | vn -0.4177 0.9086 0.0000 98 | vn 0.1302 0.9915 0.0000 99 | vn 0.4685 0.8835 0.0000 100 | vn 0.7153 0.6989 0.0000 101 | vn 0.8586 0.5127 0.0000 102 | vn 0.9127 0.4087 0.0000 103 | vn 0.9411 0.3383 0.0000 104 | vn 0.9463 0.3233 0.0000 105 | vn 0.9436 0.3312 0.0000 106 | vn 0.9502 0.3117 0.0000 107 | vn 0.9660 0.2585 0.0000 108 | vn 0.9660 0.2584 0.0000 109 | vn 1.0000 0.0000 0.0000 110 | vn 0.9758 -0.2185 0.0000 111 | vn 0.8235 -0.5674 0.0000 112 | vn 0.4502 -0.8929 0.0000 113 | vn 0.1110 -0.9938 0.0000 114 | vn -0.1934 -0.9811 0.0000 115 | vn -0.4234 -0.9059 0.0000 116 | vn -0.4679 -0.8838 0.0000 117 | vn -0.4986 -0.8668 0.0000 118 | vn -0.5197 -0.8544 0.0000 119 | vn 0.5141 -0.8578 0.0000 120 | vn 0.4812 -0.8766 0.0000 121 | vn 0.4123 -0.9110 0.0000 122 | vn 0.3488 -0.9372 0.0000 123 | vn 0.0890 -0.9960 0.0000 124 | vn -0.3347 -0.9423 0.0000 125 | usemtl dfff00 126 | s 1 127 | f 1//1 2//1 3//1 128 | f 4//1 1//1 5//1 129 | f 1//1 3//1 5//1 130 | f 4//1 6//1 1//1 131 | f 7//1 8//1 9//1 132 | f 10//1 11//1 12//1 133 | f 13//1 14//1 15//1 134 | f 16//1 17//1 18//1 135 | f 18//1 17//1 13//1 136 | f 13//1 17//1 14//1 137 | f 15//1 14//1 19//1 138 | f 19//1 14//1 20//1 139 | f 21//1 19//1 20//1 140 | f 22//1 21//1 20//1 141 | f 22//1 23//1 21//1 142 | f 21//1 23//1 24//1 143 | f 24//1 23//1 25//1 144 | f 11//1 24//1 25//1 145 | f 26//1 11//1 25//1 146 | f 27//1 10//1 28//1 147 | f 29//1 30//1 31//1 148 | f 32//1 33//1 34//1 149 | f 34//1 33//1 35//1 150 | f 32//1 29//1 33//1 151 | f 33//1 29//1 36//1 152 | f 36//1 29//1 31//1 153 | f 29//1 27//1 30//1 154 | f 9//1 8//1 37//1 155 | f 30//1 27//1 28//1 156 | f 28//1 10//1 12//1 157 | f 12//1 11//1 37//1 158 | f 9//1 37//1 26//1 159 | f 37//1 11//1 26//1 160 | f 7//1 9//1 1//1 161 | f 6//1 7//1 1//1 162 | f 4//1 5//1 38//1 163 | f 39//1 4//1 38//1 164 | f 40//2 41//2 42//2 165 | f 43//2 42//2 44//2 166 | f 43//2 40//2 42//2 167 | f 42//2 45//2 44//2 168 | f 46//2 47//2 48//2 169 | f 49//2 50//2 51//2 170 | f 52//2 53//2 54//2 171 | f 55//2 56//2 57//2 172 | f 54//2 56//2 55//2 173 | f 53//2 56//2 54//2 174 | f 58//2 53//2 52//2 175 | f 59//2 53//2 58//2 176 | f 59//2 58//2 60//2 177 | f 59//2 60//2 61//2 178 | f 60//2 62//2 61//2 179 | f 63//2 62//2 60//2 180 | f 64//2 62//2 63//2 181 | f 64//2 63//2 50//2 182 | f 64//2 50//2 65//2 183 | f 66//2 51//2 67//2 184 | f 68//2 69//2 70//2 185 | f 71//2 72//2 73//2 186 | f 74//2 72//2 71//2 187 | f 72//2 70//2 73//2 188 | f 75//2 70//2 72//2 189 | f 68//2 70//2 75//2 190 | f 69//2 67//2 70//2 191 | f 76//2 47//2 46//2 192 | f 66//2 67//2 69//2 193 | f 49//2 51//2 66//2 194 | f 76//2 50//2 49//2 195 | f 65//2 76//2 46//2 196 | f 65//2 50//2 76//2 197 | f 42//2 46//2 48//2 198 | f 42//2 48//2 45//2 199 | f 77//2 43//2 44//2 200 | f 77//2 44//2 78//2 201 | f 5//3 77//3 38//3 202 | f 5//3 43//3 77//3 203 | f 3//4 43//4 5//4 204 | f 3//4 40//4 43//4 205 | f 2//5 40//5 3//5 206 | f 2//5 41//5 40//5 207 | f 1//6 41//6 2//6 208 | f 1//6 42//6 41//6 209 | f 9//7 42//7 1//7 210 | f 9//7 46//7 42//7 211 | f 26//8 46//8 9//8 212 | f 26//8 65//8 46//8 213 | f 25//9 65//9 26//9 214 | f 25//9 64//9 65//9 215 | f 23//10 64//10 25//10 216 | f 23//10 62//10 64//10 217 | f 22//11 62//11 23//11 218 | f 22//11 61//11 62//11 219 | f 20//12 61//12 22//12 220 | f 20//12 59//12 61//12 221 | f 14//13 59//13 20//13 222 | f 14//13 53//13 59//13 223 | f 17//14 53//14 14//14 224 | f 17//14 56//14 53//14 225 | f 16//15 56//15 17//15 226 | f 16//15 57//15 56//15 227 | f 18//16 57//16 16//16 228 | f 18//16 55//16 57//16 229 | f 13//17 55//17 18//17 230 | f 13//17 54//17 55//17 231 | f 15//18 54//18 13//18 232 | f 15//18 52//18 54//18 233 | f 19//19 52//19 15//19 234 | f 19//19 58//19 52//19 235 | f 21//20 58//20 19//20 236 | f 21//20 60//20 58//20 237 | f 24//21 60//21 21//21 238 | f 24//21 63//21 60//21 239 | f 11//22 63//22 24//22 240 | f 11//22 50//22 63//22 241 | f 10//23 50//23 11//23 242 | f 10//23 51//23 50//23 243 | f 27//24 51//24 10//24 244 | f 27//24 67//24 51//24 245 | f 29//25 67//26 27//25 246 | f 29//25 70//26 67//26 247 | f 32//27 70//27 29//27 248 | f 32//27 73//27 70//27 249 | f 34//28 73//28 32//28 250 | f 34//28 71//28 73//28 251 | f 35//29 71//29 34//29 252 | f 35//29 74//29 71//29 253 | f 33//30 74//30 35//30 254 | f 33//30 72//30 74//30 255 | f 36//31 72//31 33//31 256 | f 36//31 75//31 72//31 257 | f 31//32 75//32 36//32 258 | f 31//32 68//32 75//32 259 | f 30//33 68//33 31//33 260 | f 30//33 69//33 68//33 261 | f 28//34 69//34 30//34 262 | f 28//34 66//34 69//34 263 | f 12//35 66//35 28//35 264 | f 12//35 49//35 66//35 265 | f 37//36 49//36 12//36 266 | f 37//36 76//36 49//36 267 | f 8//37 76//37 37//37 268 | f 8//37 47//37 76//37 269 | f 7//38 47//38 8//38 270 | f 7//38 48//38 47//38 271 | f 6//39 48//39 7//39 272 | f 6//39 45//39 48//39 273 | f 4//40 45//40 6//40 274 | f 4//40 44//40 45//40 275 | f 39//41 44//41 4//41 276 | f 39//41 78//41 44//41 277 | f 38//42 78//42 39//42 278 | f 38//42 77//42 78//42 279 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/finish.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/finish.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/sneakers-25-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/sneakers-25-off.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/trigrid.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/trigrid.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/voucher-coffee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/voucher-coffee.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/models/white2x2pixels.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/ar/assets/models/white2x2pixels.png -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/ar_object.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelView; 17 | uniform mat4 u_ModelViewProjection; 18 | 19 | attribute vec4 a_Position; 20 | attribute vec3 a_Normal; 21 | attribute vec2 a_TexCoord; 22 | 23 | varying vec3 v_ViewPosition; 24 | varying vec3 v_ViewNormal; 25 | varying vec2 v_TexCoord; 26 | varying vec3 v_ScreenSpacePosition; 27 | 28 | void main() { 29 | v_ViewPosition = (u_ModelView * a_Position).xyz; 30 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz); 31 | v_TexCoord = a_TexCoord; 32 | gl_Position = u_ModelViewProjection * a_Position; 33 | v_ScreenSpacePosition = gl_Position.xyz / gl_Position.w; 34 | } 35 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/background_show_depth_color_visualization.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | 18 | uniform sampler2D u_DepthTexture; 19 | 20 | varying vec2 v_TexCoord; 21 | 22 | const highp float kMaxDepth = 8000.0; // In millimeters. 23 | 24 | float DepthGetMillimeters(in sampler2D depth_texture, in vec2 depth_uv) { 25 | // Depth is packed into the red and green components of its texture. 26 | // The texture is a normalized format, storing millimeters. 27 | vec3 packedDepthAndVisibility = texture2D(depth_texture, depth_uv).xyz; 28 | return dot(packedDepthAndVisibility.xy, vec2(255.0, 256.0 * 255.0)); 29 | } 30 | 31 | // Returns a color corresponding to the depth passed in. Colors range from red 32 | // to green to blue, where red is closest and blue is farthest. 33 | // 34 | // Uses Turbo color mapping: 35 | // https://ai.googleblog.com/2019/08/turbo-improved-rainbow-colormap-for.html 36 | vec3 DepthGetColorVisualization(in float x) { 37 | const vec4 kRedVec4 = vec4(0.55305649, 3.00913185, -5.46192616, -11.11819092); 38 | const vec4 kGreenVec4 = vec4(0.16207513, 0.17712472, 15.24091500, -36.50657960); 39 | const vec4 kBlueVec4 = vec4(-0.05195877, 5.18000081, -30.94853351, 81.96403246); 40 | const vec2 kRedVec2 = vec2(27.81927491, -14.87899417); 41 | const vec2 kGreenVec2 = vec2(25.95549545, -5.02738237); 42 | const vec2 kBlueVec2 = vec2(-86.53476570, 30.23299484); 43 | const float kInvalidDepthThreshold = 0.01; 44 | 45 | // Adjusts color space via 6 degree poly interpolation to avoid pure red. 46 | x = clamp(x * 0.9 + 0.03, 0.0, 1.0); 47 | vec4 v4 = vec4(1.0, x, x * x, x * x * x); 48 | vec2 v2 = v4.zw * v4.z; 49 | vec3 polynomial_color = vec3( 50 | dot(v4, kRedVec4) + dot(v2, kRedVec2), 51 | dot(v4, kGreenVec4) + dot(v2, kGreenVec2), 52 | dot(v4, kBlueVec4) + dot(v2, kBlueVec2) 53 | ); 54 | 55 | return step(kInvalidDepthThreshold, x) * polynomial_color; 56 | } 57 | 58 | void main() { 59 | highp float normalized_depth = 60 | clamp(DepthGetMillimeters(u_DepthTexture, v_TexCoord.xy) / kMaxDepth, 61 | 0.0, 1.0); 62 | vec4 depth_color = vec4(DepthGetColorVisualization(normalized_depth), 1.0); 63 | gl_FragColor = depth_color; 64 | } 65 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/background_show_depth_color_visualization.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | v_TexCoord = a_TexCoord; 23 | gl_Position = a_Position; 24 | } 25 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/border_effect.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | varying vec2 v_TexCoord; 3 | uniform sampler2D u_colorTexture; 4 | //uniform sampler2D u_depthTexture; 5 | uniform vec2 u_pixelDelta; 6 | 7 | #define BORDER_HALF_RADIUS 2 8 | const vec4 BORDER_COLOR = vec4(1,1,1,1); 9 | 10 | void main() { 11 | int nBg = 0; 12 | int nFg = 0; 13 | vec4 selfColor; 14 | float maxAlpha = 0.0; 15 | for (int i=-BORDER_HALF_RADIUS; i <= BORDER_HALF_RADIUS; ++i) { 16 | for (int j=-BORDER_HALF_RADIUS; j <= BORDER_HALF_RADIUS; ++j) { 17 | // circular filter.. slightly less lookups and slightly less heavy 18 | if (i*i + j*j <= BORDER_HALF_RADIUS*BORDER_HALF_RADIUS) { 19 | // TODO: rather compare depth buffers for a nicer effect 20 | vec4 col = texture2D(u_colorTexture, v_TexCoord + u_pixelDelta * vec2(i, j)); 21 | if (col.a < 0.01) { 22 | nBg += 1; 23 | } else { 24 | nFg += 1; 25 | } 26 | maxAlpha = max(col.a, maxAlpha); 27 | if (i == 0 && j == 0) selfColor = col; 28 | } 29 | } 30 | } 31 | 32 | //float borderness = float(min(nBg, nFg))/float(nFg+nBg) * 2.0; 33 | float borderness = 0.0; 34 | if (nBg != 0 && nFg != 0) borderness = 1.0; 35 | 36 | vec4 bcol = BORDER_COLOR; 37 | bcol.a = maxAlpha; 38 | gl_FragColor = borderness * bcol + (1.0 - borderness) * selfColor; 39 | } 40 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/floor_plan.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform sampler2D u_Texture; 4 | 5 | varying vec2 v_TexCoord; 6 | 7 | void main() { 8 | vec4 tex_color = texture2D(u_Texture, v_TexCoord); 9 | float alpha = min(0.8, tex_color.w); 10 | gl_FragColor = vec4(tex_color.xyz, alpha); 11 | } -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/floor_plan.vert: -------------------------------------------------------------------------------- 1 | uniform mat4 u_ModelViewProjection; 2 | 3 | attribute vec3 a_Position; // (x, y, z) 4 | attribute vec2 a_TexCoord; 5 | 6 | varying vec2 v_TexCoord; 7 | 8 | void main() { 9 | v_TexCoord = a_TexCoord; 10 | // no normal: don't care about shading 11 | gl_Position = u_ModelViewProjection * vec4(a_Position, 1.0); 12 | } 13 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/object.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | 18 | uniform sampler2D u_Texture; 19 | 20 | uniform vec4 u_LightingParameters; 21 | uniform vec4 u_MaterialParameters; 22 | uniform vec4 u_ColorCorrectionParameters; 23 | 24 | varying vec3 v_ViewPosition; 25 | varying vec3 v_ViewNormal; 26 | varying vec2 v_TexCoord; 27 | uniform vec4 u_ObjColor; 28 | 29 | void main() { 30 | // We support approximate sRGB gamma. 31 | const float kGamma = 0.4545454; 32 | const float kInverseGamma = 2.2; 33 | const float kMiddleGrayGamma = 0.466; 34 | 35 | // Unpack lighting and material parameters for better naming. 36 | vec3 viewLightDirection = u_LightingParameters.xyz; 37 | vec3 colorShift = u_ColorCorrectionParameters.rgb; 38 | float averagePixelIntensity = u_ColorCorrectionParameters.a; 39 | 40 | float materialAmbient = u_MaterialParameters.x; 41 | float materialDiffuse = u_MaterialParameters.y; 42 | float materialSpecular = u_MaterialParameters.z; 43 | float materialSpecularPower = u_MaterialParameters.w; 44 | 45 | // Normalize varying parameters, because they are linearly interpolated in the vertex shader. 46 | vec3 viewFragmentDirection = normalize(v_ViewPosition); 47 | vec3 viewNormal = normalize(v_ViewNormal); 48 | 49 | // Flip the y-texture coordinate to address the texture from top-left. 50 | vec4 objectColor = texture2D(u_Texture, vec2(v_TexCoord.x, 1.0 - v_TexCoord.y)); 51 | 52 | // Apply color to grayscale image only if the alpha of u_ObjColor is 53 | // greater and equal to 255.0. 54 | objectColor.rgb *= mix(vec3(1.0), u_ObjColor.rgb / 255.0, 55 | step(255.0, u_ObjColor.a)); 56 | 57 | // Apply inverse SRGB gamma to the texture before making lighting calculations. 58 | objectColor.rgb = pow(objectColor.rgb, vec3(kInverseGamma)); 59 | 60 | // Ambient light is unaffected by the light intensity. 61 | float ambient = materialAmbient; 62 | 63 | // Approximate a hemisphere light (not a harsh directional light). 64 | float diffuse = materialDiffuse * 65 | 0.5 * (dot(viewNormal, viewLightDirection) + 1.0); 66 | 67 | // Compute specular light. 68 | vec3 reflectedLightDirection = reflect(viewLightDirection, viewNormal); 69 | float specularStrength = max(0.0, dot(viewFragmentDirection, reflectedLightDirection)); 70 | float specular = materialSpecular * 71 | pow(specularStrength, materialSpecularPower); 72 | 73 | vec3 color = objectColor.rgb * (ambient + diffuse) + specular; 74 | // Apply SRGB gamma before writing the fragment color. 75 | color.rgb = pow(color, vec3(kGamma)); 76 | // Apply average pixel intensity and color shift 77 | color *= colorShift * (averagePixelIntensity / kMiddleGrayGamma); 78 | gl_FragColor.rgb = color; 79 | gl_FragColor.a = objectColor.a; 80 | } 81 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/object.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelView; 17 | uniform mat4 u_ModelViewProjection; 18 | 19 | attribute vec4 a_Position; 20 | attribute vec3 a_Normal; 21 | attribute vec2 a_TexCoord; 22 | 23 | varying vec3 v_ViewPosition; 24 | varying vec3 v_ViewNormal; 25 | varying vec2 v_TexCoord; 26 | 27 | void main() { 28 | v_ViewPosition = (u_ModelView * a_Position).xyz; 29 | v_ViewNormal = normalize((u_ModelView * vec4(a_Normal, 0.0)).xyz); 30 | v_TexCoord = a_TexCoord; 31 | gl_Position = u_ModelViewProjection * a_Position; 32 | } 33 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/plane.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision highp float; 17 | uniform sampler2D u_Texture; 18 | uniform vec4 u_dotColor; 19 | uniform vec4 u_lineColor; 20 | uniform vec4 u_gridControl; // dotThreshold, lineThreshold, lineFadeShrink, occlusionShrink 21 | varying vec3 v_TexCoordAlpha; 22 | 23 | void main() { 24 | vec4 control = texture2D(u_Texture, v_TexCoordAlpha.xy); 25 | float dotScale = v_TexCoordAlpha.z; 26 | float lineFade = max(0.0, u_gridControl.z * v_TexCoordAlpha.z - (u_gridControl.z - 1.0)); 27 | vec3 color = (control.r * dotScale > u_gridControl.x) ? u_dotColor.rgb 28 | : (control.g > u_gridControl.y) ? u_lineColor.rgb * lineFade 29 | : (u_lineColor.rgb * 0.25 * lineFade) ; 30 | gl_FragColor = vec4(color, v_TexCoordAlpha.z * u_gridControl.w); 31 | } 32 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/plane.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_Model; 17 | uniform mat4 u_ModelViewProjection; 18 | uniform mat2 u_PlaneUvMatrix; 19 | uniform vec3 u_Normal; 20 | 21 | attribute vec3 a_XZPositionAlpha; // (x, z, alpha) 22 | 23 | varying vec3 v_TexCoordAlpha; 24 | 25 | void main() { 26 | vec4 local_pos = vec4(a_XZPositionAlpha.x, 0.0, a_XZPositionAlpha.y, 1.0); 27 | vec4 world_pos = u_Model * local_pos; 28 | 29 | // Construct two vectors that are orthogonal to the normal. 30 | // This arbitrary choice is not co-linear with either horizontal 31 | // or vertical plane normals. 32 | const vec3 arbitrary = vec3(1.0, 1.0, 0.0); 33 | vec3 vec_u = normalize(cross(u_Normal, arbitrary)); 34 | vec3 vec_v = normalize(cross(u_Normal, vec_u)); 35 | 36 | // Project vertices in world frame onto vec_u and vec_v. 37 | vec2 uv = vec2(dot(world_pos.xyz, vec_u), dot(world_pos.xyz, vec_v)); 38 | v_TexCoordAlpha = vec3(u_PlaneUvMatrix * uv, a_XZPositionAlpha.z); 39 | gl_Position = u_ModelViewProjection * local_pos; 40 | } 41 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/point_cloud.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | precision mediump float; 17 | varying vec4 v_Color; 18 | 19 | void main() { 20 | gl_FragColor = v_Color; 21 | } 22 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/point_cloud.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | uniform mat4 u_ModelViewProjection; 17 | uniform vec4 u_Color; 18 | uniform float u_PointSize; 19 | 20 | attribute vec4 a_Position; 21 | 22 | varying vec4 v_Color; 23 | 24 | void main() { 25 | v_Color = u_Color; 26 | gl_Position = u_ModelViewProjection * vec4(a_Position.xyz, 1.0); 27 | gl_PointSize = u_PointSize; 28 | } 29 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/screenquad.frag: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | #extension GL_OES_EGL_image_external : require 16 | 17 | precision mediump float; 18 | varying vec2 v_TexCoord; 19 | uniform samplerExternalOES sTexture; 20 | 21 | 22 | void main() { 23 | gl_FragColor = vec4(texture2D(sTexture, v_TexCoord).rgb, 1.0); // force camera image alpha to 1 24 | } 25 | -------------------------------------------------------------------------------- /Basic/src/ar/assets/shaders/screenquad.vert: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | 16 | attribute vec4 a_Position; 17 | attribute vec2 a_TexCoord; 18 | 19 | varying vec2 v_TexCoord; 20 | 21 | void main() { 22 | gl_Position = a_Position; 23 | v_TexCoord = a_TexCoord; 24 | } 25 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/WayfindingSession.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.indooratlas.android.sdk.IAARSession; 6 | import com.indooratlas.android.sdk.IALocation; 7 | import com.indooratlas.android.sdk.IALocationListener; 8 | import com.indooratlas.android.sdk.IALocationManager; 9 | import com.indooratlas.android.sdk.IALocationRequest; 10 | import com.indooratlas.android.sdk.IAPOI; 11 | import com.indooratlas.android.sdk.IARegion; 12 | import com.indooratlas.android.sdk.IAARObject; 13 | import com.indooratlas.android.sdk.IAWayfindingListener; 14 | import com.indooratlas.android.sdk.IAWayfindingRequest; 15 | import com.indooratlas.android.sdk.examples.ar.wrapper.Api; 16 | import com.indooratlas.android.sdk.resources.IAVenue; 17 | 18 | import org.json.JSONException; 19 | import org.json.JSONObject; 20 | 21 | import java.util.ArrayList; 22 | import java.util.List; 23 | 24 | import timber.log.Timber; 25 | 26 | public class WayfindingSession implements IALocationListener, IARegion.Listener { 27 | private final IALocationManager locationManager; 28 | private final IAARSession arSdk; 29 | private final Callbacks callbacks; 30 | 31 | interface Callbacks { 32 | void onArPoisUpdated(List arPois); 33 | } 34 | 35 | public static class ArPOI { 36 | IAPOI iaPoi; 37 | double heading; 38 | double elevation; 39 | String textureName; 40 | float scale = 1f; 41 | } 42 | 43 | WayfindingSession(IALocationManager manager, Callbacks cbs) { 44 | this.callbacks = cbs; 45 | 46 | locationManager = manager; 47 | arSdk = locationManager.requestArUpdates(); 48 | 49 | locationManager.requestLocationUpdates(IALocationRequest.create(), this); 50 | locationManager.registerRegionListener(this); 51 | } 52 | 53 | void destroy() { 54 | arSdk.destroy(); 55 | locationManager.removeWayfindingUpdates(); 56 | locationManager.unregisterRegionListener(this); 57 | locationManager.removeLocationUpdates(this); 58 | } 59 | 60 | boolean converged() { 61 | return arSdk.converged(); 62 | } 63 | 64 | void onArFrame(float[] imuToWorld, float[] invViewMat, List planes) { 65 | arSdk.setPoseMatrix(imuToWorld); 66 | arSdk.setCameraToWorldMatrix(invViewMat); 67 | for (Api.HorizontalPlane plane : planes) { 68 | arSdk.addArPlane( 69 | plane.xyz, 70 | plane.extentX, 71 | plane.extentZ); 72 | } 73 | } 74 | 75 | IAARSession getArSdk() { 76 | return arSdk; 77 | } 78 | 79 | IALocationManager getLocationManager() { return locationManager; } 80 | 81 | List getWaypoints() { 82 | return arSdk.getWayfindingTurnArrows(); 83 | } 84 | 85 | public void setWayfindingTarget(IAWayfindingRequest wayfindingRequest) { 86 | if (wayfindingRequest != null) { 87 | Timber.i("Setting AR wayfinding target to %f,%f,%d", 88 | wayfindingRequest.getLatitude(), 89 | wayfindingRequest.getLongitude(), 90 | wayfindingRequest.getFloor()); 91 | arSdk.startWayfinding(wayfindingRequest); 92 | } 93 | } 94 | 95 | @Override 96 | public void onEnterRegion(IARegion region) { 97 | Timber.d("ENTER region %s", region.getName()); 98 | IAVenue venue = region.getVenue(); 99 | if (venue != null) { 100 | Timber.i("ENTER venue %s", venue.getName()); 101 | // update POIs 102 | List newArPois = new ArrayList<>(); 103 | int i = 0; 104 | for (IAPOI poi : venue.getPOIs()) { 105 | ArPOI arPoi = new ArPOI(); 106 | double elevation = 0.5; 107 | // use one FP by random to simplify -- usually they are the same for other 108 | // could perhaps match a bit more accurately with POI.floornumber --> fp.bearing 109 | double heading = venue.getFloorPlans().get(0).getBearing(); 110 | Timber.d("POI " + poi.getId() + ", heading: "+heading); 111 | elevation = 1; 112 | // use a default image for all POIS in Camera view -- useful for quick demos 113 | arPoi.textureName = "IA_AR_ad_framed.png"; 114 | arPoi.scale = 1; 115 | 116 | if (poi.getPayload() != null) { 117 | try { 118 | Timber.d(poi.getPayload().toString()); 119 | JSONObject arPayload = poi.getPayload().getJSONObject(""); 120 | if (arPayload == null) { 121 | Timber.d("POI " + poi.getId() + " does not have AR payload, " + 122 | "using default IA image"); 123 | } else { 124 | elevation = arPayload.getDouble("elevation"); 125 | heading = arPayload.getDouble("heading"); 126 | // NOTE: a potential security issue here. Should validate that the asset 127 | // exists and is not pointing to an illegal path here 128 | arPoi.textureName = arPayload.getString("assetName"); 129 | arPoi.scale = (float) arPayload.getDouble("scale"); 130 | } 131 | } catch (JSONException ex) { 132 | Timber.e("failed to parse AR payload, use default IA image"); 133 | } 134 | } 135 | 136 | arPoi.iaPoi = poi; 137 | arPoi.heading = heading; 138 | arPoi.elevation = elevation; 139 | 140 | newArPois.add(arPoi); 141 | } 142 | 143 | Timber.d("%s AR POI(s)", newArPois.size()); 144 | callbacks.onArPoisUpdated(newArPois); 145 | } 146 | } 147 | 148 | @Override 149 | public void onExitRegion(IARegion region) { 150 | } 151 | 152 | // TODO: should not be needed 153 | @Override 154 | public void onLocationChanged(IALocation location) { 155 | } 156 | 157 | @Override 158 | public void onStatusChanged(String provider, int status, Bundle extras) { 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/helpers/CameraPermissionHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.helpers; 16 | 17 | import android.Manifest; 18 | import android.app.Activity; 19 | import android.content.Intent; 20 | import android.content.pm.PackageManager; 21 | import android.net.Uri; 22 | import android.provider.Settings; 23 | import androidx.core.app.ActivityCompat; 24 | import androidx.core.content.ContextCompat; 25 | 26 | /** Helper to ask camera permission. */ 27 | public final class CameraPermissionHelper { 28 | private static final int CAMERA_PERMISSION_CODE = 0; 29 | private static final String CAMERA_PERMISSION = Manifest.permission.CAMERA; 30 | 31 | /** Check to see we have the necessary permissions for this app. */ 32 | public static boolean hasCameraPermission(Activity activity) { 33 | return ContextCompat.checkSelfPermission(activity, CAMERA_PERMISSION) 34 | == PackageManager.PERMISSION_GRANTED; 35 | } 36 | 37 | /** Check to see we have the necessary permissions for this app, and ask for them if we don't. */ 38 | public static void requestCameraPermission(Activity activity) { 39 | ActivityCompat.requestPermissions( 40 | activity, new String[] {CAMERA_PERMISSION}, CAMERA_PERMISSION_CODE); 41 | } 42 | 43 | /** Check to see if we need to show the rationale for this permission. */ 44 | public static boolean shouldShowRequestPermissionRationale(Activity activity) { 45 | return ActivityCompat.shouldShowRequestPermissionRationale(activity, CAMERA_PERMISSION); 46 | } 47 | 48 | /** Launch Application Setting to grant permission. */ 49 | public static void launchPermissionSettings(Activity activity) { 50 | Intent intent = new Intent(); 51 | intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); 52 | intent.setData(Uri.fromParts("package", activity.getPackageName(), null)); 53 | activity.startActivity(intent); 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/helpers/DisplayRotationHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.helpers; 16 | 17 | import android.content.Context; 18 | import android.hardware.camera2.CameraAccessException; 19 | import android.hardware.camera2.CameraCharacteristics; 20 | import android.hardware.camera2.CameraManager; 21 | import android.hardware.display.DisplayManager; 22 | import android.hardware.display.DisplayManager.DisplayListener; 23 | import android.view.Display; 24 | import android.view.Surface; 25 | import android.view.WindowManager; 26 | 27 | import com.indooratlas.android.sdk.examples.ar.wrapper.Api; 28 | 29 | /** 30 | * Helper to track the display rotations. In particular, the 180 degree rotations are not notified 31 | * by the onSurfaceChanged() callback, and thus they require listening to the android display 32 | * events. 33 | */ 34 | public final class DisplayRotationHelper implements DisplayListener { 35 | private boolean viewportChanged; 36 | private int viewportWidth; 37 | private int viewportHeight; 38 | private final Display display; 39 | private final DisplayManager displayManager; 40 | private final CameraManager cameraManager; 41 | 42 | /** 43 | * Constructs the DisplayRotationHelper but does not register the listener yet. 44 | * 45 | * @param context the Android {@link Context}. 46 | */ 47 | public DisplayRotationHelper(Context context) { 48 | displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE); 49 | cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE); 50 | WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); 51 | display = windowManager.getDefaultDisplay(); 52 | } 53 | 54 | /** Registers the display listener. Should be called from onResume */ 55 | public void onResume() { 56 | displayManager.registerDisplayListener(this, null); 57 | } 58 | 59 | /** Unregisters the display listener. Should be called from onPause */ 60 | public void onPause() { 61 | displayManager.unregisterDisplayListener(this); 62 | } 63 | 64 | /** 65 | * Records a change in surface dimensions. This will be later used by updateSessionIfNeeded. 66 | * Should be called from {@link 67 | * android.opengl.GLSurfaceView.Renderer 68 | * #onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)}. 69 | * 70 | * @param width the updated width of the surface. 71 | * @param height the updated height of the surface. 72 | */ 73 | public void onSurfaceChanged(int width, int height) { 74 | viewportWidth = width; 75 | viewportHeight = height; 76 | viewportChanged = true; 77 | } 78 | 79 | /** 80 | * Updates the session display geometry if a change was posted either by {@link 81 | * #onSurfaceChanged(int, int)} call or by {@link #onDisplayChanged(int)} system callback. This 82 | * function should be called explicitly before each call to onFrame. This 83 | * function will also clear the 'pending update' (viewportChanged) flag. 84 | * 85 | * @param session the Api object to update if display geometry changed. 86 | */ 87 | public void updateSessionIfNeeded(Api session) { 88 | if (viewportChanged) { 89 | int displayRotation = display.getRotation(); 90 | session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight); 91 | viewportChanged = false; 92 | } 93 | } 94 | 95 | /** 96 | * Returns the aspect ratio of the GL surface viewport while accounting for the display rotation 97 | * relative to the device camera sensor orientation. 98 | */ 99 | public float getCameraSensorRelativeViewportAspectRatio(String cameraId) { 100 | float aspectRatio; 101 | int cameraSensorToDisplayRotation = getCameraSensorToDisplayRotation(cameraId); 102 | switch (cameraSensorToDisplayRotation) { 103 | case 90: 104 | case 270: 105 | aspectRatio = (float) viewportHeight / (float) viewportWidth; 106 | break; 107 | case 0: 108 | case 180: 109 | aspectRatio = (float) viewportWidth / (float) viewportHeight; 110 | break; 111 | default: 112 | throw new RuntimeException("Unhandled rotation: " + cameraSensorToDisplayRotation); 113 | } 114 | return aspectRatio; 115 | } 116 | 117 | /** 118 | * Returns the rotation of the back-facing camera with respect to the display. The value is one of 119 | * 0, 90, 180, 270. 120 | */ 121 | public int getCameraSensorToDisplayRotation(String cameraId) { 122 | CameraCharacteristics characteristics; 123 | try { 124 | characteristics = cameraManager.getCameraCharacteristics(cameraId); 125 | } catch (CameraAccessException e) { 126 | throw new RuntimeException("Unable to determine display orientation", e); 127 | } 128 | 129 | // Camera sensor orientation. 130 | int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); 131 | 132 | // Current display orientation. 133 | int displayOrientation = toDegrees(display.getRotation()); 134 | 135 | // Make sure we return 0, 90, 180, or 270 degrees. 136 | return (sensorOrientation - displayOrientation + 360) % 360; 137 | } 138 | 139 | private int toDegrees(int rotation) { 140 | switch (rotation) { 141 | case Surface.ROTATION_0: 142 | return 0; 143 | case Surface.ROTATION_90: 144 | return 90; 145 | case Surface.ROTATION_180: 146 | return 180; 147 | case Surface.ROTATION_270: 148 | return 270; 149 | default: 150 | throw new RuntimeException("Unknown rotation " + rotation); 151 | } 152 | } 153 | 154 | @Override 155 | public void onDisplayAdded(int displayId) {} 156 | 157 | @Override 158 | public void onDisplayRemoved(int displayId) {} 159 | 160 | @Override 161 | public void onDisplayChanged(int displayId) { 162 | viewportChanged = true; 163 | } 164 | } 165 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/helpers/FullScreenHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.View; 19 | 20 | /** Helper to set up the Android full screen mode. */ 21 | public final class FullScreenHelper { 22 | /** 23 | * Sets the Android fullscreen flags. Expected to be called from {@link 24 | * Activity#onWindowFocusChanged(boolean hasFocus)}. 25 | * 26 | * @param activity the Activity on which the full screen mode will be set. 27 | * @param hasFocus the hasFocus flag passed from the {@link Activity#onWindowFocusChanged(boolean 28 | * hasFocus)} callback. 29 | */ 30 | public static void setFullScreenOnWindowFocusChanged(Activity activity, boolean hasFocus) { 31 | if (hasFocus) { 32 | // https://developer.android.com/training/system-ui/immersive.html#sticky 33 | activity 34 | .getWindow() 35 | .getDecorView() 36 | .setSystemUiVisibility( 37 | View.SYSTEM_UI_FLAG_LAYOUT_STABLE 38 | | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION 39 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN 40 | | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION 41 | | View.SYSTEM_UI_FLAG_FULLSCREEN 42 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/helpers/SnackbarHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.helpers; 16 | 17 | import android.app.Activity; 18 | import com.google.android.material.snackbar.BaseTransientBottomBar; 19 | import com.google.android.material.snackbar.Snackbar; 20 | import android.view.View; 21 | import android.widget.TextView; 22 | 23 | /** 24 | * Helper to manage the sample snackbar. Hides the Android boilerplate code, and exposes simpler 25 | * methods. 26 | */ 27 | public final class SnackbarHelper { 28 | private static final int BACKGROUND_COLOR = 0xbf323232; 29 | private Snackbar messageSnackbar; 30 | private enum DismissBehavior { HIDE, SHOW, FINISH }; 31 | private int maxLines = 2; 32 | private String lastMessage = ""; 33 | private View snackbarView; 34 | 35 | public boolean isShowing() { 36 | return messageSnackbar != null; 37 | } 38 | 39 | /** Shows a snackbar with a given message. */ 40 | public void showMessage(Activity activity, String message) { 41 | if (!message.isEmpty() && (!isShowing() || !lastMessage.equals(message))) { 42 | lastMessage = message; 43 | show(activity, message, DismissBehavior.HIDE); 44 | } 45 | } 46 | 47 | /** Shows a snackbar with a given message, and a dismiss button. */ 48 | public void showMessageWithDismiss(Activity activity, String message) { 49 | show(activity, message, DismissBehavior.SHOW); 50 | } 51 | 52 | /** 53 | * Shows a snackbar with a given error message. When dismissed, will finish the activity. Useful 54 | * for notifying errors, where no further interaction with the activity is possible. 55 | */ 56 | public void showError(Activity activity, String errorMessage) { 57 | show(activity, errorMessage, DismissBehavior.FINISH); 58 | } 59 | 60 | /** 61 | * Hides the currently showing snackbar, if there is one. Safe to call from any thread. Safe to 62 | * call even if snackbar is not shown. 63 | */ 64 | public void hide(Activity activity) { 65 | if (!isShowing()) { 66 | return; 67 | } 68 | lastMessage = ""; 69 | final Snackbar messageSnackbarToHide = messageSnackbar; 70 | messageSnackbar = null; 71 | activity.runOnUiThread( 72 | new Runnable() { 73 | @Override 74 | public void run() { 75 | messageSnackbarToHide.dismiss(); 76 | } 77 | }); 78 | } 79 | 80 | public void setMaxLines(int lines) { 81 | maxLines = lines; 82 | } 83 | 84 | /** 85 | * Sets the view that will be used to find a suitable parent view to hold the Snackbar view. 86 | * 87 | *

To use the root layout ({@link android.R.id.content}), pass in {@code null}. 88 | * 89 | * @param snackbarView the view to pass to {@link 90 | * com.google.android.material.snackbar.Snackbar#make(…)} which will be used to find a 91 | * suitable parent, which is a {@link androidx.coordinatorlayout.widget.CoordinatorLayout}, or 92 | * the window decor's content view, whichever comes first. 93 | */ 94 | public void setParentView(View snackbarView) { 95 | this.snackbarView = snackbarView; 96 | } 97 | 98 | private void show( 99 | final Activity activity, final String message, final DismissBehavior dismissBehavior) { 100 | activity.runOnUiThread( 101 | new Runnable() { 102 | @Override 103 | public void run() { 104 | messageSnackbar = 105 | Snackbar.make( 106 | snackbarView == null 107 | ? activity.findViewById(android.R.id.content) 108 | : snackbarView, 109 | message, 110 | Snackbar.LENGTH_INDEFINITE); 111 | messageSnackbar.getView().setBackgroundColor(BACKGROUND_COLOR); 112 | if (dismissBehavior != DismissBehavior.HIDE) { 113 | messageSnackbar.setAction( 114 | "Dismiss", 115 | new View.OnClickListener() { 116 | @Override 117 | public void onClick(View v) { 118 | messageSnackbar.dismiss(); 119 | } 120 | }); 121 | if (dismissBehavior == DismissBehavior.FINISH) { 122 | messageSnackbar.addCallback( 123 | new BaseTransientBottomBar.BaseCallback() { 124 | @Override 125 | public void onDismissed(Snackbar transientBottomBar, int event) { 126 | super.onDismissed(transientBottomBar, event); 127 | activity.finish(); 128 | } 129 | }); 130 | } 131 | } 132 | ((TextView) 133 | messageSnackbar 134 | .getView() 135 | .findViewById(com.google.android.material.R.id.snackbar_text)) 136 | .setMaxLines(maxLines); 137 | messageSnackbar.show(); 138 | } 139 | }); 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/helpers/TapHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.helpers; 16 | 17 | import android.content.Context; 18 | import android.view.GestureDetector; 19 | import android.view.MotionEvent; 20 | import android.view.View; 21 | import android.view.View.OnTouchListener; 22 | import java.util.concurrent.ArrayBlockingQueue; 23 | import java.util.concurrent.BlockingQueue; 24 | 25 | /** 26 | * Helper to detect taps using Android GestureDetector, and pass the taps between UI thread and 27 | * render thread. 28 | */ 29 | public final class TapHelper implements OnTouchListener { 30 | private final GestureDetector gestureDetector; 31 | private final BlockingQueue queuedSingleTaps = new ArrayBlockingQueue<>(16); 32 | 33 | /** 34 | * Creates the tap helper. 35 | * 36 | * @param context the application's context. 37 | */ 38 | public TapHelper(Context context) { 39 | gestureDetector = 40 | new GestureDetector( 41 | context, 42 | new GestureDetector.SimpleOnGestureListener() { 43 | @Override 44 | public boolean onSingleTapUp(MotionEvent e) { 45 | // Queue tap if there is space. Tap is lost if queue is full. 46 | queuedSingleTaps.offer(e); 47 | return true; 48 | } 49 | 50 | @Override 51 | public boolean onDown(MotionEvent e) { 52 | return true; 53 | } 54 | }); 55 | } 56 | 57 | /** 58 | * Polls for a tap. 59 | * 60 | * @return if a tap was queued, a MotionEvent for the tap. Otherwise null if no taps are queued. 61 | */ 62 | public MotionEvent poll() { 63 | return queuedSingleTaps.poll(); 64 | } 65 | 66 | @Override 67 | public boolean onTouch(View view, MotionEvent motionEvent) { 68 | return gestureDetector.onTouchEvent(motionEvent); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/helpers/TrackingStateHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2019 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.helpers; 16 | 17 | import android.app.Activity; 18 | import android.view.WindowManager; 19 | 20 | /** Gets human readibly tracking failure reasons and suggested actions. */ 21 | public final class TrackingStateHelper { 22 | public static final String INSUFFICIENT_FEATURES_MESSAGE = 23 | "Can't find anything. Aim device at a surface with more texture or color."; 24 | public static final String EXCESSIVE_MOTION_MESSAGE = "Moving too fast. Slow down."; 25 | public static final String INSUFFICIENT_LIGHT_MESSAGE = 26 | "Too dark. Try moving to a well-lit area."; 27 | public static final String BAD_STATE_MESSAGE = 28 | "Tracking lost due to bad internal state. Please try restarting the AR experience."; 29 | public static final String CAMERA_UNAVAILABLE_MESSAGE = 30 | "Another app is using the camera. Tap on this app or try closing the other one."; 31 | 32 | private final Activity activity; 33 | 34 | private boolean previousShouldBeOn; 35 | 36 | public TrackingStateHelper(Activity activity) { 37 | this.activity = activity; 38 | } 39 | 40 | /** Keep the screen unlocked while tracking, but allow it to lock when tracking stops. */ 41 | public void updateKeepScreenOnFlag(final boolean shouldBeOn) { 42 | if (shouldBeOn == previousShouldBeOn) { 43 | return; 44 | } 45 | 46 | previousShouldBeOn = shouldBeOn; 47 | activity.runOnUiThread( 48 | new Runnable() { 49 | @Override 50 | public void run() { 51 | if (shouldBeOn) { 52 | activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 53 | } else { 54 | activity.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); 55 | } 56 | } 57 | }); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/rendering/BitmapSignRenderer.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar.rendering; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.BitmapFactory; 7 | import android.opengl.Matrix; 8 | 9 | import java.io.IOException; 10 | import java.util.HashMap; 11 | import java.util.Map; 12 | 13 | public class BitmapSignRenderer extends BitmapRenderer { 14 | public static class Cache { 15 | private final Map store = new HashMap<>(); 16 | 17 | private static BitmapSignRenderer load(String assetName, Activity activity) { 18 | BitmapSignRenderer r = new BitmapSignRenderer(); 19 | try { 20 | // note load bitmaps synchronously, not optimal 21 | r.onBitmapReady(BitmapFactory.decodeStream( 22 | activity.getAssets().open("models/" + assetName))); 23 | } catch (IOException e) { 24 | throw new RuntimeException(e); 25 | } 26 | return r; 27 | } 28 | 29 | public BitmapSignRenderer get(String assetName, Activity activity) { 30 | if (store.containsKey(assetName)) { 31 | } else { 32 | store.put(assetName, load(assetName, activity)); 33 | } 34 | return store.get(assetName); 35 | } 36 | } 37 | 38 | private final float[][] cornerData = new float[4][3]; 39 | private final float[] tmpMatrix2 = new float[16]; 40 | private final float[] cornerMatrix = new float[] { 41 | 1, 0, 0, 0, 42 | 0, 1, 0, 0, 43 | 0, 0, 1, 0, 44 | 0, 0, 0, 1 }; 45 | 46 | private float aspectRatio; 47 | private boolean glInitialized = false; 48 | 49 | @Override 50 | public void createOnGlThread(Context context) { 51 | if (glInitialized) return; 52 | glInitialized = true; 53 | super.createOnGlThread(context); 54 | } 55 | 56 | public void draw(float[] cameraView, float[] cameraPerspective, float [] modelMatrix, float scale) { 57 | Matrix.multiplyMM(tmpMatrix2, 0, cameraView, 0, modelMatrix, 0); 58 | boolean flip = !isObjectZAxisFacingTheViewer(tmpMatrix2); 59 | 60 | for (int i = 0; i < 4; ++i) { 61 | float texX = QUAD_TEXCOORDS[2 * i]; 62 | float texY = QUAD_TEXCOORDS[2 * i + 1]; 63 | 64 | float relX = aspectRatio * (0.5f - texX); 65 | float relY = 1f - texY; 66 | 67 | // mirror along X if not facing the viewer 68 | if (flip) relX = -relX; 69 | 70 | cornerMatrix[4 * 3 + 0] = relX * scale; 71 | cornerMatrix[4 * 3 + 1] = relY * scale; 72 | Matrix.multiplyMM(tmpMatrix2, 0, modelMatrix, 0, cornerMatrix, 0); 73 | 74 | for (int j=0; j<3; ++j) { 75 | cornerData[i][j] = tmpMatrix2[4 * 3 + j]; 76 | } 77 | } 78 | 79 | draw(cameraView, cameraPerspective, cornerData); 80 | } 81 | 82 | void onBitmapReady(Bitmap bitmap) { 83 | setBitmap(bitmap); 84 | aspectRatio = ((float) bitmap.getWidth()) / bitmap.getHeight(); 85 | } 86 | 87 | private static boolean isObjectZAxisFacingTheViewer(float [] modelViewMatrix) { 88 | float dot = 0; 89 | // computes the dot product of: 90 | // a: the vector from the camera to the bitmap plane origin in camera coordinates, 91 | // which is stored in the first 3 elements of the 4th column of the model-view-matrix 92 | // b: the bitmap plane normal (local z-axis) in camera coordinates 93 | // which is the first 3 elements of the 3rd column of the model-view-matrix 94 | // The sign of this vector determines if the normal is facing the camera or not. 95 | for (int i = 0; i < 3; ++i) 96 | dot += modelViewMatrix[4 * 3 + i] * modelViewMatrix[4 * 2 + i]; 97 | // There are several sign flips involved here, e.g., projection matrix z-axis dir and 98 | // QUAD_TEXCOORDS configuration, and it's safe to pick the correct sign by trial and error 99 | return dot > 0; 100 | } 101 | } -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/rendering/ShaderUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.rendering; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLES20; 19 | import android.util.Log; 20 | import java.io.BufferedReader; 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | import java.io.InputStreamReader; 24 | import java.util.Map; 25 | import java.util.TreeMap; 26 | 27 | /** Shader helper functions. */ 28 | public class ShaderUtil { 29 | /** 30 | * Converts a raw text file, saved as a resource, into an OpenGL ES shader. 31 | * 32 | * @param type The type of shader we will be creating. 33 | * @param filename The filename of the asset file about to be turned into a shader. 34 | * @param defineValuesMap The #define values to add to the top of the shader source code. 35 | * @return The shader object handler. 36 | */ 37 | public static int loadGLShader( 38 | String tag, Context context, int type, String filename, Map defineValuesMap) 39 | throws IOException { 40 | // Load shader source code. 41 | String code = readShaderFileFromAssets(context, filename); 42 | 43 | // Prepend any #define values specified during this run. 44 | String defines = ""; 45 | for (Map.Entry entry : defineValuesMap.entrySet()) { 46 | defines += "#define " + entry.getKey() + " " + entry.getValue() + "\n"; 47 | } 48 | code = defines + code; 49 | 50 | // Compiles shader code. 51 | int shader = GLES20.glCreateShader(type); 52 | GLES20.glShaderSource(shader, code); 53 | GLES20.glCompileShader(shader); 54 | 55 | // Get the compilation status. 56 | final int[] compileStatus = new int[1]; 57 | GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); 58 | 59 | // If the compilation failed, delete the shader. 60 | if (compileStatus[0] == 0) { 61 | Log.e(tag, "Error compiling shader: " + GLES20.glGetShaderInfoLog(shader)); 62 | GLES20.glDeleteShader(shader); 63 | shader = 0; 64 | } 65 | 66 | if (shader == 0) { 67 | throw new RuntimeException("Error creating shader."); 68 | } 69 | 70 | return shader; 71 | } 72 | 73 | /** Overload of loadGLShader that assumes no additional #define values to add. */ 74 | public static int loadGLShader(String tag, Context context, int type, String filename) 75 | throws IOException { 76 | Map emptyDefineValuesMap = new TreeMap<>(); 77 | return loadGLShader(tag, context, type, filename, emptyDefineValuesMap); 78 | } 79 | 80 | /** 81 | * Checks if we've had an error inside of OpenGL ES, and if so what that error is. 82 | * 83 | * @param label Label to report in case of error. 84 | * @throws RuntimeException If an OpenGL error is detected. 85 | */ 86 | public static void checkGLError(String tag, String label) { 87 | int lastError = GLES20.GL_NO_ERROR; 88 | // Drain the queue of all errors. 89 | int error; 90 | while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { 91 | Log.e(tag, label + ": glError " + error); 92 | lastError = error; 93 | } 94 | if (lastError != GLES20.GL_NO_ERROR) { 95 | throw new RuntimeException(label + ": glError 0x" + String.format("%x", lastError)); 96 | } 97 | } 98 | 99 | // for AR Engine compatibility 100 | public static void checkGlError(String tag, String label) { 101 | checkGLError(tag, label); 102 | } 103 | 104 | /** 105 | * Converts a raw shader file into a string. 106 | * 107 | * @param filename The filename of the shader file about to be turned into a shader. 108 | * @return The context of the text file, or null in case of error. 109 | */ 110 | private static String readShaderFileFromAssets(Context context, String filename) 111 | throws IOException { 112 | try (InputStream inputStream = context.getAssets().open(filename); 113 | BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { 114 | StringBuilder sb = new StringBuilder(); 115 | String line; 116 | while ((line = reader.readLine()) != null) { 117 | String[] tokens = line.split(" ", -1); 118 | if (tokens[0].equals("#include")) { 119 | String includeFilename = tokens[1]; 120 | includeFilename = includeFilename.replace("\"", ""); 121 | if (includeFilename.equals(filename)) { 122 | throw new IOException("Do not include the calling file."); 123 | } 124 | sb.append(readShaderFileFromAssets(context, includeFilename)); 125 | } else { 126 | sb.append(line).append("\n"); 127 | } 128 | } 129 | return sb.toString(); 130 | } 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar/wrapper/Api.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar.wrapper; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | 6 | import com.indooratlas.android.sdk.examples.ar.rendering.ObjectRenderer; 7 | 8 | import java.io.IOException; 9 | import java.util.List; 10 | 11 | public interface Api { 12 | public interface ARAvailabilityCallback { 13 | void onARAvailability(boolean available); 14 | } 15 | 16 | class ResumeResult { 17 | public enum Status { 18 | SUCCESS, 19 | PENDING, 20 | ERROR 21 | }; 22 | public Status status; 23 | public String errorMessage; 24 | 25 | ResumeResult(Status status) { 26 | this.status = status; 27 | } 28 | 29 | ResumeResult(String errorMessage) { 30 | this.status = Status.ERROR; 31 | this.errorMessage = errorMessage; 32 | } 33 | } 34 | 35 | class HorizontalPlane { 36 | public float[] xyz; 37 | public float extentX, extentZ; 38 | } 39 | 40 | ResumeResult handleInstallFlowAndResume(Activity activity); 41 | boolean isRunning(); 42 | 43 | void pause(); 44 | 45 | void onFrame(); 46 | void renderPointCloud(float[] viewmtx, float[] projmtx); 47 | void renderPlanes(float[] projmtx); 48 | float[] getUpdatedUvTransformMatrix(); 49 | boolean getColorCorrection(float[] rgba); 50 | 51 | void getViewMatrix(float[] mat); // world-to-camea matrix 52 | void getProjectionMatrix(float[] mat, float nearClip, float farClip); 53 | 54 | // these are given to the IA AR SDK 55 | void getCameraToWorldMatrix(float[] mat); 56 | void getImuToWorldMatrix(float[] mat); 57 | List getHorizontalPlanes(); 58 | 59 | void onSurfaceCreated(Context context) throws IOException; 60 | void setupObject(Context context, ObjectRenderer obj) throws IOException; 61 | void setDisplayGeometry(int rot, int w, int h); 62 | 63 | // returns null if tracking 64 | String getTrackingFailureReasonString(); 65 | boolean shouldKeepScreenOn(); 66 | } -------------------------------------------------------------------------------- /Basic/src/arCore/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /Basic/src/arCore/java/com/indooratlas/android/sdk/examples/ar/rendering/PointCloudRenderer.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Google Inc. All Rights Reserved. 3 | * Licensed under the Apache License, Version 2.0 (the "License"); 4 | * you may not use this file except in compliance with the License. 5 | * You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software 10 | * distributed under the License is distributed on an "AS IS" BASIS, 11 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | * See the License for the specific language governing permissions and 13 | * limitations under the License. 14 | */ 15 | package com.indooratlas.android.sdk.examples.ar.rendering; 16 | 17 | import android.content.Context; 18 | import android.opengl.GLES20; 19 | import android.opengl.GLSurfaceView; 20 | import android.opengl.Matrix; 21 | import com.google.ar.core.PointCloud; 22 | import java.io.IOException; 23 | 24 | /** Renders a point cloud. */ 25 | public class PointCloudRenderer { 26 | private static final String TAG = PointCloud.class.getSimpleName(); 27 | 28 | // Shader names. 29 | private static final String VERTEX_SHADER_NAME = "shaders/point_cloud.vert"; 30 | private static final String FRAGMENT_SHADER_NAME = "shaders/point_cloud.frag"; 31 | 32 | private static final int BYTES_PER_FLOAT = Float.SIZE / 8; 33 | private static final int FLOATS_PER_POINT = 4; // X,Y,Z,confidence. 34 | private static final int BYTES_PER_POINT = BYTES_PER_FLOAT * FLOATS_PER_POINT; 35 | private static final int INITIAL_BUFFER_POINTS = 1000; 36 | 37 | private int vbo; 38 | private int vboSize; 39 | 40 | private int programName; 41 | private int positionAttribute; 42 | private int modelViewProjectionUniform; 43 | private int colorUniform; 44 | private int pointSizeUniform; 45 | 46 | private int numPoints = 0; 47 | 48 | // Keep track of the last point cloud rendered to avoid updating the VBO if point cloud 49 | // was not changed. Do this using the timestamp since we can't compare PointCloud objects. 50 | private long lastTimestamp = 0; 51 | 52 | public PointCloudRenderer() {} 53 | 54 | /** 55 | * Allocates and initializes OpenGL resources needed by the plane renderer. Must be called on the 56 | * OpenGL thread, typically in {@link GLSurfaceView.Renderer#onSurfaceCreated(GL10, EGLConfig)}. 57 | * 58 | * @param context Needed to access shader source. 59 | */ 60 | public void createOnGlThread(Context context) throws IOException { 61 | ShaderUtil.checkGLError(TAG, "before create"); 62 | 63 | int[] buffers = new int[1]; 64 | GLES20.glGenBuffers(1, buffers, 0); 65 | vbo = buffers[0]; 66 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo); 67 | 68 | vboSize = INITIAL_BUFFER_POINTS * BYTES_PER_POINT; 69 | GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vboSize, null, GLES20.GL_DYNAMIC_DRAW); 70 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 71 | 72 | ShaderUtil.checkGLError(TAG, "buffer alloc"); 73 | 74 | int vertexShader = 75 | ShaderUtil.loadGLShader(TAG, context, GLES20.GL_VERTEX_SHADER, VERTEX_SHADER_NAME); 76 | int passthroughShader = 77 | ShaderUtil.loadGLShader(TAG, context, GLES20.GL_FRAGMENT_SHADER, FRAGMENT_SHADER_NAME); 78 | 79 | programName = GLES20.glCreateProgram(); 80 | GLES20.glAttachShader(programName, vertexShader); 81 | GLES20.glAttachShader(programName, passthroughShader); 82 | GLES20.glLinkProgram(programName); 83 | GLES20.glUseProgram(programName); 84 | 85 | ShaderUtil.checkGLError(TAG, "program"); 86 | 87 | positionAttribute = GLES20.glGetAttribLocation(programName, "a_Position"); 88 | colorUniform = GLES20.glGetUniformLocation(programName, "u_Color"); 89 | modelViewProjectionUniform = GLES20.glGetUniformLocation(programName, "u_ModelViewProjection"); 90 | pointSizeUniform = GLES20.glGetUniformLocation(programName, "u_PointSize"); 91 | 92 | ShaderUtil.checkGLError(TAG, "program params"); 93 | } 94 | 95 | /** 96 | * Updates the OpenGL buffer contents to the provided point. Repeated calls with the same point 97 | * cloud will be ignored. 98 | */ 99 | public void update(PointCloud cloud) { 100 | if (cloud.getTimestamp() == lastTimestamp) { 101 | // Redundant call. 102 | return; 103 | } 104 | ShaderUtil.checkGLError(TAG, "before update"); 105 | 106 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo); 107 | lastTimestamp = cloud.getTimestamp(); 108 | 109 | // If the VBO is not large enough to fit the new point cloud, resize it. 110 | numPoints = cloud.getPoints().remaining() / FLOATS_PER_POINT; 111 | if (numPoints * BYTES_PER_POINT > vboSize) { 112 | while (numPoints * BYTES_PER_POINT > vboSize) { 113 | vboSize *= 2; 114 | } 115 | GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, vboSize, null, GLES20.GL_DYNAMIC_DRAW); 116 | } 117 | GLES20.glBufferSubData( 118 | GLES20.GL_ARRAY_BUFFER, 0, numPoints * BYTES_PER_POINT, cloud.getPoints()); 119 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 120 | 121 | ShaderUtil.checkGLError(TAG, "after update"); 122 | } 123 | 124 | /** 125 | * Renders the point cloud. ARCore point cloud is given in world space. 126 | * 127 | * @param cameraView the camera view matrix for this frame, typically from {@link 128 | * com.google.ar.core.Camera#getViewMatrix(float[], int)}. 129 | * @param cameraPerspective the camera projection matrix for this frame, typically from {@link 130 | * com.google.ar.core.Camera#getProjectionMatrix(float[], int, float, float)}. 131 | */ 132 | public void draw(float[] cameraView, float[] cameraPerspective) { 133 | float[] modelViewProjection = new float[16]; 134 | Matrix.multiplyMM(modelViewProjection, 0, cameraPerspective, 0, cameraView, 0); 135 | 136 | ShaderUtil.checkGLError(TAG, "Before draw"); 137 | 138 | GLES20.glUseProgram(programName); 139 | GLES20.glEnableVertexAttribArray(positionAttribute); 140 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, vbo); 141 | GLES20.glVertexAttribPointer(positionAttribute, 4, GLES20.GL_FLOAT, false, BYTES_PER_POINT, 0); 142 | GLES20.glUniform4f(colorUniform, 31.0f / 255.0f, 188.0f / 255.0f, 210.0f / 255.0f, 1.0f); 143 | GLES20.glUniformMatrix4fv(modelViewProjectionUniform, 1, false, modelViewProjection, 0); 144 | GLES20.glUniform1f(pointSizeUniform, 5.0f); 145 | 146 | GLES20.glDrawArrays(GLES20.GL_POINTS, 0, numPoints); 147 | GLES20.glDisableVertexAttribArray(positionAttribute); 148 | GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0); 149 | 150 | ShaderUtil.checkGLError(TAG, "Draw"); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /Basic/src/arCore/java/com/indooratlas/android/sdk/examples/ar/rendering/Texture.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020 Google Inc. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.indooratlas.android.sdk.examples.ar.rendering; 18 | 19 | import static android.opengl.GLES20.GL_CLAMP_TO_EDGE; 20 | import static android.opengl.GLES20.GL_TEXTURE_2D; 21 | import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER; 22 | import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER; 23 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_S; 24 | import static android.opengl.GLES20.GL_TEXTURE_WRAP_T; 25 | import static android.opengl.GLES20.GL_UNSIGNED_BYTE; 26 | import static android.opengl.GLES20.glBindTexture; 27 | import static android.opengl.GLES20.glGenTextures; 28 | import static android.opengl.GLES20.glTexImage2D; 29 | import static android.opengl.GLES20.glTexParameteri; 30 | import static android.opengl.GLES30.GL_LINEAR; 31 | import static android.opengl.GLES30.GL_RG; 32 | import static android.opengl.GLES30.GL_RG8; 33 | 34 | import android.media.Image; 35 | import com.google.ar.core.Frame; 36 | import com.google.ar.core.exceptions.NotYetAvailableException; 37 | 38 | /** Handle the creation and update of a GPU texture. */ 39 | public final class Texture { 40 | // Stores the latest provided texture id. 41 | private int textureId = -1; 42 | private int width = -1; 43 | private int height = -1; 44 | 45 | /** 46 | * Creates and initializes the texture. This method needs to be called on a thread with a EGL 47 | * context attached. 48 | */ 49 | public void createOnGlThread() { 50 | int[] textureIdArray = new int[1]; 51 | glGenTextures(1, textureIdArray, 0); 52 | textureId = textureIdArray[0]; 53 | glBindTexture(GL_TEXTURE_2D, textureId); 54 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 55 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 56 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 57 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 58 | } 59 | 60 | /** 61 | * Updates the texture with the content from acquireDepthImage, which provides an image in DEPTH16 62 | * format, representing each pixel as a depth measurement in millimeters. This method needs to be 63 | * called on a thread with a EGL context attached. 64 | */ 65 | public void updateWithDepthImageOnGlThread(final Frame frame) { 66 | try { 67 | Image depthImage = frame.acquireDepthImage(); 68 | width = depthImage.getWidth(); 69 | height = depthImage.getHeight(); 70 | glBindTexture(GL_TEXTURE_2D, textureId); 71 | glTexImage2D( 72 | GL_TEXTURE_2D, 73 | 0, 74 | GL_RG8, 75 | width, 76 | height, 77 | 0, 78 | GL_RG, 79 | GL_UNSIGNED_BYTE, 80 | depthImage.getPlanes()[0].getBuffer()); 81 | depthImage.close(); 82 | } catch (NotYetAvailableException e) { 83 | // This normally means that depth data is not available yet. This is normal so we will not 84 | // spam the logcat with this. 85 | } 86 | } 87 | 88 | public int getTextureId() { 89 | return textureId; 90 | } 91 | 92 | public int getWidth() { 93 | return width; 94 | } 95 | 96 | public int getHeight() { 97 | return height; 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Basic/src/arCore/java/com/indooratlas/android/sdk/examples/ar/wrapper/Implementation.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar.wrapper; 2 | 3 | import android.content.Context; 4 | import android.os.Handler; 5 | 6 | import com.google.ar.core.ArCoreApk; 7 | import com.indooratlas.android.sdk.examples.ar.wrapper.Api; 8 | import com.indooratlas.android.sdk.examples.ar.wrapper.ArCore; 9 | 10 | public class Implementation { 11 | public static Api createArWrapper() { 12 | return new ArCore(); 13 | } 14 | 15 | public static void checkArAvailability(final Context context, final Api.ARAvailabilityCallback callback) { 16 | ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(context); 17 | if (availability.isTransient()) { 18 | // (This is directly from Google's example code) 19 | // Re-query at 5Hz while compatibility is checked in the background. 20 | new Handler().postDelayed(new Runnable() { 21 | @Override 22 | public void run() { 23 | checkArAvailability(context, callback); 24 | } 25 | }, 200); 26 | } 27 | if (availability.isSupported()) { 28 | callback.onARAvailability(true); 29 | } else { // Unsupported or unknown. 30 | callback.onARAvailability(false); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Basic/src/arCore/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | This application runs on Google Play Services for AR (ARCore), 3 | which is provided by Google LLC and governed by the Google Privacy Policy. 4 | -------------------------------------------------------------------------------- /Basic/src/arEngine/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 10 | 11 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /Basic/src/arEngine/java/com/indooratlas/android/sdk/examples/ar/wrapper/ConnectAppMarketActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // From https://github.com/HMS-Core/hms-AREngine-demo/blob/154298691a83df37da7189b4b5b9f073fa773051/HwAREngineDemo/src/main/java/com/huawei/arengine/demos/common/ConnectAppMarketActivity.java 17 | // IndoorAtlas: package names changed 18 | package com.indooratlas.android.sdk.examples.ar.wrapper; 19 | 20 | import android.app.Activity; 21 | import android.app.AlertDialog; 22 | import android.content.ActivityNotFoundException; 23 | import android.content.DialogInterface; 24 | import android.content.Intent; 25 | import android.os.Bundle; 26 | import android.util.Log; 27 | 28 | import com.indooratlas.android.sdk.examples.R; 29 | import com.huawei.hiar.exceptions.ARFatalException; 30 | 31 | /** 32 | * This activity is used to redirect the user to AppGallery and install the AR Engine server. 33 | * This activity is called when the AR Engine is not installed. 34 | * 35 | * @author HW 36 | * @since 2020-03-31 37 | */ 38 | public class ConnectAppMarketActivity extends Activity { 39 | private static final String TAG = ConnectAppMarketActivity.class.getSimpleName(); 40 | 41 | private static final String ACTION_HUAWEI_DOWNLOAD_QUIK = "com.huawei.appmarket.intent.action.AppDetail"; 42 | 43 | private static final String HUAWEI_MARTKET_NAME = "com.huawei.appmarket"; 44 | 45 | private static final String PACKAGE_NAME_KEY = "APP_PACKAGENAME"; 46 | 47 | private static final String PACKAGENAME_ARSERVICE = "com.huawei.arengine.service"; 48 | 49 | private AlertDialog.Builder dialog; 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | setContentView(R.layout.activity_connection_app_market); 55 | showSuggestiveDialog(); 56 | } 57 | 58 | @Override 59 | protected void onResume() { 60 | if (dialog != null) { 61 | Log.d(TAG, "show dialog."); 62 | dialog.show(); 63 | } 64 | super.onResume(); 65 | } 66 | 67 | private void showSuggestiveDialog() { 68 | Log.d(TAG, "Show education dialog."); 69 | dialog = new AlertDialog.Builder(this); 70 | showAppMarket(); 71 | } 72 | 73 | private void showAppMarket() { 74 | dialog.setMessage(R.string.arengine_install_app); 75 | dialog.setNegativeButton(R.string.arengine_cancel, new DialogInterface.OnClickListener() { 76 | @Override 77 | public void onClick(DialogInterface dialogInterface, int i) { 78 | Log.d(TAG, "Show education showAppMarket123."); 79 | finish(); 80 | } 81 | }); 82 | dialog.setPositiveButton(R.string.arengine_install, new DialogInterface.OnClickListener() { 83 | @Override 84 | public void onClick(DialogInterface dialogInterface, int i) { 85 | try { 86 | Log.d(TAG, "arengine_install onClick."); 87 | downLoadArServiceApp(); 88 | finish(); 89 | } catch (ActivityNotFoundException e) { 90 | throw new ARFatalException("Failed to launch ARInstallActivity"); 91 | } 92 | } 93 | }); 94 | dialog.setOnCancelListener(new DialogInterface.OnCancelListener() { 95 | @Override 96 | public void onCancel(DialogInterface dialogInterface) { 97 | finish(); 98 | } 99 | }); 100 | } 101 | 102 | private void downLoadArServiceApp() { 103 | try { 104 | Intent intent = new Intent(ACTION_HUAWEI_DOWNLOAD_QUIK); 105 | intent.putExtra(PACKAGE_NAME_KEY, PACKAGENAME_ARSERVICE); 106 | intent.setPackage(HUAWEI_MARTKET_NAME); 107 | intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 108 | startActivity(intent); 109 | } catch (SecurityException e) { 110 | Log.w(TAG, "the target app has no permission of media"); 111 | } catch (ActivityNotFoundException e) { 112 | Log.w(TAG, "the target activity is not found: " + e.getMessage()); 113 | } 114 | } 115 | } -------------------------------------------------------------------------------- /Basic/src/arEngine/java/com/indooratlas/android/sdk/examples/ar/wrapper/Implementation.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar.wrapper; 2 | import android.content.Context; 3 | 4 | public class Implementation { 5 | public static Api createArWrapper() { 6 | return new ArEngine(); 7 | } 8 | 9 | public static void checkArAvailability(final Context context, final Api.ARAvailabilityCallback callback) { 10 | callback.onARAvailability(true); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /Basic/src/arEngine/java/com/indooratlas/android/sdk/examples/ar/wrapper/MatrixUtil.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2020. Huawei Technologies Co., Ltd. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | // From https://github.com/HMS-Core/hms-AREngine-demo/blob/154298691a83df37da7189b4b5b9f073fa773051/HwAREngineDemo/src/main/java/com/huawei/arengine/demos/common/MatrixUtil.java 17 | // IndoorAtlas: package name changed 18 | 19 | package com.indooratlas.android.sdk.examples.ar.wrapper; 20 | 21 | import android.opengl.Matrix; 22 | 23 | /** 24 | * Matrix utility class. 25 | * 26 | * @author HW 27 | * @since 2020-03-29 28 | */ 29 | public class MatrixUtil { 30 | private static final int MATRIX_SIZE = 16; 31 | 32 | private MatrixUtil() { 33 | } 34 | 35 | /** 36 | * Get the matrix of a specified type. 37 | * 38 | * @param matrix Results of matrix obtained. 39 | * @param width Width. 40 | * @param height Height. 41 | */ 42 | public static void getProjectionMatrix(float[] matrix, int width, int height) { 43 | if (height > 0 && width > 0) { 44 | float[] projection = new float[MATRIX_SIZE]; 45 | float[] camera = new float[MATRIX_SIZE]; 46 | 47 | // Calculate the orthographic projection matrix. 48 | Matrix.orthoM(projection, 0, -1, 1, -1, 1, 1, 3); 49 | Matrix.setLookAtM(camera, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0); 50 | Matrix.multiplyMM(matrix, 0, projection, 0, camera, 0); 51 | } 52 | } 53 | 54 | /** 55 | * Three-dimensional data standardization method, which divides each 56 | * number by the root of the sum of squares of all numbers. 57 | * 58 | * @param vector Three-dimensional vector. 59 | */ 60 | public static void normalizeVec3(float[] vector) { 61 | // This data has three dimensions(0,1,2) 62 | float length = 1.0f / (float) Math.sqrt(vector[0] * vector[0] + vector[1] * vector[1] + vector[2] * vector[2]); 63 | vector[0] *= length; 64 | vector[1] *= length; 65 | vector[2] *= length; 66 | } 67 | 68 | /** 69 | * Provide a 4 * 4 unit matrix. 70 | * 71 | * @return Returns matrix as an array. 72 | */ 73 | public static float[] getOriginalMatrix() { 74 | return new float[] {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; 75 | } 76 | } -------------------------------------------------------------------------------- /Basic/src/arEngine/res/layout/activity_connection_app_market.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | -------------------------------------------------------------------------------- /Basic/src/arEngine/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | CANCEL 3 | INSTALL 4 | Install the latest version of HUAWEI AR Engine to continue. 5 | 6 | This application uses Huawei AR Engine. 7 | -------------------------------------------------------------------------------- /Basic/src/lite/java/com/indooratlas/android/sdk/examples/ar/ThirdPartyAr.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar; 2 | 3 | // dummy class for non-AR build 4 | public class ThirdPartyAr {} 5 | -------------------------------------------------------------------------------- /Basic/src/lite/java/com/indooratlas/android/sdk/examples/ar/WayfindingAr.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar; 2 | 3 | // dummy class for non-AR build 4 | public class WayfindingAr {} 5 | -------------------------------------------------------------------------------- /Basic/src/lite/java/com/indooratlas/android/sdk/examples/ar/wrapper/Api.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar.wrapper; 2 | 3 | public interface Api { 4 | public interface ARAvailabilityCallback { 5 | void onARAvailability(boolean available); 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /Basic/src/lite/java/com/indooratlas/android/sdk/examples/ar/wrapper/Implementation.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.ar.wrapper; 2 | 3 | import com.indooratlas.android.sdk.examples.ar.wrapper.Api; 4 | 5 | public class Implementation { 6 | public static void checkArAvailability(Object contextUnused, Api.ARAvailabilityCallback callback) { 7 | callback.onARAvailability(false); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /Basic/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 27 | 30 | 33 | 36 | 39 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 53 | 57 | 61 | 64 | 68 | 72 | 76 | 80 | 81 | 84 | 85 | 89 | 90 | 91 | 95 | 96 | 100 | 103 | 104 | 108 | 109 | 114 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/SdkExample.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples; 2 | 3 | import androidx.annotation.StringRes; 4 | 5 | import java.lang.annotation.ElementType; 6 | import java.lang.annotation.Retention; 7 | import java.lang.annotation.RetentionPolicy; 8 | import java.lang.annotation.Target; 9 | 10 | /** 11 | * Activities tagged with this annotation are listed in the main view as examples. 12 | */ 13 | @Retention(RetentionPolicy.RUNTIME) 14 | @Target(ElementType.TYPE) 15 | public @interface SdkExample { 16 | 17 | /** 18 | * Resource identifier that's content will be shown in first line in examples list entry. If 19 | * not set, activity's label will be used. 20 | */ 21 | @StringRes int title() default -1; 22 | 23 | /** 24 | * Resource identified that's content will be shown on second line in examples list entry. 25 | * Describes what the example is showcasing. 26 | */ 27 | @StringRes int description(); 28 | 29 | } 30 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/credentials/CredentialsFromCodeActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | */ 4 | package com.indooratlas.android.sdk.examples.credentials; 5 | 6 | import android.content.Context; 7 | import android.os.Bundle; 8 | import androidx.appcompat.app.AppCompatActivity; 9 | import android.widget.TextView; 10 | 11 | import com.indooratlas.android.sdk.IALocation; 12 | import com.indooratlas.android.sdk.IALocationListener; 13 | import com.indooratlas.android.sdk.IALocationManager; 14 | import com.indooratlas.android.sdk.IALocationRequest; 15 | import com.indooratlas.android.sdk.examples.R; 16 | import com.indooratlas.android.sdk.examples.SdkExample; 17 | 18 | import java.util.Locale; 19 | 20 | /** 21 | * There are two ways of setting credentials: 22 | *

    23 | *
  • a) specifying as meta-data in AndroidManifest.xml
  • 24 | *
  • b) passing in as extra parameters via{@link IALocationManager#create(Context, Bundle)}
  • 25 | *
26 | * This example demonstrates option b). 27 | */ 28 | @SdkExample(description = R.string.example_credentials_description) 29 | public class CredentialsFromCodeActivity extends AppCompatActivity implements IALocationListener { 30 | 31 | private IALocationManager mLocationManager; 32 | private TextView mLog; 33 | 34 | @SuppressWarnings("unchecked") 35 | @Override 36 | public void onCreate(Bundle savedInstanceState) { 37 | super.onCreate(savedInstanceState); 38 | setContentView(R.layout.text_only); 39 | mLog = (TextView) findViewById(R.id.text); 40 | 41 | Bundle extras = new Bundle(2); 42 | extras.putString(IALocationManager.EXTRA_API_KEY, 43 | getString(R.string.indooratlas_api_key)); 44 | extras.putString(IALocationManager.EXTRA_API_SECRET, 45 | getString(R.string.indooratlas_api_secret)); 46 | mLocationManager = IALocationManager.create(this, extras); 47 | 48 | } 49 | 50 | @Override 51 | protected void onDestroy() { 52 | super.onDestroy(); 53 | mLocationManager.destroy(); 54 | } 55 | 56 | @Override 57 | protected void onResume() { 58 | super.onResume(); 59 | mLocationManager.requestLocationUpdates(IALocationRequest.create(), this); 60 | } 61 | 62 | @Override 63 | protected void onPause() { 64 | super.onPause(); 65 | mLocationManager.removeLocationUpdates(this); 66 | } 67 | 68 | @Override 69 | public void onLocationChanged(IALocation location) { 70 | log(String.format(Locale.US, "%f,%f, accuracy: %.2f", location.getLatitude(), 71 | location.getLongitude(), location.getAccuracy())); 72 | } 73 | 74 | @Override 75 | public void onStatusChanged(String provider, int status, Bundle extras) { 76 | log("onStatusChanged: " + status); 77 | } 78 | 79 | private void log(String msg) { 80 | mLog.append("\n" + msg); 81 | } 82 | 83 | } 84 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/foregroundservice/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.foregroundservice; 2 | 3 | import android.app.NotificationManager; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import androidx.core.app.ActivityCompat; 7 | import androidx.appcompat.app.AppCompatActivity; 8 | import android.os.Bundle; 9 | import android.util.Log; 10 | import android.view.View; 11 | import android.widget.Button; 12 | 13 | import com.indooratlas.android.sdk.examples.R; 14 | import com.indooratlas.android.sdk.examples.SdkExample; 15 | 16 | @SdkExample(description = R.string.example_foregroundservice_description) 17 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 18 | 19 | private String TAG = "ForeGroundServiceExample/MainActivity"; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_foreground); 25 | 26 | Button startButton = findViewById(R.id.button1); 27 | Button stopButton = findViewById(R.id.button2); 28 | 29 | // Start foreground service will create persistent notification with the "Start" and "Stop" 30 | // buttons for positioning 31 | startButton.setOnClickListener(this); 32 | stopButton.setOnClickListener(this); 33 | } 34 | 35 | public void onResume() { 36 | super.onResume(); 37 | Log.d(TAG, "onResume"); 38 | 39 | // Check if notifications are enabled for my app. 40 | // Needed to show IA positioning updates in the notification aka Action bar. 41 | NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); 42 | boolean areNotificationsEnabled = notificationManager.areNotificationsEnabled(); 43 | 44 | Log.d(TAG, "onResume, areNotificationsEnabled : "+areNotificationsEnabled); 45 | 46 | if (!areNotificationsEnabled) { 47 | // Notifications are disabled for your app. You might want to notify the user or take appropriate action. 48 | Intent intent = new Intent(); 49 | intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS"); 50 | intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName()); 51 | startActivity(intent); 52 | } 53 | } 54 | 55 | 56 | @Override 57 | public void onClick(View v) { 58 | switch (v.getId()) { 59 | case R.id.button1: 60 | Log.d(TAG, "Starting Foreground Service with Intent"); 61 | // After starting the foreground service, you can close the example app and continue 62 | // using the foreground service notification 63 | Intent startIntent = new Intent(MainActivity.this, ForegroundService.class); 64 | startIntent.setAction(ForegroundService.STARTFOREGROUND_ACTION); 65 | startService(startIntent); 66 | break; 67 | case R.id.button2: 68 | Log.d(TAG, "Stopping Foreground Service with Intent"); 69 | // To close the foreground service, "Stop foreground service" button must be pressed 70 | Intent stopIntent = new Intent(MainActivity.this, ForegroundService.class); 71 | stopIntent.setAction(ForegroundService.STOPFOREGROUND_ACTION); 72 | startService(stopIntent); 73 | break; 74 | 75 | default: 76 | break; 77 | } 78 | 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/imageview/BlueDotView.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.imageview; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Paint; 6 | import android.graphics.Path; 7 | import android.graphics.PointF; 8 | import android.util.AttributeSet; 9 | import android.util.Log; 10 | 11 | import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView; 12 | import com.indooratlas.android.sdk.examples.R; 13 | 14 | /** 15 | * Extends great ImageView library by Dave Morrissey. See more: 16 | * https://github.com/davemorrissey/subsampling-scale-image-view. 17 | */ 18 | public class BlueDotView extends SubsamplingScaleImageView { 19 | 20 | private float uncertaintyRadius = 1.0f; 21 | private float dotRadius = 1.0f; 22 | private PointF dotCenter = null; 23 | private double heading = -1.0; 24 | private SmoothEstimate smoothEstimate = new SmoothEstimate(); 25 | Paint paint = new Paint(); 26 | 27 | public void setUncertaintyRadius(float uncertaintyRadius) { 28 | this.uncertaintyRadius = uncertaintyRadius; 29 | } 30 | 31 | public void setDotRadius(float dotRadius) { 32 | this.dotRadius = dotRadius; 33 | } 34 | 35 | public void setDotCenter(PointF dotCenter) { 36 | this.dotCenter = dotCenter; 37 | } 38 | 39 | public void setHeading(double heading) { 40 | this.heading = heading; 41 | } 42 | 43 | public BlueDotView(Context context) { 44 | this(context, null); 45 | } 46 | 47 | public BlueDotView(Context context, AttributeSet attr) { 48 | super(context, attr); 49 | initialise(); 50 | } 51 | 52 | private void initialise() { 53 | Log.d("BluedotView", "Initialize"); 54 | setWillNotDraw(false); 55 | setPanLimit(SubsamplingScaleImageView.PAN_LIMIT_CENTER); 56 | 57 | paint.setAntiAlias(true); 58 | paint.setStyle(Paint.Style.FILL); 59 | paint.setColor(getResources().getColor(R.color.ia_blue)); 60 | } 61 | 62 | 63 | 64 | @Override 65 | protected void onDraw(Canvas canvas) { 66 | super.onDraw(canvas); 67 | 68 | if (!isReady()) { 69 | return; 70 | } 71 | 72 | if (dotCenter != null) { 73 | // Update smooth estimate 74 | smoothEstimate.update( 75 | dotCenter.x, dotCenter.y, 76 | (float)((heading)/180.0 * Math.PI), // Map degrees to radians 77 | uncertaintyRadius, 78 | System.currentTimeMillis()); 79 | 80 | PointF vPoint = sourceToViewCoord(smoothEstimate.getX(), smoothEstimate.getY()); 81 | 82 | // Paint uncertainty circle 83 | float scaledUncertaintyRadius = getScale() * smoothEstimate.getRadius(); 84 | paint.setAlpha(30); 85 | canvas.drawCircle(vPoint.x, vPoint.y, scaledUncertaintyRadius, paint); 86 | 87 | // Paint center point 88 | float scaledDotRadius = getScale() * dotRadius; 89 | paint.setAlpha(90); 90 | canvas.drawCircle(vPoint.x, vPoint.y, scaledDotRadius, paint); 91 | 92 | // Paint heading triangle if available 93 | if (heading != -1.0) { 94 | paint.setAlpha(255); 95 | Path triangle = headingTriangle(vPoint.x, vPoint.y, 96 | // Note: Rotate up-pointing angle to right (for unit circle) 97 | smoothEstimate.getHeading() - (float)Math.PI/2, 98 | scaledDotRadius); 99 | canvas.drawPath(triangle, paint); 100 | } 101 | } 102 | 103 | postInvalidate(); 104 | } 105 | 106 | /** 107 | * Trigonometric (unit circle) computation of the heading arrow triangle 108 | * @param x X coordinate of the estimate (circle) center 109 | * @param y Y coordinate of the estimate (circle) center 110 | * @param a Heading angle in radians (zero pointing right) 111 | * @param r Radius of the estimate circle 112 | * @return Path representing the heading triangle 113 | */ 114 | private static Path headingTriangle(float x, float y, float a, float r){ 115 | float x1 = (float)(x + 0.9*r*Math.cos(a)); 116 | float y1 = (float)(y + 0.9*r*Math.sin(a)); 117 | float x2 = (float)(x + 0.2*r*Math.cos(a + 0.5*Math.PI)); 118 | float y2 = (float)(y + 0.2*r*Math.sin(a + 0.5*Math.PI)); 119 | float x3 = (float)(x + 0.2*r*Math.cos(a - 0.5*Math.PI)); 120 | float y3 = (float)(y + 0.2*r*Math.sin(a - 0.5*Math.PI)); 121 | 122 | Path triangle = new Path(); 123 | triangle.moveTo(x1, y1); 124 | triangle.lineTo(x2, y2); 125 | triangle.lineTo(x3, y3); 126 | triangle.lineTo(x1, y1); 127 | 128 | return triangle; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/imageview/ImageViewActivity.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.imageview; 2 | 3 | import android.app.DownloadManager; 4 | import android.content.Context; 5 | import android.graphics.Bitmap; 6 | import android.graphics.PointF; 7 | import android.graphics.drawable.Drawable; 8 | import android.os.Bundle; 9 | import androidx.fragment.app.FragmentActivity; 10 | 11 | import android.os.Handler; 12 | import android.util.Log; 13 | import android.widget.Toast; 14 | 15 | import com.davemorrissey.labs.subscaleview.ImageSource; 16 | import com.indooratlas.android.sdk.IALocation; 17 | import com.indooratlas.android.sdk.IALocationListener; 18 | import com.indooratlas.android.sdk.IALocationManager; 19 | import com.indooratlas.android.sdk.IALocationRequest; 20 | import com.indooratlas.android.sdk.IAOrientationListener; 21 | import com.indooratlas.android.sdk.IAOrientationRequest; 22 | import com.indooratlas.android.sdk.IARegion; 23 | import com.indooratlas.android.sdk.examples.R; 24 | import com.indooratlas.android.sdk.examples.SdkExample; 25 | import com.indooratlas.android.sdk.examples.utils.ExampleUtils; 26 | import com.indooratlas.android.sdk.resources.IAFloorPlan; 27 | import com.indooratlas.android.sdk.resources.IALatLng; 28 | import com.indooratlas.android.sdk.resources.IALocationListenerSupport; 29 | import com.squareup.picasso.Picasso; 30 | import com.squareup.picasso.RequestCreator; 31 | import com.squareup.picasso.Target; 32 | 33 | @SdkExample(description = R.string.example_imageview_description) 34 | public class ImageViewActivity extends FragmentActivity { 35 | 36 | private static final String TAG = "IndoorAtlasExample"; 37 | 38 | // blue dot radius in meters 39 | private static final float dotRadius = 1.0f; 40 | 41 | private IALocationManager mIALocationManager; 42 | private IAFloorPlan mFloorPlan; 43 | private BlueDotView mImageView; 44 | private Target mLoadTarget; 45 | 46 | private IALocationListener mLocationListener = new IALocationListenerSupport() { 47 | @Override 48 | public void onLocationChanged(IALocation location) { 49 | Log.d(TAG, "location is: " + location.getLatitude() + "," + location.getLongitude()); 50 | if (mImageView != null && mImageView.isReady()) { 51 | IALatLng latLng = new IALatLng(location.getLatitude(), location.getLongitude()); 52 | PointF point = mFloorPlan.coordinateToPoint(latLng); 53 | mImageView.setDotCenter(point); 54 | mImageView.setUncertaintyRadius( 55 | mFloorPlan.getMetersToPixels() * location.getAccuracy()); 56 | mImageView.postInvalidate(); 57 | } 58 | } 59 | }; 60 | 61 | private IAOrientationListener mOrientationListener = new IAOrientationListener() { 62 | @Override 63 | public void onHeadingChanged(long timestamp, double heading) { 64 | if (mFloorPlan != null) { 65 | mImageView.setHeading(heading - mFloorPlan.getBearing()); 66 | } 67 | } 68 | 69 | @Override 70 | public void onOrientationChange(long l, double[] doubles) { 71 | // No-op 72 | } 73 | }; 74 | 75 | private IARegion.Listener mRegionListener = new IARegion.Listener() { 76 | 77 | @Override 78 | public void onEnterRegion(IARegion region) { 79 | if (region.getType() == IARegion.TYPE_FLOOR_PLAN) { 80 | String id = region.getId(); 81 | Log.d(TAG, "floorPlan changed to " + id); 82 | Toast.makeText(ImageViewActivity.this, id, Toast.LENGTH_SHORT).show(); 83 | fetchFloorPlanBitmap(region.getFloorPlan()); 84 | } 85 | } 86 | 87 | @Override 88 | public void onExitRegion(IARegion region) { 89 | // leaving a previously entered region 90 | } 91 | 92 | }; 93 | 94 | @Override 95 | protected void onCreate(Bundle savedInstanceState) { 96 | super.onCreate(savedInstanceState); 97 | setContentView(R.layout.activity_image_view); 98 | // prevent the screen going to sleep while app is on foreground 99 | findViewById(android.R.id.content).setKeepScreenOn(true); 100 | 101 | mImageView = findViewById(R.id.imageView); 102 | 103 | mIALocationManager = IALocationManager.create(this); 104 | 105 | // Setup long click listener for sharing traceId 106 | ExampleUtils.shareTraceId(findViewById(R.id.imageView), ImageViewActivity.this, 107 | mIALocationManager); 108 | 109 | } 110 | 111 | @Override 112 | protected void onDestroy() { 113 | super.onDestroy(); 114 | mIALocationManager.destroy(); 115 | } 116 | 117 | @Override 118 | protected void onResume() { 119 | super.onResume(); 120 | // starts receiving location updates 121 | ///mIALocationManager.requestLocationUpdates(IALocationRequest.create(), mLocationListener); 122 | mIALocationManager.registerRegionListener(mRegionListener); 123 | IAOrientationRequest orientationRequest = new IAOrientationRequest(10f, 10f); 124 | mIALocationManager.registerOrientationListener(orientationRequest, mOrientationListener); 125 | 126 | 127 | IALocationRequest locReq = IALocationRequest.create(); 128 | 129 | // default mode 130 | locReq.setPriority(IALocationRequest.PRIORITY_HIGH_ACCURACY); 131 | 132 | // Low power mode: Uses less power, but has lower accuracy use e.g. for background tracking 133 | //locReq.setPriority(IALocationRequest.PRIORITY_LOW_POWER); 134 | 135 | // Cart mode: Use when device is mounted to a shopping cart or similar platform with wheels 136 | //locReq.setPriority(IALocationRequest.PRIORITY_CART_MODE); 137 | 138 | // --- start receiving location updates & monitor region changes 139 | mIALocationManager.requestLocationUpdates(locReq, mLocationListener); 140 | mIALocationManager.registerRegionListener(mRegionListener); 141 | } 142 | 143 | @Override 144 | protected void onPause() { 145 | super.onPause(); 146 | mIALocationManager.removeLocationUpdates(mLocationListener); 147 | mIALocationManager.unregisterRegionListener(mRegionListener); 148 | mIALocationManager.unregisterOrientationListener(mOrientationListener); 149 | } 150 | 151 | /** 152 | * Methods for fetching bitmap image. 153 | */ 154 | 155 | private void showFloorPlanImage(Bitmap bitmap) { 156 | mImageView.setDotRadius(mFloorPlan.getMetersToPixels() * dotRadius); 157 | mImageView.setImage(ImageSource.cachedBitmap(bitmap)); 158 | } 159 | 160 | 161 | /** 162 | * Download floor plan using Picasso library. 163 | */ 164 | private void fetchFloorPlanBitmap(final IAFloorPlan floorPlan) { 165 | 166 | mFloorPlan = floorPlan; 167 | final String url = floorPlan.getUrl(); 168 | mLoadTarget = new Target() { 169 | 170 | @Override 171 | public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { 172 | Log.d(TAG, "onBitmap floorplan loaded with dimensions: " 173 | + bitmap.getWidth() + "x" + bitmap.getHeight()); 174 | if (mFloorPlan != null && floorPlan.getId().equals(mFloorPlan.getId())) { 175 | showFloorPlanImage(bitmap); 176 | } 177 | } 178 | 179 | @Override 180 | public void onPrepareLoad(Drawable placeHolderDrawable) { 181 | // N/A 182 | } 183 | 184 | @Override 185 | public void onBitmapFailed(Drawable placeHolderDrawable) { 186 | Toast.makeText(ImageViewActivity.this, "Failed to load bitmap", Toast.LENGTH_SHORT).show(); 187 | mFloorPlan = null; 188 | } 189 | }; 190 | 191 | RequestCreator request = Picasso.with(this).load(url); 192 | request.into(mLoadTarget); 193 | } 194 | 195 | } 196 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/imageview/SmoothEstimate.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.imageview; 2 | 3 | /** 4 | * Simple smooth estimate for creating pleasant animation for estimates. The smoothness of the 5 | * animation is controlled by setting the speedRatio parameter. This controls how "close" to the 6 | * new estimate the smooth estimate will travel in one second. 7 | * 8 | * The x and y coordinates are unit independent, so you can use them with pixel, metric, or even 9 | * latitude-longitude coordinates. 10 | */ 11 | public class SmoothEstimate { 12 | private float x = 0f; 13 | private float y = 0f; 14 | private float a = 0f; // Heading in radians 15 | private float r = 0f; // Uncertainty radius 16 | private long t = -1; // -1 stands for uninitialized 17 | private double smoothnessInMs; 18 | 19 | /** 20 | * Default constructor setting the speed ratio towards the new estimate to 0.9 per second 21 | */ 22 | public SmoothEstimate() { 23 | this(0.9); 24 | } 25 | 26 | /** 27 | * Constructor with speedRatio parameter 28 | * @param speedRatio Should be on interval [0,1]. When updating, controls the ratio of movement 29 | * towards the new estimate in 1 second time 30 | */ 31 | public SmoothEstimate(double speedRatio) { 32 | this.smoothnessInMs = Math.pow(1.0 - speedRatio, 0.001); 33 | } 34 | 35 | /** 36 | * Smoothly updates the estimate coordinates according to the speed ratio and time elapsed 37 | * from last update 38 | * @param x x coordinate 39 | * @param y y coordinate 40 | * @param a Heading in radians 41 | * @param r Estimate uncertainty radius 42 | * @param t Timestamp in milliseconds 43 | */ 44 | public void update(float x, float y, float a, float r, long t) { 45 | if (this.t != -1) { 46 | long dt = t - this.t; 47 | this.t = t; 48 | float ratio = (float) Math.pow(smoothnessInMs, dt); 49 | this.x = ratio * this.x + (1f - ratio) * x; 50 | this.y = ratio * this.y + (1f - ratio) * y; 51 | this.r = ratio * this.r + (1f - ratio) * r; 52 | this.a = weightedAngle(this.a, a, ratio, 1f - ratio); 53 | } else { 54 | this.x = x; 55 | this.y = y; 56 | this.a = a; 57 | this.r = r; 58 | this.t = t; 59 | } 60 | } 61 | 62 | public float getX() { 63 | return x; 64 | } 65 | 66 | public float getY() { 67 | return y; 68 | } 69 | 70 | public float getHeading() { 71 | return a; 72 | } 73 | 74 | public float getRadius() { 75 | return r; 76 | } 77 | 78 | private static float weightedAngle(float a1, float a2, float w1, float w2) { 79 | double angleDiff = normalizeAngle(a2 - a1); 80 | double normalizedW2 = w2 / (w1 + w2); 81 | return (float) normalizeAngle(a1 + normalizedW2 * angleDiff); 82 | } 83 | 84 | private static double normalizeAngle(double a) { 85 | while (a > Math.PI) a -= 2 * Math.PI; 86 | while (a < -Math.PI) a += 2 * Math.PI; 87 | return a; 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/locationsettings/LocationSettingsActivity.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.locationsettings; 2 | 3 | import android.annotation.TargetApi; 4 | import android.bluetooth.BluetoothAdapter; 5 | import android.content.ActivityNotFoundException; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.net.wifi.WifiManager; 9 | import android.os.Build; 10 | import android.os.Bundle; 11 | import android.provider.Settings; 12 | import androidx.appcompat.app.AppCompatActivity; 13 | import android.view.View; 14 | 15 | import com.indooratlas.android.sdk.examples.R; 16 | import com.indooratlas.android.sdk.examples.SdkExample; 17 | import com.indooratlas.android.sdk.examples.utils.ExampleUtils; 18 | 19 | @SdkExample(description = R.string.example_location_settings_description) 20 | public class LocationSettingsActivity extends AppCompatActivity { 21 | 22 | 23 | // This example demonstrates how to access some of the system settings that might affect overall 24 | // positioning performance with IndoorAtlas SDK. 25 | // Check our docs page for more information about different device settings 26 | // https://docs.indooratlas.com/technical/android-settings/ 27 | 28 | 29 | private static final int WIFI_BACKGROUND_SCANNING_ENABLED_REQUEST_CODE = 100; 30 | private static final int BT_ENABLED_REQUEST_CODE = 101; 31 | 32 | @Override 33 | protected void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_location_settings); 36 | } 37 | 38 | @Override 39 | protected void onActivityResult(int requestCode, int resultCode, Intent data) { 40 | super.onActivityResult(requestCode, resultCode, data); 41 | final String text; 42 | switch (requestCode) { 43 | case WIFI_BACKGROUND_SCANNING_ENABLED_REQUEST_CODE: 44 | if (resultCode == RESULT_OK) { 45 | text = getString(R.string.wifi_background_scanning_enabled); 46 | } else { 47 | text = getString(R.string.wifi_background_scanning_denied); 48 | } 49 | ExampleUtils.showInfo(this, text); 50 | break; 51 | 52 | case BT_ENABLED_REQUEST_CODE: 53 | if (resultCode == RESULT_OK) { 54 | text = getString(R.string.bt_enabled); 55 | } else { 56 | text = getString(R.string.bt_denied); 57 | } 58 | ExampleUtils.showInfo(this, text); 59 | break; 60 | } 61 | } 62 | 63 | /** 64 | * Check that WiFi is supported and background scanning is enabled 65 | */ 66 | @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) 67 | public void onCheckWiFiBackgroundScanning(View view) { 68 | WifiManager manager = (WifiManager) getApplicationContext() 69 | .getSystemService(Context.WIFI_SERVICE); 70 | if (manager == null) { 71 | ExampleUtils.showInfo(this, getString(R.string.wifi_not_supported)); 72 | } else { 73 | if (manager.isScanAlwaysAvailable()) { 74 | ExampleUtils.showInfo(this, getString(R.string.wifi_background_scanning_enabled)); 75 | } else { 76 | // Ask user to enable background scanning 77 | startActivityForResult( 78 | new Intent(WifiManager.ACTION_REQUEST_SCAN_ALWAYS_AVAILABLE), 79 | WIFI_BACKGROUND_SCANNING_ENABLED_REQUEST_CODE); 80 | } 81 | } 82 | } 83 | 84 | /** 85 | * Check if Bluetooth is supported and enabled 86 | */ 87 | public void onCheckBluetoothStatus(View view) { 88 | BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); 89 | if (adapter == null) { 90 | ExampleUtils.showInfo(this, getString(R.string.bt_not_supported)); 91 | } else { 92 | if (adapter.getState() == BluetoothAdapter.STATE_ON) { 93 | ExampleUtils.showInfo(this, getString(R.string.bt_enabled)); 94 | } else { 95 | // Ask user to enable Bluetooth 96 | startActivityForResult( 97 | new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE), 98 | BT_ENABLED_REQUEST_CODE); 99 | } 100 | } 101 | } 102 | 103 | /** 104 | * Verify currently selected location mode 105 | */ 106 | public void onCheckLocationMode(View view) { 107 | 108 | // Check also https://developer.android.com/training/location/change-location-settings.html 109 | // using the LocationRequest adds dependency to Google Play Services SDK. 110 | // This approach below shows one way to get a reference about current location mode without 111 | // the dependency. 112 | 113 | try { 114 | final int mode = Settings.Secure.getInt(getContentResolver(), 115 | Settings.Secure.LOCATION_MODE); 116 | if (mode == Settings.Secure.LOCATION_MODE_HIGH_ACCURACY 117 | || mode == Settings.Secure.LOCATION_MODE_BATTERY_SAVING) { 118 | ExampleUtils.showInfo(this, getString(R.string.location_provider_available)); 119 | } else { 120 | startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); 121 | } 122 | } catch (Settings.SettingNotFoundException exception) { 123 | ExampleUtils.showInfo(this, exception.getMessage()); 124 | } catch (ActivityNotFoundException exception) { 125 | ExampleUtils.showInfo(this, exception.getMessage()); 126 | } 127 | } 128 | } 129 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/orientation/GLPrimitive.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.orientation; 2 | 3 | import android.opengl.GLES20; 4 | 5 | import java.nio.ByteBuffer; 6 | import java.nio.ByteOrder; 7 | import java.nio.FloatBuffer; 8 | import java.util.ArrayList; 9 | 10 | /** 11 | * Contains a primitive shape that can be drawn using GLES20.glDrawArrays 12 | */ 13 | class GLPrimitive { 14 | 15 | private int mNumVertices; 16 | private FloatBuffer mPosition; 17 | private FloatBuffer mTexCoord; 18 | 19 | GLPrimitive(float [] coordinates, float [] texCoords) { 20 | if (coordinates == null) { 21 | throw new IllegalArgumentException("coordinates cannot be null"); 22 | } 23 | if (texCoords == null) { 24 | throw new IllegalArgumentException("texCoords cannot be null"); 25 | } 26 | if (coordinates.length % 3 != 0) { 27 | throw new IllegalArgumentException("coordinates.length not dividable by three (" + 28 | coordinates.length + ")"); 29 | } 30 | if (texCoords.length % 2 != 0) { 31 | throw new IllegalArgumentException("texCoords.length not dividable by two (" + 32 | texCoords.length + ")"); 33 | } 34 | 35 | mNumVertices = coordinates.length / 3; 36 | if (texCoords.length / 2 != mNumVertices) { 37 | throw new IllegalArgumentException("different number of points in text coords"); 38 | } 39 | 40 | ByteBuffer bb = ByteBuffer.allocateDirect(coordinates.length * 4); 41 | bb.order(ByteOrder.nativeOrder()); 42 | mPosition = bb.asFloatBuffer(); 43 | mPosition.put(coordinates); 44 | mPosition.position(0); 45 | 46 | ByteBuffer bb2 = ByteBuffer.allocateDirect(texCoords.length * 4); 47 | bb2.order(ByteOrder.nativeOrder()); 48 | mTexCoord = bb2.asFloatBuffer(); 49 | mTexCoord.put(texCoords); 50 | mTexCoord.position(0); 51 | } 52 | 53 | public void drawArrayWithPos(int handlePosition, int type) { 54 | GLES20.glVertexAttribPointer(handlePosition, 3, GLES20.GL_FLOAT, false, 0, mPosition); 55 | GLES20.glDrawArrays(type, 0, mNumVertices); 56 | } 57 | 58 | public void drawArrayWithPosTexCoord(int handlePosition, int handleTexCoords, int type) { 59 | GLES20.glVertexAttribPointer(handlePosition, 3, GLES20.GL_FLOAT, false, 0, mPosition); 60 | GLES20.glVertexAttribPointer(handleTexCoords, 2, GLES20.GL_FLOAT, false, 0, mTexCoord); 61 | GLES20.glDrawArrays(type, 0, mNumVertices); 62 | } 63 | 64 | public static class Builder { 65 | 66 | private ArrayList mGivenPositions = new ArrayList<>(); 67 | private ArrayList mGivenTexCoords = new ArrayList<>(); 68 | 69 | public Builder posAndTexCoord(float x, float y, float z, float tx, float ty) { 70 | mGivenPositions.add(x); 71 | mGivenPositions.add(y); 72 | mGivenPositions.add(z); 73 | mGivenTexCoords.add(tx); 74 | mGivenTexCoords.add(ty); 75 | return this; 76 | } 77 | 78 | public GLPrimitive build() { 79 | float [] coordinates = new float[mGivenPositions.size()]; 80 | for (int i = 0; i < mGivenPositions.size(); i++) { 81 | coordinates[i] = mGivenPositions.get(i); 82 | } 83 | float tex [] = new float[mGivenTexCoords.size()]; 84 | for (int i = 0; i < mGivenTexCoords.size(); i++) { 85 | tex[i] = mGivenTexCoords.get(i); 86 | } 87 | return new GLPrimitive(coordinates, tex); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/orientation/OrientationActivity.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.orientation; 2 | 3 | import android.opengl.GLSurfaceView; 4 | import androidx.appcompat.app.AppCompatActivity; 5 | import android.os.Bundle; 6 | import android.widget.TextView; 7 | 8 | import com.indooratlas.android.sdk.IALocation; 9 | import com.indooratlas.android.sdk.IALocationListener; 10 | import com.indooratlas.android.sdk.IALocationManager; 11 | import com.indooratlas.android.sdk.IALocationRequest; 12 | import com.indooratlas.android.sdk.IAOrientationListener; 13 | import com.indooratlas.android.sdk.IAOrientationRequest; 14 | import com.indooratlas.android.sdk.examples.R; 15 | import com.indooratlas.android.sdk.examples.SdkExample; 16 | 17 | @SdkExample(description = R.string.example_orientation_description) 18 | public class OrientationActivity extends AppCompatActivity implements IALocationListener, 19 | IAOrientationListener { 20 | 21 | GLSurfaceView mGlView; 22 | OrientationRenderer mRenderer; 23 | 24 | TextView mTextBearing; 25 | TextView mTextHeading; 26 | TextView mTextOrientation; 27 | 28 | IALocationManager mManager; 29 | 30 | 31 | @Override 32 | protected void onCreate(Bundle savedInstanceState) { 33 | super.onCreate(savedInstanceState); 34 | setContentView(R.layout.activity_orientation); 35 | 36 | mGlView = (GLSurfaceView) findViewById(R.id.gl_view); 37 | mGlView.setEGLContextClientVersion(2); 38 | mRenderer = new OrientationRenderer(this, R.raw.panorama); 39 | mGlView.setRenderer(mRenderer); 40 | mGlView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); 41 | 42 | mTextBearing = (TextView) findViewById(R.id.text_bearing); 43 | mTextHeading = (TextView) findViewById(R.id.text_heading); 44 | mTextOrientation = (TextView) findViewById(R.id.text_orientation); 45 | 46 | mManager = IALocationManager.create(this); 47 | } 48 | 49 | @Override 50 | protected void onResume() { 51 | super.onResume(); 52 | mManager.requestLocationUpdates(IALocationRequest.create(), this); 53 | // trigger heading and orientation updates when they have changed by 5 degrees 54 | mManager.registerOrientationListener(new IAOrientationRequest(5.0, 5.0), this); 55 | } 56 | 57 | @Override 58 | protected void onPause() { 59 | mManager.unregisterOrientationListener(this); 60 | mManager.removeLocationUpdates(this); 61 | super.onPause(); 62 | } 63 | 64 | @Override 65 | protected void onDestroy() { 66 | mManager.destroy(); 67 | super.onDestroy(); 68 | } 69 | 70 | @Override 71 | public void onLocationChanged(IALocation iaLocation) { 72 | mTextBearing.setText(getString(R.string.text_bearing, iaLocation.getBearing())); 73 | } 74 | 75 | @Override 76 | public void onStatusChanged(String s, int i, Bundle bundle) { 77 | } 78 | 79 | @Override 80 | public void onHeadingChanged(long timestamp, double heading) { 81 | mTextHeading.setText(getString(R.string.text_heading, heading)); 82 | } 83 | 84 | @Override 85 | public void onOrientationChange(long timestamp, double[] orientation) { 86 | final double qw = orientation[0]; 87 | final double qx = orientation[1]; 88 | final double qy = orientation[2]; 89 | final double qz = orientation[3]; 90 | 91 | // Compute Euler angles 92 | final double pitch = Math.atan2(2.0 * (qw * qx + qy * qz), 1.0 - 2.0 * (qx * qx + qy * qy)); 93 | final double roll = Math.asin(2.0 * (qw * qy - qz * qx)); 94 | 95 | // Yaw is the same as heading but in radians and ranges from -PI to PI when computed 96 | // like this. It may also differ from the last heading value because change thresholds 97 | // defined in registerOrientationListener may trigger at different times 98 | final double yaw = -Math.atan2(2.0 * (qw * qz + qx * qy), 1.0 - 2.0 * (qy * qy + qz * qz)); 99 | 100 | mTextOrientation.setText(getString(R.string.text_orientation, 101 | Math.toDegrees(yaw), 102 | Math.toDegrees(pitch), 103 | Math.toDegrees(roll))); 104 | 105 | mRenderer.setOrientation(orientation); 106 | mGlView.requestRender(); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/orientation/OrientationRenderer.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.orientation; 2 | 3 | import android.content.Context; 4 | import android.opengl.GLES20; 5 | import android.opengl.GLSurfaceView; 6 | import android.opengl.Matrix; 7 | import android.view.Surface; 8 | import android.view.WindowManager; 9 | 10 | import javax.microedition.khronos.egl.EGLConfig; 11 | import javax.microedition.khronos.opengles.GL10; 12 | 13 | /** 14 | * Renders a panorama view. 15 | */ 16 | public class OrientationRenderer implements GLSurfaceView.Renderer { 17 | 18 | private final Context mContext; 19 | private final int mResourceId; 20 | 21 | private float mUpX, mUpY; 22 | private float [] mOrientation = new float[] {1.0f, 0.0f, 0.0f, 0.0f}; 23 | private final float[] mMatrixProjection = new float[16]; 24 | private final float[] mMatrixView = new float[16]; 25 | private final float[] mMatrixCombined = new float[16]; 26 | 27 | private GLPrimitive mPanoramaShape; 28 | private int mTexturePanorama = 0; 29 | 30 | /** 31 | * Constructor 32 | * 33 | * @param context Context 34 | * @param panoramaResource Resource to use as panorama image 35 | */ 36 | public OrientationRenderer(Context context, int panoramaResource) { 37 | mContext = context; 38 | mResourceId = panoramaResource; 39 | } 40 | 41 | /** 42 | * Set orientation. The quaternion received from IndoorAtlas can be given to the method. 43 | * 44 | * @param quat Unit quaternion. 45 | */ 46 | public void setOrientation(double [] quat) { 47 | if (quat == null) { 48 | throw new IllegalArgumentException("Orientation quaternion cannot be null"); 49 | } 50 | if (quat.length != 4) { 51 | throw new IllegalArgumentException("Orientation quaternion needs to have 4 elements"); 52 | } 53 | mOrientation = new float[4]; 54 | for (int i = 0; i < 4; i++) { 55 | mOrientation[i] = (float) quat[i]; 56 | } 57 | } 58 | 59 | @Override 60 | public void onDrawFrame(GL10 unused) { 61 | 62 | GLES20.glClearColor(1.0f, 0.0f, 0.0f, 0.0f); 63 | GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT); 64 | 65 | float [] quat = mOrientation; 66 | // forward is always where phone negative z axis points 67 | float [] fwd = GLTools.rotate(quat, 0.0f, 0.0f, -1.0f); 68 | // up depends on screen orientation 69 | float [] up = GLTools.rotate(quat, mUpX, mUpY, 0.0f); // up is where phone y points 70 | 71 | // Note difference between ENU coordinates and OpenGL coordinates 72 | Matrix.setLookAtM(mMatrixView, 0, 0.0f, 0.0f, 0.0f, 73 | fwd[0], fwd[2], -fwd[1], 74 | up[0], up[2], -up[1]); 75 | 76 | // Calculate the projection and view transformation 77 | Matrix.multiplyMM(mMatrixCombined, 0, mMatrixProjection, 0, mMatrixView, 0); 78 | 79 | // ** panorama ** // 80 | 81 | // Draw using the texture program 82 | GLES20.glUseProgram(GLTools.sProgTexture); 83 | int handlePosition = GLES20.glGetAttribLocation(GLTools.sProgTexture, "vPosition"); 84 | int handleTexCoord = GLES20.glGetAttribLocation(GLTools.sProgTexture, "aTexCoordinate"); 85 | int handleMatrix = GLES20.glGetUniformLocation(GLTools.sProgTexture, "uMatrix"); 86 | int handleTexture = GLES20.glGetUniformLocation(GLTools.sProgTexture, "uTexture"); 87 | 88 | GLES20.glEnableVertexAttribArray(handlePosition); 89 | GLES20.glEnableVertexAttribArray(handleTexCoord); 90 | GLES20.glUniformMatrix4fv(handleMatrix, 1, false, mMatrixCombined, 0); 91 | GLES20.glActiveTexture(GLES20.GL_TEXTURE0); 92 | GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTexturePanorama); 93 | GLES20.glUniform1i(handleTexture, 0); 94 | 95 | mPanoramaShape.drawArrayWithPosTexCoord(handlePosition, handleTexCoord, GLES20.GL_TRIANGLES); 96 | 97 | GLES20.glDisableVertexAttribArray(handleTexCoord); 98 | GLES20.glDisableVertexAttribArray(handlePosition); 99 | 100 | } 101 | 102 | @Override 103 | public void onSurfaceChanged(GL10 gl, int width, int height) { 104 | 105 | // The orientation of the phone is given in Android sensor coordinates but the screen 106 | // coordinates depends on the orientation of the phone. 107 | WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 108 | switch (wm.getDefaultDisplay().getRotation()) { 109 | default: 110 | case Surface.ROTATION_0: 111 | mUpX = 0.0f; 112 | mUpY = 1.0f; 113 | break; 114 | case Surface.ROTATION_90: 115 | mUpX = 1.0f; 116 | mUpY = 0.0f; 117 | break; 118 | case Surface.ROTATION_180: 119 | mUpX = 0.0f; 120 | mUpY = -1.0f; 121 | break; 122 | case Surface.ROTATION_270: 123 | mUpX = -1.0f; 124 | mUpY = 0.0f; 125 | break; 126 | } 127 | 128 | // Set viewport 129 | GLES20.glViewport(0, 0, width, height); 130 | float near = 0.1f; 131 | float fow = 1.0f; 132 | float far = 200.0f; 133 | float dx = near * fow; 134 | float dy = near * fow * (float) height / (float) width; 135 | Matrix.frustumM(mMatrixProjection, 0, -dx, dx, -dy, dy, near, far); 136 | 137 | } 138 | 139 | @Override 140 | public void onSurfaceCreated(GL10 gl, EGLConfig config) { 141 | GLTools.setup(); 142 | mPanoramaShape = GLTools.createPanoramaSphere(50, 50, 5.0f); 143 | mTexturePanorama = GLTools.loadTexture(mContext, mResourceId); 144 | } 145 | 146 | } 147 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/regions/RegionsActivity.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.regions; 2 | 3 | import android.os.Bundle; 4 | import androidx.annotation.NonNull; 5 | import androidx.fragment.app.FragmentActivity; 6 | import android.view.animation.AnimationUtils; 7 | import android.widget.TextView; 8 | 9 | import com.indooratlas.android.sdk.IALocation; 10 | import com.indooratlas.android.sdk.IALocationListener; 11 | import com.indooratlas.android.sdk.IALocationManager; 12 | import com.indooratlas.android.sdk.IALocationRequest; 13 | import com.indooratlas.android.sdk.IARegion; 14 | import com.indooratlas.android.sdk.examples.R; 15 | 16 | import com.indooratlas.android.sdk.examples.SdkExample; 17 | 18 | /** 19 | * Demonstrates automatic region transitions and floor level certainty 20 | */ 21 | @SdkExample(description = R.string.example_regions_description) 22 | public class RegionsActivity extends FragmentActivity implements IALocationListener, 23 | IARegion.Listener { 24 | 25 | 26 | IALocationManager mManager; 27 | IARegion mCurrentVenue = null; 28 | IARegion mCurrentFloorPlan = null; 29 | Integer mCurrentFloorLevel = null; 30 | Float mCurrentCertainty = null; 31 | 32 | TextView mUiVenue; 33 | TextView mUiVenueId; 34 | TextView mUiFloorPlan; 35 | TextView mUiFloorPlanId; 36 | TextView mUiFloorLevel; 37 | TextView mUiFloorCertainty; 38 | 39 | 40 | @Override 41 | public void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | 44 | setContentView(R.layout.activity_regions); 45 | 46 | mManager = IALocationManager.create(this); 47 | mManager.registerRegionListener(this); 48 | mManager.requestLocationUpdates(IALocationRequest.create(), this); 49 | 50 | mUiVenue = (TextView) findViewById(R.id.text_view_venue); 51 | mUiVenueId = (TextView) findViewById(R.id.text_view_venue_id); 52 | mUiFloorPlan = (TextView) findViewById(R.id.text_view_floor_plan); 53 | mUiFloorPlanId = (TextView) findViewById(R.id.text_view_floor_plan_id); 54 | mUiFloorLevel = (TextView) findViewById(R.id.text_view_floor_level); 55 | mUiFloorCertainty = (TextView) findViewById(R.id.text_view_floor_certainty); 56 | 57 | updateUi(); 58 | } 59 | 60 | @Override 61 | protected void onDestroy() { 62 | mManager.destroy(); 63 | super.onDestroy(); 64 | } 65 | 66 | @Override 67 | public void onLocationChanged(IALocation iaLocation) { 68 | mCurrentFloorLevel = iaLocation.hasFloorLevel() ? iaLocation.getFloorLevel() : null; 69 | mCurrentCertainty = iaLocation.hasFloorCertainty() ? iaLocation.getFloorCertainty() : null; 70 | updateUi(); 71 | } 72 | 73 | @Override 74 | public void onStatusChanged(String s, int i, Bundle bundle) { 75 | } 76 | 77 | @Override 78 | public void onEnterRegion(IARegion iaRegion) { 79 | if (iaRegion.getType() == IARegion.TYPE_VENUE) { 80 | mCurrentVenue = iaRegion; 81 | } else if (iaRegion.getType() == IARegion.TYPE_FLOOR_PLAN) { 82 | mCurrentFloorPlan = iaRegion; 83 | } 84 | updateUi(); 85 | } 86 | 87 | @Override 88 | public void onExitRegion(IARegion iaRegion) { 89 | if (iaRegion.getType() == IARegion.TYPE_VENUE) { 90 | mCurrentVenue = iaRegion; 91 | } else if (iaRegion.getType() == IARegion.TYPE_FLOOR_PLAN) { 92 | mCurrentFloorPlan = iaRegion; 93 | } 94 | updateUi(); 95 | } 96 | 97 | void updateUi() { 98 | String venue = getString(R.string.venue_outside); 99 | String venueId = ""; 100 | String floorPlan = ""; 101 | String floorPlanId = ""; 102 | String level = ""; 103 | String certainty = ""; 104 | if (mCurrentVenue != null) { 105 | venue = getString(R.string.venue_inside); 106 | venueId = mCurrentVenue.getId(); 107 | if (mCurrentFloorPlan != null) { 108 | floorPlan = mCurrentFloorPlan.getName(); 109 | floorPlanId = mCurrentFloorPlan.getId(); 110 | } else { 111 | floorPlan = getString(R.string.floor_plan_outside); 112 | } 113 | } 114 | if (mCurrentFloorLevel != null) { 115 | level = mCurrentFloorLevel.toString(); 116 | } 117 | if (mCurrentCertainty != null) { 118 | certainty = getString(R.string.floor_certainty_percentage, mCurrentCertainty * 100.0f); 119 | } 120 | setText(mUiVenue, venue, true); 121 | setText(mUiVenueId, venueId, true); 122 | setText(mUiFloorPlan, floorPlan, true); 123 | setText(mUiFloorPlanId, floorPlanId, true); 124 | setText(mUiFloorLevel, level, true); 125 | setText(mUiFloorCertainty, certainty, false); // do not animate as changes can be frequent 126 | } 127 | 128 | /** 129 | * Set the text of a TextView and make a animation to notify when the value has changed 130 | */ 131 | void setText(@NonNull TextView view, @NonNull String text, boolean animateWhenChanged) { 132 | if (!view.getText().toString().equals(text)) { 133 | view.setText(text); 134 | if (animateWhenChanged) { 135 | view.startAnimation(AnimationUtils.loadAnimation(this, R.anim.notify_change)); 136 | } 137 | } 138 | } 139 | 140 | } 141 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/systemgeofence/GeofenceReceiver.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.systemgeofence; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.os.Bundle; 7 | import androidx.annotation.NonNull; 8 | import androidx.annotation.Nullable; 9 | import androidx.localbroadcastmanager.content.LocalBroadcastManager; 10 | 11 | import android.util.Log; 12 | 13 | import com.google.android.gms.common.ConnectionResult; 14 | import com.google.android.gms.common.api.GoogleApiClient; 15 | import com.google.android.gms.common.api.ResultCallback; 16 | import com.google.android.gms.common.api.Status; 17 | import com.google.android.gms.location.Geofence; 18 | import com.google.android.gms.location.GeofencingEvent; 19 | import com.indooratlas.android.sdk.examples.foregroundservice.ForegroundService; 20 | 21 | public class GeofenceReceiver extends BroadcastReceiver implements GoogleApiClient.ConnectionCallbacks, GoogleApiClient.OnConnectionFailedListener, ResultCallback { 22 | public final static String ACTION_GEOFENCE_EVENT = "ACTION_GEOFENCE_EVENT"; 23 | private final static String TAG = "Geofencing"; 24 | 25 | @Override 26 | public void onReceive(Context context, Intent intent) { 27 | 28 | sendLogToMainActivity(context, "GeofenceReceiver onReceive"); 29 | 30 | if (intent.getAction().equals(ACTION_GEOFENCE_EVENT)) { 31 | GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent); 32 | 33 | if (geofencingEvent.hasError()) { 34 | sendLogToMainActivity(context, "Geofencing Error Code(" + 35 | geofencingEvent.getErrorCode() + ")"); 36 | return; 37 | } 38 | switch (geofencingEvent.getGeofenceTransition()) { 39 | case Geofence.GEOFENCE_TRANSITION_ENTER: 40 | sendLogToMainActivity(context, "GeofenceReceiver onReceive : " + 41 | "GEOFENCE_TRANSITION_ENTER"); 42 | sendLogToMainActivity(context, "GeofenceReceiver onReceive : " + 43 | "starting IndoorAtlas positioning in Foreground Service" + 44 | "--> See ActionBar for location updates"); 45 | 46 | sendLogToMainActivity(context, "GeofenceReceiver onReceive : " + 47 | "--> Note: you can use a Fake GPS app to simulate location updates" + 48 | " inside and outside the geofence platform geofence area"); 49 | 50 | // After starting the foreground service, you can close the 51 | // example app and continue 52 | // using the foreground service notification 53 | Intent startIntent = new Intent(context, ForegroundService.class); 54 | startIntent.setAction(ForegroundService.STARTFOREGROUND_ACTION); 55 | context.startService(startIntent); 56 | break; 57 | case Geofence.GEOFENCE_TRANSITION_EXIT: 58 | sendLogToMainActivity(context, "GeofenceReceiver onReceive : " + 59 | "GEOFENCE_TRANSITION_EXIT"); 60 | sendLogToMainActivity(context, "GeofenceReceiver onReceive : " + 61 | "stopping IndoorAtlas positioning in Foreground Service" + 62 | "--> ActionBar notification is closed"); 63 | 64 | // To close the foreground service, "Stop foreground service" button 65 | // must be pressed 66 | Intent stopIntent = new Intent(context, ForegroundService.class); 67 | stopIntent.setAction(ForegroundService.STOPFOREGROUND_ACTION); 68 | context.startService(stopIntent); 69 | break; 70 | default: 71 | break; 72 | } 73 | 74 | } 75 | } 76 | 77 | @Override 78 | public void onConnected(@Nullable Bundle bundle) { 79 | 80 | } 81 | 82 | @Override 83 | public void onConnectionSuspended(int i) { 84 | 85 | } 86 | 87 | @Override 88 | public void onConnectionFailed(@NonNull ConnectionResult connectionResult) { 89 | 90 | } 91 | 92 | @Override 93 | public void onResult(@NonNull Status status) { 94 | 95 | } 96 | 97 | private void sendLogToMainActivity(Context context, String log) { 98 | // Send a local broadcast 99 | Log.d(TAG, "sendLogToMainActivity : "+log); 100 | Intent localIntent = new Intent("GeofenceReceiverLog"); 101 | localIntent.putExtra("log", log); 102 | LocalBroadcastManager.getInstance(context).sendBroadcast(localIntent); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /Basic/src/main/java/com/indooratlas/android/sdk/examples/utils/ExampleUtils.java: -------------------------------------------------------------------------------- 1 | package com.indooratlas.android.sdk.examples.utils; 2 | 3 | import android.app.Activity; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import com.google.android.material.snackbar.Snackbar; 7 | import android.view.View; 8 | 9 | import com.indooratlas.android.sdk.IALocationManager; 10 | import com.indooratlas.android.sdk.examples.R; 11 | 12 | 13 | public class ExampleUtils { 14 | 15 | /** 16 | * Shares the trace ID of the client. Trace ID can be used under certain conditions by 17 | * IndoorAtlas to provide detailed support. 18 | */ 19 | public static void shareTraceId(View view, final Context context, 20 | final IALocationManager manager) { 21 | view.setOnLongClickListener(new View.OnLongClickListener() { 22 | @Override 23 | public boolean onLongClick(View view) { 24 | shareText(context, manager.getExtraInfo().traceId, "traceId"); 25 | return true; 26 | } 27 | }); 28 | } 29 | 30 | /** 31 | * Use the share tool to share text via Slack, email, WhatsApp etc. 32 | */ 33 | public static void shareText(Context context, String text, String title) { 34 | 35 | Intent sendIntent = new Intent(); 36 | sendIntent.setAction(Intent.ACTION_SEND); 37 | sendIntent.putExtra(Intent.EXTRA_TEXT, text); 38 | sendIntent.setType("text/plain"); 39 | 40 | context.startActivity(Intent.createChooser(sendIntent, title)); 41 | } 42 | 43 | /** 44 | * Shows a {@link Snackbar} with defined text 45 | */ 46 | public static void showInfo(Activity activity, String text) { 47 | final Snackbar snackbar = Snackbar.make(activity.findViewById(android.R.id.content), text, 48 | Snackbar.LENGTH_INDEFINITE); 49 | snackbar.setAction(R.string.button_close, new View.OnClickListener() { 50 | @Override 51 | public void onClick(View view) { 52 | snackbar.dismiss(); 53 | } 54 | }); 55 | snackbar.show(); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Basic/src/main/res/anim/notify_change.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-hdpi/ic_gps_fixed_white_18dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-hdpi/ic_gps_fixed_white_18dp.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-hdpi/ic_person_outline_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-hdpi/ic_person_outline_white_36dp.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-mdpi/ic_person_outline_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-mdpi/ic_person_outline_white_36dp.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xhdpi/ic_person_outline_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xhdpi/ic_person_outline_white_36dp.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xhdpi/map_blue_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xhdpi/map_blue_dot.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xhdpi/map_red_dot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xhdpi/map_red_dot.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xxhdpi/ic_person_outline_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xxhdpi/ic_person_outline_white_36dp.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable-xxxhdpi/ic_person_outline_white_36dp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/drawable-xxxhdpi/ic_person_outline_white_36dp.png -------------------------------------------------------------------------------- /Basic/src/main/res/drawable/circle.xml: -------------------------------------------------------------------------------- 1 | 3 | 5 | 8 | -------------------------------------------------------------------------------- /Basic/src/main/res/layout/activity_ar.xml: -------------------------------------------------------------------------------- 1 | 13 | 17 | 18 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Basic/src/main/res/layout/activity_foreground.xml: -------------------------------------------------------------------------------- 1 | 6 | 7 | 16 | 17 |