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 |
25 |
26 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_image_view.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
9 |
10 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_location_settings.xml:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
21 |
22 |
30 |
31 |
39 |
40 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_lockfloor.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
17 |
18 |
24 |
25 |
31 |
32 |
33 |
34 |
39 |
40 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
11 |
12 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_maps.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
18 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_maps_rotate.xml:
--------------------------------------------------------------------------------
1 |
4 |
5 |
10 |
11 |
19 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_orientation.xml:
--------------------------------------------------------------------------------
1 |
2 |
12 |
13 |
17 |
18 |
27 |
28 |
37 |
38 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_regions.xml:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
16 |
17 |
25 |
26 |
33 |
34 |
41 |
42 |
49 |
50 |
55 |
56 |
63 |
64 |
71 |
72 |
77 |
78 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_simple.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
17 |
18 |
24 |
25 |
31 |
32 |
33 |
34 |
39 |
40 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/activity_system_geofence.xml:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
18 |
25 |
26 |
27 |
34 |
35 |
36 |
42 |
43 |
50 |
51 |
58 |
59 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/location_request_dialog.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
8 |
12 |
13 |
20 |
21 |
25 |
26 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/preference_googlemaps.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/text_only.xml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
14 |
15 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Basic/src/main/res/layout/toolbar.xml:
--------------------------------------------------------------------------------
1 |
8 |
--------------------------------------------------------------------------------
/Basic/src/main/res/menu/menu_simple.xml:
--------------------------------------------------------------------------------
1 |
14 |
--------------------------------------------------------------------------------
/Basic/src/main/res/raw/panorama.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/Basic/src/main/res/raw/panorama.jpg
--------------------------------------------------------------------------------
/Basic/src/main/res/values-w820dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 64dp
6 |
7 |
--------------------------------------------------------------------------------
/Basic/src/main/res/values/arrays.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | - #941100
5 | - #005493
6 | - #8EFA00
7 | - #FF2600
8 | - #D783FF
9 | - #FFFB00
10 | - #73FDFF
11 | - #797979
12 |
13 |
--------------------------------------------------------------------------------
/Basic/src/main/res/values/colors.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | #33ff0000
5 | #ffff0000
6 | #ff00a5f5
7 |
8 | #ffff0000
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Basic/src/main/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | 16dp
4 | 16dp
5 | 10sp
6 | 8dp
7 |
8 |
--------------------------------------------------------------------------------
/Basic/src/main/res/values/google_maps_api.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | AIzaSyDxKbdk5uAlIiGQSZC_TciRI8BtpAepKOs
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Basic/src/main/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | IndoorAtlas SDK Examples
4 | Clear
5 | Simple
6 | Demonstrates basic functionality, shows events as text entries.
7 | ImageView
8 | Demonstrates showing locations on a floor plan displayed with ImageView.
9 | Google Maps - Indoor-outdoor
10 | Geofences on Google Maps Overlay
11 | Demonstrates showing location over a floor plan which is loaded as map overlay. Indoor-outdoor detection is enabled, automatically switches between IndoorAtlas and GPS
12 | Demonstrates showing location and setting Geofences over a floor plan which is loaded as map overlay. Indoor-outdoor detection is enabled, automatically switches between IndoorAtlas and GPS. Geofences work outdoors as well.
13 | Google Indoor Maps
14 | Demonstrates using IndoorAtlas locations on Google Indoor Maps
15 | AR Wayfinding
16 | Demonstrates AR wayfinding using data from IndoorAtlas services
17 | 3rdparty AR Wayfinding
18 | Demonstrates AR wayfinding using custom routing data
19 | Platform Geofences example
20 | Demonstrates starting/stopping IndoorAtlas positioning when the device enters / exits Android platform geofence. Uses Foreground service.
21 | Unable to load venue coordinate from Positioning API. Use default coordinate defined in source code.
22 | Permission required
23 | Access to coarse location is required for faster first fix and for some examples.
24 | No access to locations. Time to first fix may be severely delayed and some examples may not work!
25 | No access to external storage. Permission needed for displaying floor plans
26 | OK
27 | Cancel
28 | Close
29 | Sure
30 | Deny
31 | Configuration incomplete
32 | API credentials needed, please see gradle.properties in project root level.
33 | Set location
34 | Error setting location: %s
35 | Share…
36 | Your shared name?
37 | Current channel: %s
38 | Error while loading floor plan
39 | Me: %s
40 | Set channel
41 | Channel name
42 | Setting channel failed: %s
43 | Change color
44 | Set credentials
45 | Demonstrates setting credentials from code
46 | Location request options
47 | Fastest interval (milliseconds)
48 | Shortest displacement (meters)
49 | use default
50 | Demonstrates automatic region transitions and vertical position information
51 | Regions
52 | Region information
53 | Outside mapped area
54 | In venue
55 | No floor plan
56 | Floor level
57 | Certainty: %.1f %%
58 |
59 |
60 | Demonstrates displaying the 3D orientation of the device. Panorama image credit: ESO (Very Large Telescope ready for action)
61 | Orientation
62 | Bearing: no updates
63 | Bearing: %1$5.1f\u00b0
64 | Heading: no updates
65 | Heading: %1$5.1f\u00b0
66 | Orient.: no updates
67 | Yaw: %1$5.2f, Pitch: %2$5.2f, Roll: %3$5.2f
68 |
69 |
70 | Demonstrates usage of geofences in IndoorAtlas SDK
71 | Geofences
72 |
73 |
74 | Device radio and location settings
75 | Shows how to verify Bluetooth, WiFi and location settings
76 | Example on how to verify current WiFi, Bluetooth and location mode settings for optimal localization performance.
77 | Check WiFi background scanning
78 | Check Bluetooth status
79 | Check location mode
80 | Bluetooth is not supported on this hardware platform
81 | Bluetooth is enabled
82 | User denied use of bluetooth
83 | WiFi is not supported on this hardware platform
84 | WiFi background scanning is enabled
85 | User denied WiFi background scanning
86 | Location provider enabled
87 |
88 | Demonstrates usage of IndoorAtlas Wayfinding & PoIs
89 | Wayfinding & PoIs
90 |
91 | Demonstrates IndoorAtlas background positioning using a Foreground Service.
92 | Background mode (Foreground Service)
93 |
94 | Demonstrates how locking positioning to specific floor or indoors is achieved.
95 | Lock floor and Indoors
96 |
97 |
98 |
99 |
--------------------------------------------------------------------------------
/Basic/src/main/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Basic/src/main/res/xml/filepaths.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # IndoorAtlas SDK Examples for Android
2 |
3 | [IndoorAtlas](https://www.indooratlas.com/) provides a unique Platform-as-a-Service (PaaS) solution that runs a disruptive geomagnetic positioning in its full-stack hybrid technology for accurately pinpointing a location inside a building. The IndoorAtlas SDK enables app developers to use high-accuracy indoor positioning in venues that have been fingerprinted.
4 |
5 | This example app showcases the IndoorAtlas SDK features and acts as a reference implementation for many of the basic SDK features. Getting started requires you to set up a free developer account and fingerprint your indoor venue using the IndoorAtlas MapCreator tool.
6 |
7 | There are also similar examples for iOS in [Objective-C](https://github.com/IndoorAtlas/ios-sdk-examples) and [Swift](https://github.com/IndoorAtlas/ios-sdk-swift-examples).
8 |
9 | * [Getting Started](#getting-started)
10 | * [Set up your account](#set-up-your-account)
11 | * [Set up your API keys](#set-up-your-api-keys)
12 | * [Features](#features)
13 | * [Documentation](#documentation)
14 | * [SDK Changelog](#sdk-changelog)
15 | * [License](#license)
16 |
17 |
18 | ## Getting Started
19 |
20 | ### Set up your account
21 |
22 | * Set up your [free developer account](https://app.indooratlas.com) in the IndoorAtlas developer portal. Help with getting started is available in the [Quick Start Guide](http://docs.indooratlas.com/quick-start-guide.html).
23 | * To enable IndoorAtlas indoor positioning in a venue, the venue needs to be fingerprinted with the [IndoorAtlas MapCreator 2](https://play.google.com/store/apps/details?id=com.indooratlas.android.apps.jaywalker) tool.
24 | * To start developing your own app, create an [API key](https://app.indooratlas.com/apps).
25 |
26 | ### Set up your API keys
27 |
28 | To run the examples you need to configure your IndoorAtlas API keys. If you do not have keys yet, go to and sign up.
29 |
30 | Once you have API keys, edit them into `gradle.properties` in the project root level.
31 |
32 | ### Building the AR examples
33 |
34 | By default the AR examples aren't build. You can choose ARCore and AREngine variants to build the examples. Note: you need AR enabled api key to run the AR examples, contact the IndoorAtlas sales at sales@indooratlas.com
35 |
36 | ## Examples
37 |
38 | ### AR Example
39 |
40 | * [AR Example](https://github.com/IndoorAtlas/android-sdk-examples/blob/master/Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar): Shows how to use IndoorAtlas SDK's AR APIs to implement AR Wayfinding. Displays AR POIs/Ads.
41 |
42 | 
43 |
44 |
45 | ### Simple Example
46 |
47 | * [Simple Example](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/simple): This is the hello world of IndoorAtlas SDK. Displays received location updates as log entries.
48 |
49 | 
50 |
51 |
52 | ### Imageview Example
53 |
54 | * [ImageView](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/imageview): Automatically downloads the floor plan that user has entered and displays it using Dave Morrissey's
55 | . This is a great library for handling large images! The example also demonstrates smoothly animating the blue dot and how to set up OrientationListener for obtaining device heading
56 | information.
57 |
58 | 
59 |
60 |
61 | ### Google Maps - Overlay Example
62 |
63 | * [Google Maps](https://github.com/IndoorAtlas/android-sdk-examples/blob/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/mapsoverlay) - Overlay: Just like *Google Maps - Basic* but demonstrates how to place floor plan on world map by coordinates.
64 |
65 | 
66 |
67 |
68 | ### Automatic Venue and Floor Detection Example
69 |
70 | * [Automatic Venue and Floor Detection](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/regions): Demonstrates automatic region changes i.e. automatic venue detection and floor detection.
71 |
72 | 
73 |
74 |
75 | ### Wayfinding Example
76 |
77 | * [Wayfinding Example](https://github.com/IndoorAtlas/android-sdk-examples/blob/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/wayfinding/WayfindingOverlayActivity.java#L260): In this example, a wayfinding graph json file is loaded. On the UI, you'll see your current location, and when you tap another point on the floorplan, you'll be shown a wayfinding route to that location.
78 |
79 | * Note: to setup, you need to draw a wayfinding graph for your venue using app.indooratlas.com and save it. Obviously you also need to fingerprint the venue and generate a map.
80 |
81 | 
82 |
83 |
84 | ### Foreground Service Positioning Example
85 |
86 | * [Foreground Service Positioning Example](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/foregroundservice): Demonstrates running IndoorAtlas positioning when the app is in the background, using an Android Foreground Service.
87 |
88 | 
89 |
90 |
91 | ### IndoorAtlas Geofences Example
92 |
93 | * [Geofences](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/geofence): Demonstrates how to set geofences and receive the geofence events.
94 |
95 | 
96 |
97 | ### Start IndoorAtlas with Platform Geofence Wakeup
98 |
99 | * [Platform Geofence Wakeup](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/systemgeofence): Demonstrates how to set and wakeup from platform geofence events to start IndoorAtlas near a venue.
100 |
101 | 
102 |
103 |
104 | ### Orientation Example
105 |
106 | * [Orientation](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/orientation): Demonstrates IndoorAtlas 3D Orientation API.
107 |
108 | 
109 |
110 |
111 | ### Set Credentials from Code Example
112 |
113 | * [Set credentials](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/main/java/com/indooratlas/android/sdk/examples/credentials): Demonstrates how to set IndoorAtlas credentials from code in runtime.
114 |
115 | 
116 |
117 | ### AR wayfinding examples
118 |
119 | * [AR wayfinding](https://github.com/IndoorAtlas/android-sdk-examples/tree/master/Basic/src/ar/java/com/indooratlas/android/sdk/examples/ar): AR wayfinding examples, both using IndoorAtlas high-level and low-level AR apis.
120 |
121 |
122 | ## Documentation
123 |
124 | The IndoorAtlas SDK API documentation is available in the documentation portal:
125 |
126 | ## SDK Changelog
127 |
128 |
129 |
130 | ## License
131 |
132 | Copyright 2015-2019 IndoorAtlas Ltd. The IndoorAtlas SDK Examples are released under the Apache License. See the [LICENSE.md](https://github.com/IndoorAtlas/android-sdk-examples/blob/master/LICENSE.md) file for details.
133 |
134 |
135 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | buildscript {
3 |
4 | repositories {
5 | google()
6 | jcenter()
7 | }
8 |
9 | dependencies {
10 | classpath 'com.android.tools.build:gradle:8.9.2'
11 | classpath 'com.jaredsburrows:gradle-license-plugin:0.9.8'
12 | }
13 | }
14 |
15 | allprojects {
16 |
17 | repositories {
18 | google()
19 | jcenter()
20 | mavenCentral()
21 | maven {
22 | url "https://dl.cloudsmith.io/public/indooratlas/mvn-public/maven/"
23 | }
24 | maven {
25 | url "https://dl.cloudsmith.io/public/indooratlas/mvn-public-alpha/maven/"
26 | }
27 | maven {
28 | url "https://dl.cloudsmith.io/public/indooratlas/mvn-public-beta/maven/"
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/example-screenshots/AR-wayfinding-ad.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/AR-wayfinding-ad.jpg
--------------------------------------------------------------------------------
/example-screenshots/device-radio-and-location-settings_11.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/device-radio-and-location-settings_11.jpg
--------------------------------------------------------------------------------
/example-screenshots/foreground-service_14.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/foreground-service_14.png
--------------------------------------------------------------------------------
/example-screenshots/geofences_10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/geofences_10.jpg
--------------------------------------------------------------------------------
/example-screenshots/geofences_10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/geofences_10.png
--------------------------------------------------------------------------------
/example-screenshots/googlemaps - overlay_04.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/googlemaps - overlay_04.jpg
--------------------------------------------------------------------------------
/example-screenshots/imageview_02.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/imageview_02.jpg
--------------------------------------------------------------------------------
/example-screenshots/open-street-map_08.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/open-street-map_08.jpg
--------------------------------------------------------------------------------
/example-screenshots/orientation_09.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/orientation_09.jpg
--------------------------------------------------------------------------------
/example-screenshots/platform_geofence_example_15.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/platform_geofence_example_15.png
--------------------------------------------------------------------------------
/example-screenshots/regions_07.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/regions_07.jpg
--------------------------------------------------------------------------------
/example-screenshots/set-credentials_06.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/set-credentials_06.jpg
--------------------------------------------------------------------------------
/example-screenshots/sharelocation-05.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/sharelocation-05.jpg
--------------------------------------------------------------------------------
/example-screenshots/simple_01.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/simple_01.jpg
--------------------------------------------------------------------------------
/example-screenshots/wayfinding_12.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/example-screenshots/wayfinding_12.jpg
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | android.enableJetifier=true
2 | android.nonFinalResIds=false
3 | android.nonTransitiveRClass=false
4 | android.useAndroidX=true
5 |
6 | # indoorAtlasApiKey=api-key-here
7 | # indoorAtlasApiSecret=api-secret-here
8 |
9 |
10 | # Reporting endpoint for the Foreground Service example
11 | # backgroundReportEndPoint=https://example.com/report_api/my-android-phone-id
12 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/IndoorAtlas/android-sdk-examples/76c6e937b25001c1193ac5c37277cec49e1d6bff/gradlew
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | include ':Basic'
2 |
3 |
4 |
--------------------------------------------------------------------------------