move to firestore

This commit is contained in:
Raffaele Mignone 2019-01-21 18:23:12 +01:00
parent 1433334f15
commit 9a0a49fd38
Signed by: norangebit
GPG Key ID: 4B9DF72AB9508845
6 changed files with 102 additions and 180 deletions

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
</component>
</project>

View File

@ -37,7 +37,7 @@ dependencies {
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation "com.google.ar.sceneform.ux:sceneform-ux:1.6.0" implementation "com.google.ar.sceneform.ux:sceneform-ux:1.6.0"
implementation 'com.google.firebase:firebase-core:16.0.6' implementation 'com.google.firebase:firebase-core:16.0.6'
implementation 'com.google.firebase:firebase-database:16.0.5' implementation 'com.google.firebase:firebase-firestore:17.1.5'
} }

View File

@ -0,0 +1,77 @@
/*
* Copyright (c) 2019, norangebit
*
* This file is part of cloud-anchors.
*
* cloud-anchors is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* cloud-anchors is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with cloud-anchors. If not, see <http://www.gnu.org/licenses/>
*
*/
package it.norangeb.cloudanchors
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.SetOptions
class CloudAnchorsHelper {
private val fireStoreDb = FirebaseFirestore.getInstance()
private var nextCode = 0
init {
fireStoreDb.collection(COLLECTION)
.document(DOCUMENT)
.get()
.addOnSuccessListener {
val nCode = it.data?.get(NEXT_CODE) ?: return@addOnSuccessListener
nextCode = nCode.toString().toInt()
}
}
fun getShortCode(cloudAnchorId: String): Int {
fireStoreDb.collection(COLLECTION)
.document(DOCUMENT)
.set(
mapOf(Pair(nextCode.toString(), cloudAnchorId)),
SetOptions.merge())
uploadNextCode(nextCode+1)
return nextCode++
}
private fun uploadNextCode(nextCode: Int) {
fireStoreDb.collection(COLLECTION)
.document(DOCUMENT)
.set(
mapOf(Pair(NEXT_CODE, nextCode)),
SetOptions.merge()
)
}
fun getCloudAnchorId(
shortCode: Int,
onSuccess: (String) -> Unit
) {
fireStoreDb.collection(COLLECTION)
.document(DOCUMENT)
.get()
.addOnSuccessListener {
val x = it.data?.get(shortCode.toString()) as String
onSuccess(x)
}
}
companion object {
private const val COLLECTION = "short_codes"
private const val DOCUMENT = "short_codes_doc"
private const val NEXT_CODE = "next_short_code"
}
}

View File

@ -36,8 +36,8 @@ class MainActivity : AppCompatActivity() {
private val TAG = MainActivity::class.java.canonicalName private val TAG = MainActivity::class.java.canonicalName
private lateinit var arFragment: CloudArFragment private lateinit var arFragment: CloudArFragment
private lateinit var storageManager: StorageManager private val cloudAnchorsHelper = CloudAnchorsHelper()
private var cloudAnchorState = CloudAnchorState.LOCAL private var cloudAnchorState = CloudAnchorState.NONE
private var cloudAnchor: Anchor? = null private var cloudAnchor: Anchor? = null
set(value) { set(value) {
field?.detach() field?.detach()
@ -50,8 +50,6 @@ class MainActivity : AppCompatActivity() {
if (!checkIsSupportedDeviceOrFinish(this, TAG)) if (!checkIsSupportedDeviceOrFinish(this, TAG))
return return
storageManager = StorageManager(this)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as CloudArFragment arFragment = supportFragmentManager.findFragmentById(R.id.ar_fragment) as CloudArFragment
@ -63,7 +61,7 @@ class MainActivity : AppCompatActivity() {
} }
private fun addModel(hitResult: HitResult, plane: Plane, motionEvent: MotionEvent) { private fun addModel(hitResult: HitResult, plane: Plane, motionEvent: MotionEvent) {
if (cloudAnchorState != CloudAnchorState.LOCAL) if (cloudAnchorState != CloudAnchorState.NONE)
return return
cloudAnchor = arFragment.arSceneView.session cloudAnchor = arFragment.arSceneView.session
@ -90,7 +88,7 @@ class MainActivity : AppCompatActivity() {
if (cloudState.isError) { if (cloudState.isError) {
toastError() toastError()
cloudAnchorState = CloudAnchorState.LOCAL cloudAnchorState = CloudAnchorState.NONE
return return
} }
@ -98,29 +96,25 @@ class MainActivity : AppCompatActivity() {
return return
if (cloudAnchorState == CloudAnchorState.HOSTING) if (cloudAnchorState == CloudAnchorState.HOSTING)
checkHosting(cloudState) checkHosting()
else else
checkResolving(cloudState) checkResolving()
} }
private fun checkResolving(state: Anchor.CloudAnchorState) { private fun checkResolving() {
Toast.makeText(this, "Anchor resolved!", Toast.LENGTH_LONG) Toast.makeText(this, "Anchor resolved!", Toast.LENGTH_LONG)
.show() .show()
cloudAnchorState = CloudAnchorState.RESOLVED cloudAnchorState = CloudAnchorState.RESOLVED
} }
private fun checkHosting(state: Anchor.CloudAnchorState) { private fun checkHosting() {
storageManager.nextShortCode { shortCode -> val cAnchor = cloudAnchor ?: return
if (shortCode == null) {
toastError()
return@nextShortCode
}
storageManager.storeUsingShortCode(shortCode, cloudAnchor?.cloudAnchorId)
Toast.makeText(this, "Anchor hosted with code $shortCode", Toast.LENGTH_LONG) val shortCode = cloudAnchorsHelper.getShortCode(cAnchor.cloudAnchorId)
.show()
Log.d("NORANGEBIT", "$shortCode") Toast.makeText(this, "Anchor hosted with code $shortCode", Toast.LENGTH_LONG)
} .show()
Log.d("NORANGEBIT", "$shortCode")
cloudAnchorState = CloudAnchorState.HOSTED cloudAnchorState = CloudAnchorState.HOSTED
} }
@ -130,8 +124,8 @@ class MainActivity : AppCompatActivity() {
.show() .show()
private fun onResolveOkPressed(dialogValue: String) { private fun onResolveOkPressed(dialogValue: String) {
val shortCode = Integer.parseInt(dialogValue) val shortCode = dialogValue.toInt()
storageManager.getCloudAnchorID(shortCode) { cloudAnchorsHelper.getCloudAnchorId(shortCode) {
cloudAnchor = arFragment.arSceneView.session cloudAnchor = arFragment.arSceneView.session
.resolveCloudAnchor(it) .resolveCloudAnchor(it)
@ -146,7 +140,7 @@ class MainActivity : AppCompatActivity() {
fun onClearClick(view: View) { fun onClearClick(view: View) {
cloudAnchor?.detach() cloudAnchor?.detach()
cloudAnchor = null cloudAnchor = null
cloudAnchorState = CloudAnchorState.LOCAL cloudAnchorState = CloudAnchorState.NONE
} }
fun onResolveClick(view: View) { fun onResolveClick(view: View) {

View File

@ -1,98 +0,0 @@
/**
* This class is made by Google
*
* visit https://codelabs.developers.google.com/codelabs/arcore-cloud-anchors/#4
*/
package it.norangeb.cloudanchors;
import android.content.Context;
import android.util.Log;
import com.google.firebase.FirebaseApp;
import com.google.firebase.database.*;
/** Helper class for Firebase storage of cloud anchor IDs. */
class StorageManager {
/** Listener for a new Cloud Anchor ID from the Firebase Database. */
interface CloudAnchorIdListener {
void onCloudAnchorIdAvailable(String cloudAnchorId);
}
/** Listener for a new short code from the Firebase Database. */
interface ShortCodeListener {
void onShortCodeAvailable(Integer shortCode);
}
private static final String TAG = StorageManager.class.getName();
private static final String KEY_ROOT_DIR = "shared_anchor_codelab_root";
private static final String KEY_NEXT_SHORT_CODE = "next_short_code";
private static final String KEY_PREFIX = "anchor;";
private static final int INITIAL_SHORT_CODE = 142;
private final DatabaseReference rootRef;
StorageManager(Context context) {
FirebaseApp firebaseApp = FirebaseApp.initializeApp(context);
rootRef = FirebaseDatabase.getInstance(firebaseApp).getReference().child(KEY_ROOT_DIR);
DatabaseReference.goOnline();
}
/** Gets a new short code that can be used to store the anchor ID. */
void nextShortCode(ShortCodeListener listener) {
// Run a transaction on the node containing the next short code available. This increments the
// value in the database and retrieves it in one atomic all-or-nothing operation.
rootRef
.child(KEY_NEXT_SHORT_CODE)
.runTransaction(
new Transaction.Handler() {
@Override
public Transaction.Result doTransaction(MutableData currentData) {
Integer shortCode = currentData.getValue(Integer.class);
if (shortCode == null) {
shortCode = INITIAL_SHORT_CODE - 1;
}
currentData.setValue(shortCode + 1);
return Transaction.success(currentData);
}
@Override
public void onComplete(
DatabaseError error, boolean committed, DataSnapshot currentData) {
if (!committed) {
Log.e(TAG, "Firebase Error", error.toException());
listener.onShortCodeAvailable(null);
} else {
listener.onShortCodeAvailable(currentData.getValue(Integer.class));
}
}
});
}
/** Stores the cloud anchor ID in the configured Firebase Database. */
void storeUsingShortCode(int shortCode, String cloudAnchorId) {
rootRef.child(KEY_PREFIX + shortCode).setValue(cloudAnchorId);
}
/**
* Retrieves the cloud anchor ID using a short code. Returns an empty string if a cloud anchor ID
* was not stored for this short code.
*/
void getCloudAnchorID(int shortCode, CloudAnchorIdListener listener) {
rootRef
.child(KEY_PREFIX + shortCode)
.addListenerForSingleValueEvent(
new ValueEventListener() {
@Override
public void onDataChange(DataSnapshot dataSnapshot) {
listener.onCloudAnchorIdAvailable(String.valueOf(dataSnapshot.getValue()));
}
@Override
public void onCancelled(DatabaseError error) {
Log.e(TAG, "The database operation for getCloudAnchorID was cancelled.",
error.toException());
listener.onCloudAnchorIdAvailable(null);
}
});
}
}

View File

@ -29,12 +29,8 @@ import android.os.Build
import android.util.Log import android.util.Log
import android.widget.Toast import android.widget.Toast
import com.google.ar.core.Anchor import com.google.ar.core.Anchor
import com.google.ar.core.Session
import com.google.ar.core.Trackable
import com.google.ar.core.TrackingState
import com.google.ar.sceneform.AnchorNode import com.google.ar.sceneform.AnchorNode
import com.google.ar.sceneform.Node import com.google.ar.sceneform.Node
import com.google.ar.sceneform.math.Vector3
import com.google.ar.sceneform.rendering.* import com.google.ar.sceneform.rendering.*
import com.google.ar.sceneform.ux.ArFragment import com.google.ar.sceneform.ux.ArFragment
import com.google.ar.sceneform.ux.TransformableNode import com.google.ar.sceneform.ux.TransformableNode
@ -62,10 +58,6 @@ fun checkIsSupportedDeviceOrFinish(activity: Activity, tag: String): Boolean {
return true return true
} }
operator fun ArFragment.invoke(λ: ArFragment.() -> Unit) = λ()
fun isTrackig(trackable: Trackable) = trackable.trackingState == TrackingState.TRACKING
fun buildRenderable( fun buildRenderable(
context: Context, context: Context,
model: Uri, model: Uri,
@ -81,55 +73,6 @@ fun buildRenderable(
} }
} }
fun buildMaterial(
context: Context,
color: Color,
onSuccess: (material: Material) -> Unit
) {
MaterialFactory
.makeOpaqueWithColor(context, color)
.thenAccept(onSuccess)
}
fun changeColorOfMaterial(
context: Context,
color: Color,
renderable: Renderable
) {
val newColor = buildMaterial(context, color) {
renderable.material = it
}
}
/**
fun buildRenderable(
context: Context,
model: RenderableSource,
modelUri: Uri,
onSuccess: (renderable: Renderable) -> Unit
) {
ModelRenderable.builder()
.setRegistryId(modelUri)
.setSource(context, model)
.build()
.thenAccept(onSuccess)
.exceptionally {
Log.e("SCENEFORM", "unable to load model", it)
return@exceptionally null
}
}
fun fetchModel(
context: Context,
source: Uri
) : RenderableSource {
return RenderableSource.builder()
.setSource(context, source, RenderableSource.SourceType.GLTF2)
.setRecenterMode(RenderableSource.RecenterMode.ROOT)
.build()
}
*/
fun addTransformableNodeToScene(arFragment: ArFragment, anchor: Anchor, renderable: Renderable): Node { fun addTransformableNodeToScene(arFragment: ArFragment, anchor: Anchor, renderable: Renderable): Node {
val anchorNode = AnchorNode(anchor) val anchorNode = AnchorNode(anchor)
@ -142,7 +85,7 @@ fun addTransformableNodeToScene(arFragment: ArFragment, anchor: Anchor, renderab
} }
enum class CloudAnchorState { enum class CloudAnchorState {
LOCAL, NONE,
HOSTING, HOSTING,
HOSTED, HOSTED,
RESOLVING, RESOLVING,