add example app
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index e80e2d2..d780c39 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -21,9 +21,9 @@
           java-version: 11
           distribution: adopt
       - name: Gradle Build Action
-        run: ./gradlew :app:assembleDebug
+        run: ./gradlew :exampleApp:assembleDebug
       - name: Upload artifact
         uses: actions/upload-artifact@v2
         with:
           name: app-debug.apk
-          path: app/build/outputs/apk/debug/app-debug.apk
+          path: exampleApp/build/outputs/apk/debug/exampleApp-debug.apk
diff --git a/FaceShared/build.gradle b/FaceShared/build.gradle
index 7fa02cf..8c48df2 100644
--- a/FaceShared/build.gradle
+++ b/FaceShared/build.gradle
@@ -58,4 +58,12 @@
 dependencies {
 	implementation('androidx.annotation:annotation:1.6.0')
 	implementation('org.tensorflow:tensorflow-lite:2.11.0')
+	constraints {
+		implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.0") {
+			because("kotlin-stdlib-jdk7 is now a part of kotlin-stdlib")
+		}
+		implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.0") {
+			because("kotlin-stdlib-jdk8 is now a part of kotlin-stdlib")
+		}
+	}
 }
\ No newline at end of file
diff --git a/exampleApp/.gitignore b/exampleApp/.gitignore
new file mode 100644
index 0000000..42afabf
--- /dev/null
+++ b/exampleApp/.gitignore
@@ -0,0 +1 @@
+/build
\ No newline at end of file
diff --git a/exampleApp/build.gradle b/exampleApp/build.gradle
new file mode 100644
index 0000000..a7d9c9c
--- /dev/null
+++ b/exampleApp/build.gradle
@@ -0,0 +1,43 @@
+plugins {
+	id 'com.android.application'
+}
+
+android {
+	namespace 'com.libremobileos.facedetect'
+	compileSdk 33
+
+	defaultConfig {
+		applicationId "com.libremobileos.yifan.face.example"
+		minSdk 28
+		targetSdk 33
+		versionCode 1
+		versionName "1.0"
+		missingDimensionStrategy 'gpu', 'withGpu' // include gpu delegate support. withoutGpu = exclude it
+	}
+
+	buildTypes {
+		release {
+			minifyEnabled false
+			proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
+		}
+	}
+	compileOptions {
+		sourceCompatibility JavaVersion.VERSION_11
+		targetCompatibility JavaVersion.VERSION_11
+	}
+}
+
+dependencies {
+	implementation('androidx.annotation:annotation:1.6.0')
+	implementation('androidx.appcompat:appcompat:1.6.1')
+	implementation(project(':FaceShared'))
+
+	def camerax_version = "1.3.0-alpha04"
+	implementation "androidx.camera:camera-core:${camerax_version}"
+	implementation "androidx.camera:camera-camera2:${camerax_version}"
+	implementation "androidx.camera:camera-lifecycle:${camerax_version}"
+	implementation "androidx.camera:camera-video:${camerax_version}"
+	implementation "androidx.camera:camera-view:${camerax_version}"
+	implementation "androidx.camera:camera-extensions:${camerax_version}"
+	implementation "androidx.exifinterface:exifinterface:1.3.6"
+}
\ No newline at end of file
diff --git a/exampleApp/proguard-rules.pro b/exampleApp/proguard-rules.pro
new file mode 100644
index 0000000..481bb43
--- /dev/null
+++ b/exampleApp/proguard-rules.pro
@@ -0,0 +1,21 @@
+# Add project specific ProGuard rules here.
+# You can control the set of applied configuration files using the
+# proguardFiles setting in build.gradle.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
+
+# Uncomment this to preserve the line number information for
+# debugging stack traces.
+#-keepattributes SourceFile,LineNumberTable
+
+# If you keep the line number information, uncomment this to
+# hide the original source file name.
+#-renamesourcefileattribute SourceFile
\ No newline at end of file
diff --git a/exampleApp/src/main/AndroidManifest.xml b/exampleApp/src/main/AndroidManifest.xml
new file mode 100644
index 0000000..108779a
--- /dev/null
+++ b/exampleApp/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:tools="http://schemas.android.com/tools">
+
+	<uses-feature
+		android:name="android.hardware.camera"
+		android:required="true" />
+
+	<uses-permission android:name="android.permission.CAMERA" />
+
+	<application
+		android:allowBackup="true"
+		android:dataExtractionRules="@xml/data_extraction_rules"
+		android:fullBackupContent="@xml/backup_rules"
+		android:icon="@mipmap/ic_launcher"
+		android:label="@string/app_name"
+		android:supportsRtl="true"
+		android:theme="@style/Theme.FaceDetect"
+		tools:targetApi="31">
+		<activity
+			android:name=".MainActivity"
+			android:exported="true">
+			<intent-filter>
+				<action android:name="android.intent.action.MAIN" />
+
+				<category android:name="android.intent.category.LAUNCHER" />
+			</intent-filter>
+		</activity>
+	</application>
+
+</manifest>
\ No newline at end of file
diff --git a/exampleApp/src/main/java/com/libremobileos/facedetect/BitmapUtils.java b/exampleApp/src/main/java/com/libremobileos/facedetect/BitmapUtils.java
new file mode 100644
index 0000000..dbc303b
--- /dev/null
+++ b/exampleApp/src/main/java/com/libremobileos/facedetect/BitmapUtils.java
@@ -0,0 +1,256 @@
+/*
+ * Copyright 2020 Google LLC. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * File imported without required modifications, only fixing IDE warnings.
+ * Source: https://github.com/googlesamples/mlkit/blob/d10c447f8259b59262582c30c1608cdf38f4e4a0/android/vision-quickstart/app/src/main/java/com/google/mlkit/vision/demo/BitmapUtils.java
+ */
+
+package com.libremobileos.facedetect;
+
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.ImageFormat;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.YuvImage;
+import android.media.Image;
+import android.media.Image.Plane;
+import android.util.Log;
+import androidx.annotation.Nullable;
+import androidx.camera.core.ExperimentalGetImage;
+import androidx.camera.core.ImageProxy;
+
+import java.io.ByteArrayOutputStream;
+import java.nio.ByteBuffer;
+import java.util.Objects;
+
+/** Utils functions for bitmap conversions. */
+public class BitmapUtils {
+	/** Describing a frame info. */
+	public static class FrameMetadata {
+
+		private final int width;
+		private final int height;
+		private final int rotation;
+
+		public int getWidth() {
+			return width;
+		}
+
+		public int getHeight() {
+			return height;
+		}
+
+		public int getRotation() {
+			return rotation;
+		}
+
+		private FrameMetadata(int width, int height, int rotation) {
+			this.width = width;
+			this.height = height;
+			this.rotation = rotation;
+		}
+
+		/** Builder of {@link FrameMetadata}. */
+		public static class Builder {
+
+			private int width;
+			private int height;
+			private int rotation;
+
+			public Builder setWidth(int width) {
+				this.width = width;
+				return this;
+			}
+
+			public Builder setHeight(int height) {
+				this.height = height;
+				return this;
+			}
+
+			public Builder setRotation(int rotation) {
+				this.rotation = rotation;
+				return this;
+			}
+
+			public FrameMetadata build() {
+				return new FrameMetadata(width, height, rotation);
+			}
+		}
+	}
+
+	/** Converts NV21 format byte buffer to bitmap. */
+	@Nullable
+	public static Bitmap getBitmap(ByteBuffer data, FrameMetadata metadata) {
+		data.rewind();
+		byte[] imageInBuffer = new byte[data.limit()];
+		data.get(imageInBuffer, 0, imageInBuffer.length);
+		try {
+			YuvImage image =
+					new YuvImage(
+							imageInBuffer, ImageFormat.NV21, metadata.getWidth(), metadata.getHeight(), null);
+			ByteArrayOutputStream stream = new ByteArrayOutputStream();
+			image.compressToJpeg(new Rect(0, 0, metadata.getWidth(), metadata.getHeight()), 80, stream);
+
+			Bitmap bmp = BitmapFactory.decodeByteArray(stream.toByteArray(), 0, stream.size());
+
+			stream.close();
+			return rotateBitmap(bmp, metadata.getRotation());
+		} catch (Exception e) {
+			Log.e("VisionProcessorBase", "Error: " + e.getMessage());
+		}
+		return null;
+	}
+
+	/** Converts a YUV_420_888 image from CameraX API to a bitmap. */
+	@Nullable
+	@ExperimentalGetImage
+	public static Bitmap getBitmap(ImageProxy image) {
+		FrameMetadata frameMetadata =
+				new FrameMetadata.Builder()
+						.setWidth(image.getWidth())
+						.setHeight(image.getHeight())
+						.setRotation(image.getImageInfo().getRotationDegrees())
+						.build();
+
+		ByteBuffer nv21Buffer =
+				yuv420ThreePlanesToNV21(Objects.requireNonNull(image.getImage()).getPlanes(), image.getWidth(), image.getHeight());
+		return getBitmap(nv21Buffer, frameMetadata);
+	}
+
+	/** Rotates a bitmap if it is converted from a bytebuffer. */
+	private static Bitmap rotateBitmap(
+			Bitmap bitmap, int rotationDegrees) {
+		Matrix matrix = new Matrix();
+
+		// Rotate the image back to straight.
+		matrix.postRotate(rotationDegrees);
+
+		Bitmap rotatedBitmap =
+				Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
+
+		// Recycle the old bitmap if it has changed.
+		if (rotatedBitmap != bitmap) {
+			bitmap.recycle();
+		}
+		return rotatedBitmap;
+	}
+
+	/**
+	 * Converts YUV_420_888 to NV21 bytebuffer.
+	 *
+	 * <p>The NV21 format consists of a single byte array containing the Y, U and V values. For an
+	 * image of size S, the first S positions of the array contain all the Y values. The remaining
+	 * positions contain interleaved V and U values. U and V are subsampled by a factor of 2 in both
+	 * dimensions, so there are S/4 U values and S/4 V values. In summary, the NV21 array will contain
+	 * S Y values followed by S/4 VU values: YYYYYYYYYYYYYY(...)YVUVUVUVU(...)VU
+	 *
+	 * <p>YUV_420_888 is a generic format that can describe any YUV image where U and V are subsampled
+	 * by a factor of 2 in both dimensions. {@link Image#getPlanes} returns an array with the Y, U and
+	 * V planes. The Y plane is guaranteed not to be interleaved, so we can just copy its values into
+	 * the first part of the NV21 array. The U and V planes may already have the representation in the
+	 * NV21 format. This happens if the planes share the same buffer, the V buffer is one position
+	 * before the U buffer and the planes have a pixelStride of 2. If this is case, we can just copy
+	 * them to the NV21 array.
+	 */
+	private static ByteBuffer yuv420ThreePlanesToNV21(
+			Plane[] yuv420888planes, int width, int height) {
+		int imageSize = width * height;
+		byte[] out = new byte[imageSize + 2 * (imageSize / 4)];
+
+		if (areUVPlanesNV21(yuv420888planes, width, height)) {
+			// Copy the Y values.
+			yuv420888planes[0].getBuffer().get(out, 0, imageSize);
+
+			ByteBuffer uBuffer = yuv420888planes[1].getBuffer();
+			ByteBuffer vBuffer = yuv420888planes[2].getBuffer();
+			// Get the first V value from the V buffer, since the U buffer does not contain it.
+			vBuffer.get(out, imageSize, 1);
+			// Copy the first U value and the remaining VU values from the U buffer.
+			uBuffer.get(out, imageSize + 1, 2 * imageSize / 4 - 1);
+		} else {
+			// Fallback to copying the UV values one by one, which is slower but also works.
+			// Unpack Y.
+			unpackPlane(yuv420888planes[0], width, height, out, 0, 1);
+			// Unpack U.
+			unpackPlane(yuv420888planes[1], width, height, out, imageSize + 1, 2);
+			// Unpack V.
+			unpackPlane(yuv420888planes[2], width, height, out, imageSize, 2);
+		}
+
+		return ByteBuffer.wrap(out);
+	}
+
+	/** Checks if the UV plane buffers of a YUV_420_888 image are in the NV21 format. */
+	private static boolean areUVPlanesNV21(Plane[] planes, int width, int height) {
+		int imageSize = width * height;
+
+		ByteBuffer uBuffer = planes[1].getBuffer();
+		ByteBuffer vBuffer = planes[2].getBuffer();
+
+		// Backup buffer properties.
+		int vBufferPosition = vBuffer.position();
+		int uBufferLimit = uBuffer.limit();
+
+		// Advance the V buffer by 1 byte, since the U buffer will not contain the first V value.
+		vBuffer.position(vBufferPosition + 1);
+		// Chop off the last byte of the U buffer, since the V buffer will not contain the last U value.
+		uBuffer.limit(uBufferLimit - 1);
+
+		// Check that the buffers are equal and have the expected number of elements.
+		boolean areNV21 =
+				(vBuffer.remaining() == (2 * imageSize / 4 - 2)) && (vBuffer.compareTo(uBuffer) == 0);
+
+		// Restore buffers to their initial state.
+		vBuffer.position(vBufferPosition);
+		uBuffer.limit(uBufferLimit);
+
+		return areNV21;
+	}
+
+	/**
+	 * Unpack an image plane into a byte array.
+	 *
+	 * <p>The input plane data will be copied in 'out', starting at 'offset' and every pixel will be
+	 * spaced by 'pixelStride'. Note that there is no row padding on the output.
+	 */
+	private static void unpackPlane(
+			Plane plane, int width, int height, byte[] out, int offset, int pixelStride) {
+		ByteBuffer buffer = plane.getBuffer();
+		buffer.rewind();
+
+		// Compute the size of the current plane.
+		// We assume that it has the aspect ratio as the original image.
+		int numRow = (buffer.limit() + plane.getRowStride() - 1) / plane.getRowStride();
+		if (numRow == 0) {
+			return;
+		}
+		int scaleFactor = height / numRow;
+		int numCol = width / scaleFactor;
+
+		// Extract the data in the output buffer.
+		int outputPos = offset;
+		int rowStart = 0;
+		for (int row = 0; row < numRow; row++) {
+			int inputPos = rowStart;
+			for (int col = 0; col < numCol; col++) {
+				out[outputPos] = buffer.get(inputPos);
+				outputPos += pixelStride;
+				inputPos += plane.getPixelStride();
+			}
+			rowStart += plane.getRowStride();
+		}
+	}
+}
\ No newline at end of file
diff --git a/exampleApp/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java b/exampleApp/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java
new file mode 100644
index 0000000..8da8b9e
--- /dev/null
+++ b/exampleApp/src/main/java/com/libremobileos/facedetect/FaceBoundsOverlayView.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright 2023 LibreMobileOS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.libremobileos.facedetect;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.util.Pair;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.libremobileos.yifan.face.ImageUtils;
+
+import java.util.List;
+
+public class FaceBoundsOverlayView extends View {
+
+	private List<Pair<RectF, String>> bounds = null;
+	private Paint paint, textPaint;
+	private Matrix transform = null;
+	private int extraWidth, extraHeight, viewWidth, viewHeight, sensorWidth, sensorHeight;
+
+	public FaceBoundsOverlayView(Context context) {
+		this(context, null);
+	}
+
+	public FaceBoundsOverlayView(Context context, @Nullable AttributeSet attrs) {
+		this(context, attrs, 0);
+	}
+
+	public FaceBoundsOverlayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+		this(context, attrs, defStyleAttr, 0);
+	}
+
+	public FaceBoundsOverlayView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+		super(context, attrs, defStyleAttr, defStyleRes);
+	}
+
+	@Override
+	protected void onDraw(Canvas canvas) {
+		super.onDraw(canvas);
+		if (bounds == null || transform == null || paint == null)
+			return; // am I ready yet?
+ 		for (Pair<RectF, String> bound : bounds) {
+			canvas.drawRect(bound.first, paint);
+			if (bound.second != null)
+				canvas.drawText(bound.second, bound.first.left, bound.first.bottom, textPaint);
+		}
+	}
+
+	@Override
+	protected void onSizeChanged(int w, int h, int oldWidth, int oldHeight) {
+		super.onSizeChanged(w, h, oldWidth, oldHeight);
+		viewWidth = w;
+		viewHeight = h;
+		transform = null;
+	}
+
+	// please give me RectF's that wont be used otherwise as I modify them
+	public void updateBounds(List<Pair<RectF, String>> inputBounds, int sensorWidth, int sensorHeight) {
+		this.bounds = inputBounds;
+		// if we have no paint yet, make one
+		if (paint == null) {
+			paint = new Paint();
+			paint.setStyle(Paint.Style.STROKE);
+			paint.setStrokeWidth(10f);
+			paint.setColor(Color.RED);
+		}
+		if (textPaint == null) {
+			textPaint = new Paint();
+			textPaint.setColor(Color.RED);
+			textPaint.setTextSize(100);
+		}
+		// if camera size or view size changed, recalculate it
+		if (this.sensorWidth != sensorWidth || this.sensorHeight != sensorHeight || (viewWidth + viewHeight) > 0) {
+			this.sensorWidth = sensorWidth;
+			this.sensorHeight = sensorHeight;
+			int oldWidth = viewWidth;
+			int oldHeight = viewHeight;
+			extraWidth = 0;
+			extraHeight = 0;
+			// calculate scaling keeping aspect ratio
+			int newHeight = (int)((oldWidth / (float)sensorWidth) * sensorHeight);
+			int newWidth = (int)((oldHeight / (float)sensorHeight) * sensorWidth);
+			// calculate out black bars
+			if (newWidth > oldWidth) {
+				extraHeight = (oldHeight - newHeight) / 2;
+				viewHeight = newHeight;
+			} else {
+				extraWidth = (oldWidth - newWidth) / 2;
+				viewWidth = newWidth;
+			}
+			// scale from image size to view size
+			transform = ImageUtils.getTransformationMatrix(sensorWidth, sensorHeight, viewWidth, viewHeight, 0, false);
+			viewWidth = 0; viewHeight = 0;
+		}
+		// map bounds to view size
+		for (Pair<RectF, String> bound : bounds) {
+			transform.mapRect(bound.first);
+			bound.first.offset(extraWidth, extraHeight);
+		}
+		invalidate();
+	}
+}
diff --git a/exampleApp/src/main/java/com/libremobileos/facedetect/MainActivity.java b/exampleApp/src/main/java/com/libremobileos/facedetect/MainActivity.java
new file mode 100644
index 0000000..a3243d1
--- /dev/null
+++ b/exampleApp/src/main/java/com/libremobileos/facedetect/MainActivity.java
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2023 LibreMobileOS
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.libremobileos.facedetect;
+
+import android.content.res.Configuration;
+import android.graphics.Matrix;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.util.Pair;
+import android.util.Size;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.EditText;
+import android.widget.ImageView;
+import android.widget.TextView;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.OptIn;
+import androidx.appcompat.app.AlertDialog;
+import androidx.appcompat.app.AppCompatActivity;
+import androidx.camera.core.CameraSelector;
+import androidx.camera.core.ExperimentalGetImage;
+import androidx.camera.core.ImageAnalysis;
+import androidx.camera.core.Preview;
+import androidx.camera.lifecycle.ProcessCameraProvider;
+import androidx.camera.view.PreviewView;
+
+import com.google.common.util.concurrent.ListenableFuture;
+
+import com.libremobileos.yifan.face.FaceRecognizer;
+import com.libremobileos.yifan.face.FaceStorageBackend;
+import com.libremobileos.yifan.face.SharedPreferencesFaceStorageBackend;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+public class MainActivity extends AppCompatActivity {
+
+	// CameraX boilerplate
+	private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
+	// View showing camera frames
+	private PreviewView previewView;
+	// AI-based detector
+	private FaceRecognizer faceRecognizer;
+	// Simple view allowing us to draw Rectangles over the Preview
+	private FaceBoundsOverlayView overlayView;
+	// The desired camera input size
+	private final Size desiredInputSize = new Size(640, 480);
+	// The calculated actual processing width & height
+	private int width, height;
+	// Store registered Faces in Memory
+	private FaceStorageBackend faceStorage;
+	// If we are waiting for a face to be added to knownFaces
+	private boolean addPending = false;
+
+	@Override
+	protected void onCreate(@Nullable Bundle savedInstanceState) {
+		// Initialize basic views
+		super.onCreate(savedInstanceState);
+		setContentView(R.layout.activity_main);
+		previewView = findViewById(R.id.viewFinder);
+		previewView.setScaleType(PreviewView.ScaleType.FIT_CENTER);
+		overlayView = findViewById(R.id.overlay);
+		overlayView.setOnClickListener(v -> addPending = true);
+		setTitle(getString(R.string.tap_to_add_face));
+
+		// CameraX boilerplate (create camera connection)
+		cameraProviderFuture = ProcessCameraProvider.getInstance(this);
+		cameraProviderFuture.addListener(() -> {
+			try {
+				ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
+				bindPreview(cameraProvider);
+			} catch (ExecutionException | InterruptedException e) {
+				// No errors need to be handled for this Future.
+				// This should never be reached.
+			}
+		}, getMainExecutor());
+
+	}
+
+	@OptIn(markerClass = ExperimentalGetImage.class)
+	private void bindPreview(@NonNull ProcessCameraProvider cameraProvider) {
+		// We're connected to the camera, set up everything
+		Preview preview = new Preview.Builder()
+				.build();
+
+		// Which camera to use
+		int selectedCamera = CameraSelector.LENS_FACING_FRONT;
+		CameraSelector cameraSelector = new CameraSelector.Builder()
+				.requireLensFacing(selectedCamera)
+				.build();
+
+		preview.setSurfaceProvider(previewView.getSurfaceProvider());
+
+		// Cameras give us landscape images. If we are in portrait mode
+		// (and want to process a portrait image), swap width/height to
+		// make the image portrait.
+		if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
+			width = desiredInputSize.getHeight();
+			height = desiredInputSize.getWidth();
+		} else {
+			width = desiredInputSize.getWidth();
+			height = desiredInputSize.getHeight();
+		}
+
+		// Set up CameraX boilerplate and configure it to drop frames if we can't keep up
+		ImageAnalysis imageAnalysis =
+				new ImageAnalysis.Builder()
+						.setTargetResolution(new Size(width, height))
+						.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
+						.build();
+
+		imageAnalysis.setAnalyzer(getMainExecutor(), imageProxy -> {
+			// Convert CameraX Image to Bitmap and process it
+			// Return list of detected faces
+			List<FaceRecognizer.Face> data = faceRecognizer.recognize(BitmapUtils.getBitmap(imageProxy));
+			ArrayList<Pair<RectF, String>> bounds = new ArrayList<>();
+
+			for (FaceRecognizer.Face face : data) {
+				RectF boundingBox = new RectF(face.getLocation());
+
+				// Camera is frontal so the image is flipped horizontally,
+				// so flip it again.
+				Matrix flip = new Matrix();
+				flip.postScale(-1, 1, width / 2.0f, height / 2.0f);
+				flip.mapRect(boundingBox);
+
+				// Generate UI text for face
+				String uiText;
+				// Do we want to add a new face?
+				if (addPending) {
+					// If we want to add a new face, show the dialog.
+					runOnUiThread(() -> showAddFaceDialog(face));
+					addPending = false;
+				}
+				// Do we have any match?
+				if (face.isRecognized()) {
+					// If yes, show the user-visible ID and the detection confidence
+					uiText = face.getModelCount() + " " + face.getTitle() + " " + face.getDistance();
+				} else {
+					// Show detected object type (always "Face") and how confident the AI is that this is a Face
+					uiText = face.getTitle() + " " + face.getDetectionConfidence();
+				}
+				bounds.add(new Pair<>(boundingBox, uiText));
+			}
+
+			// Pass bounds to View drawing rectangles
+			overlayView.updateBounds(bounds, width, height);
+			// Clean up
+			imageProxy.close();
+		});
+
+		// Bind all objects together
+		/* Camera camera = */ cameraProvider.bindToLifecycle(this, cameraSelector, imageAnalysis, preview);
+
+		// Create AI-based face detection
+		//faceStorage = new VolatileFaceStorageBackend();
+		faceStorage = new SharedPreferencesFaceStorageBackend(getSharedPreferences("faces", 0));
+		faceRecognizer = FaceRecognizer.create(this,
+				faceStorage, /* face data storage */
+				0.6f, /* minimum confidence to consider object as face */
+				width, /* bitmap width */
+				height, /* bitmap height */
+				0, /* CameraX rotates the image for us, so we chose to IGNORE sensorRotation altogether */
+				0.7f, /* maximum distance to track face */
+				1 /* minimum model count to track face */
+		);
+	}
+
+	private void showAddFaceDialog(FaceRecognizer.Face rec) {
+		AlertDialog.Builder builder = new AlertDialog.Builder(this);
+		LayoutInflater inflater = getLayoutInflater();
+		View dialogLayout = inflater.inflate(R.layout.image_edit_dialog, null);
+		ImageView ivFace = dialogLayout.findViewById(R.id.dlg_image);
+		TextView tvTitle = dialogLayout.findViewById(R.id.dlg_title);
+		EditText etName = dialogLayout.findViewById(R.id.dlg_input);
+
+		tvTitle.setText(R.string.add_face);
+		// Add preview of cropped face to verify we're adding the correct one
+		ivFace.setImageBitmap(rec.getCrop());
+		etName.setHint(R.string.input_name);
+
+		builder.setPositiveButton(R.string.ok, (dlg, i) -> {
+			String name = etName.getText().toString();
+			if (name.isEmpty()) {
+				return;
+			}
+			// Save facial features in knownFaces
+			if (!faceStorage.extendRegistered(name, rec.getExtra(), true)) {
+				Toast.makeText(this, R.string.register_failed, Toast.LENGTH_LONG).show();
+			}
+			dlg.dismiss();
+		});
+		builder.setView(dialogLayout);
+		builder.show();
+	}
+
+}
diff --git a/exampleApp/src/main/res/drawable-v24/ic_launcher_foreground.xml b/exampleApp/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 0000000..c6aee64
--- /dev/null
+++ b/exampleApp/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,30 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+	xmlns:aapt="http://schemas.android.com/aapt"
+	android:width="108dp"
+	android:height="108dp"
+	android:viewportWidth="108"
+	android:viewportHeight="108">
+	<path android:pathData="M31,63.928c0,0 6.4,-11 12.1,-13.1c7.2,-2.6 26,-1.4 26,-1.4l38.1,38.1L107,108.928l-32,-1L31,63.928z">
+		<aapt:attr name="android:fillColor">
+			<gradient
+				android:endX="85.84757"
+				android:endY="92.4963"
+				android:startX="42.9492"
+				android:startY="49.59793"
+				android:type="linear">
+				<item
+					android:color="#44000000"
+					android:offset="0.0" />
+				<item
+					android:color="#00000000"
+					android:offset="1.0" />
+			</gradient>
+		</aapt:attr>
+	</path>
+	<path
+		android:fillColor="#FFFFFF"
+		android:fillType="nonZero"
+		android:pathData="M65.3,45.828l3.8,-6.6c0.2,-0.4 0.1,-0.9 -0.3,-1.1c-0.4,-0.2 -0.9,-0.1 -1.1,0.3l-3.9,6.7c-6.3,-2.8 -13.4,-2.8 -19.7,0l-3.9,-6.7c-0.2,-0.4 -0.7,-0.5 -1.1,-0.3C38.8,38.328 38.7,38.828 38.9,39.228l3.8,6.6C36.2,49.428 31.7,56.028 31,63.928h46C76.3,56.028 71.8,49.428 65.3,45.828zM43.4,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2c-0.3,-0.7 -0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C45.3,56.528 44.5,57.328 43.4,57.328L43.4,57.328zM64.6,57.328c-0.8,0 -1.5,-0.5 -1.8,-1.2s-0.1,-1.5 0.4,-2.1c0.5,-0.5 1.4,-0.7 2.1,-0.4c0.7,0.3 1.2,1 1.2,1.8C66.5,56.528 65.6,57.328 64.6,57.328L64.6,57.328z"
+		android:strokeWidth="1"
+		android:strokeColor="#00000000" />
+</vector>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/drawable/ic_launcher_background.xml b/exampleApp/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 0000000..4e12b43
--- /dev/null
+++ b/exampleApp/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="utf-8"?>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+	android:width="108dp"
+	android:height="108dp"
+	android:viewportWidth="108"
+	android:viewportHeight="108">
+	<path
+		android:fillColor="#3DDC84"
+		android:pathData="M0,0h108v108h-108z" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M9,0L9,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,0L19,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M29,0L29,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M39,0L39,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M49,0L49,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M59,0L59,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M69,0L69,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M79,0L79,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M89,0L89,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M99,0L99,108"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,9L108,9"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,19L108,19"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,29L108,29"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,39L108,39"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,49L108,49"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,59L108,59"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,69L108,69"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,79L108,79"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,89L108,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M0,99L108,99"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,29L89,29"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,39L89,39"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,49L89,49"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,59L89,59"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,69L89,69"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M19,79L89,79"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M29,19L29,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M39,19L39,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M49,19L49,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M59,19L59,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M69,19L69,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+	<path
+		android:fillColor="#00000000"
+		android:pathData="M79,19L79,89"
+		android:strokeWidth="0.8"
+		android:strokeColor="#33FFFFFF" />
+</vector>
diff --git a/exampleApp/src/main/res/layout/activity_main.xml b/exampleApp/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000..1f0ca0c
--- /dev/null
+++ b/exampleApp/src/main/res/layout/activity_main.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:layout_width="match_parent"
+	android:layout_height="match_parent"
+	android:orientation="vertical">
+
+	<androidx.camera.view.PreviewView
+		android:id="@+id/viewFinder"
+		android:layout_width="match_parent"
+		android:layout_height="match_parent" />
+
+	<com.libremobileos.facedetect.FaceBoundsOverlayView
+		android:id="@+id/overlay"
+		android:layout_width="match_parent"
+		android:layout_height="match_parent" />
+
+</FrameLayout>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/layout/image_edit_dialog.xml b/exampleApp/src/main/res/layout/image_edit_dialog.xml
new file mode 100644
index 0000000..60e46ca
--- /dev/null
+++ b/exampleApp/src/main/res/layout/image_edit_dialog.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+	android:layout_width="wrap_content"
+	android:layout_height="wrap_content"
+	xmlns:tools="http://schemas.android.com/tools"
+	android:orientation="vertical"
+	android:padding="16dp">
+
+	<TextView
+		android:id="@+id/dlg_title"
+		android:layout_gravity="center"
+		android:textSize="20sp"
+		tools:text="The dialog title"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"/>
+
+	<ImageView
+		android:layout_gravity="center"
+		android:id="@+id/dlg_image"
+		android:layout_width="200dp"
+		android:layout_height="200dp"
+		android:scaleType="centerCrop"
+		android:adjustViewBounds="true"
+		/>
+
+	<EditText
+		android:layout_gravity="center"
+		android:id="@+id/dlg_input"
+		android:layout_width="wrap_content"
+		android:layout_height="wrap_content"
+		tools:hint="The dialog hint"
+		/>
+
+
+</LinearLayout>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/exampleApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 0000000..65bd9d3
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+	<background android:drawable="@drawable/ic_launcher_background" />
+	<foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/exampleApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 0000000..65bd9d3
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+	<background android:drawable="@drawable/ic_launcher_background" />
+	<foreground android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/mipmap-anydpi-v33/ic_launcher.xml b/exampleApp/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
new file mode 100644
index 0000000..52ac069
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-anydpi-v33/ic_launcher.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+	<background android:drawable="@drawable/ic_launcher_background" />
+	<foreground android:drawable="@drawable/ic_launcher_foreground" />
+	<monochrome android:drawable="@drawable/ic_launcher_foreground" />
+</adaptive-icon>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/exampleApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..4eaccdd
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-hdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/exampleApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/exampleApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..7baaea0
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-mdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/exampleApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/exampleApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..9b01b6d
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/exampleApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/exampleApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..bfc2f07
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/exampleApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/exampleApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
new file mode 100644
index 0000000..0ee89d8
--- /dev/null
+++ b/exampleApp/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png
Binary files differ
diff --git a/exampleApp/src/main/res/values/colors.xml b/exampleApp/src/main/res/values/colors.xml
new file mode 100644
index 0000000..d95bf93
--- /dev/null
+++ b/exampleApp/src/main/res/values/colors.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+	<color name="purple_200">#FFBB86FC</color>
+	<color name="purple_500">#FF6200EE</color>
+	<color name="purple_700">#FF3700B3</color>
+	<color name="teal_200">#FF03DAC5</color>
+	<color name="teal_700">#FF018786</color>
+	<color name="black">#FF000000</color>
+	<color name="white">#FFFFFFFF</color>
+</resources>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/values/strings.xml b/exampleApp/src/main/res/values/strings.xml
new file mode 100644
index 0000000..573d092
--- /dev/null
+++ b/exampleApp/src/main/res/values/strings.xml
@@ -0,0 +1,8 @@
+<resources>
+	<string name="app_name">FaceDetect</string>
+	<string name="add_face">Add Face</string>
+	<string name="input_name">Input name</string>
+	<string name="ok">OK</string>
+	<string name="tap_to_add_face">Tap anywhere to add face</string>
+	<string name="register_failed">Registering the face failed.</string>
+</resources>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/values/themes.xml b/exampleApp/src/main/res/values/themes.xml
new file mode 100644
index 0000000..aaa8e1b
--- /dev/null
+++ b/exampleApp/src/main/res/values/themes.xml
@@ -0,0 +1,6 @@
+<resources xmlns:tools="http://schemas.android.com/tools">
+	<!-- Base application theme. -->
+	<style name="Theme.FaceDetect" parent="Theme.AppCompat.DayNight">
+		<!-- Customize your theme here. -->
+	</style>
+</resources>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/xml/backup_rules.xml b/exampleApp/src/main/res/xml/backup_rules.xml
new file mode 100644
index 0000000..26457c5
--- /dev/null
+++ b/exampleApp/src/main/res/xml/backup_rules.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+   Sample backup rules file; uncomment and customize as necessary.
+   See https://developer.android.com/guide/topics/data/autobackup
+   for details.
+   Note: This file is ignored for devices older that API 31
+   See https://developer.android.com/about/versions/12/backup-restore
+-->
+<full-backup-content>
+   <exclude domain="sharedpref" path="faces.xml"/>
+</full-backup-content>
\ No newline at end of file
diff --git a/exampleApp/src/main/res/xml/data_extraction_rules.xml b/exampleApp/src/main/res/xml/data_extraction_rules.xml
new file mode 100644
index 0000000..3fc20df
--- /dev/null
+++ b/exampleApp/src/main/res/xml/data_extraction_rules.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+   Sample data extraction rules file; uncomment and customize as necessary.
+   See https://developer.android.com/about/versions/12/backup-restore#xml-changes
+   for details.
+-->
+<data-extraction-rules>
+	<cloud-backup>
+		<exclude domain="sharedpref" path="faces.xml" />
+	</cloud-backup>
+    <device-transfer>
+	    <exclude domain="sharedpref" path="faces.xml" />
+    </device-transfer>
+</data-extraction-rules>
\ No newline at end of file
diff --git a/settings.gradle b/settings.gradle
index 72e3b45..d3d6890 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -13,5 +13,6 @@
 	}
 }
 rootProject.name = "FaceDetect"
-include ':app'
-include ':FaceShared'
\ No newline at end of file
+include ':FaceShared'
+include ':exampleApp'
+include ':app'
\ No newline at end of file