move to firestore
This commit is contained in:
parent
1433334f15
commit
9a0a49fd38
6
cloud-anchors/.idea/vcs.xml
Normal file
6
cloud-anchors/.idea/vcs.xml
Normal 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>
|
@ -37,7 +37,7 @@ dependencies {
|
||||
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.firebase:firebase-core:16.0.6'
|
||||
implementation 'com.google.firebase:firebase-database:16.0.5'
|
||||
implementation 'com.google.firebase:firebase-firestore:17.1.5'
|
||||
}
|
||||
|
||||
|
||||
|
@ -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"
|
||||
}
|
||||
}
|
@ -36,8 +36,8 @@ class MainActivity : AppCompatActivity() {
|
||||
private val TAG = MainActivity::class.java.canonicalName
|
||||
|
||||
private lateinit var arFragment: CloudArFragment
|
||||
private lateinit var storageManager: StorageManager
|
||||
private var cloudAnchorState = CloudAnchorState.LOCAL
|
||||
private val cloudAnchorsHelper = CloudAnchorsHelper()
|
||||
private var cloudAnchorState = CloudAnchorState.NONE
|
||||
private var cloudAnchor: Anchor? = null
|
||||
set(value) {
|
||||
field?.detach()
|
||||
@ -50,8 +50,6 @@ class MainActivity : AppCompatActivity() {
|
||||
if (!checkIsSupportedDeviceOrFinish(this, TAG))
|
||||
return
|
||||
|
||||
storageManager = StorageManager(this)
|
||||
|
||||
setContentView(R.layout.activity_main)
|
||||
|
||||
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) {
|
||||
if (cloudAnchorState != CloudAnchorState.LOCAL)
|
||||
if (cloudAnchorState != CloudAnchorState.NONE)
|
||||
return
|
||||
|
||||
cloudAnchor = arFragment.arSceneView.session
|
||||
@ -90,7 +88,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
if (cloudState.isError) {
|
||||
toastError()
|
||||
cloudAnchorState = CloudAnchorState.LOCAL
|
||||
cloudAnchorState = CloudAnchorState.NONE
|
||||
return
|
||||
}
|
||||
|
||||
@ -98,29 +96,25 @@ class MainActivity : AppCompatActivity() {
|
||||
return
|
||||
|
||||
if (cloudAnchorState == CloudAnchorState.HOSTING)
|
||||
checkHosting(cloudState)
|
||||
checkHosting()
|
||||
else
|
||||
checkResolving(cloudState)
|
||||
checkResolving()
|
||||
}
|
||||
|
||||
private fun checkResolving(state: Anchor.CloudAnchorState) {
|
||||
private fun checkResolving() {
|
||||
Toast.makeText(this, "Anchor resolved!", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
cloudAnchorState = CloudAnchorState.RESOLVED
|
||||
}
|
||||
|
||||
private fun checkHosting(state: Anchor.CloudAnchorState) {
|
||||
storageManager.nextShortCode { shortCode ->
|
||||
if (shortCode == null) {
|
||||
toastError()
|
||||
return@nextShortCode
|
||||
}
|
||||
storageManager.storeUsingShortCode(shortCode, cloudAnchor?.cloudAnchorId)
|
||||
private fun checkHosting() {
|
||||
val cAnchor = cloudAnchor ?: return
|
||||
|
||||
Toast.makeText(this, "Anchor hosted with code $shortCode", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
Log.d("NORANGEBIT", "$shortCode")
|
||||
}
|
||||
val shortCode = cloudAnchorsHelper.getShortCode(cAnchor.cloudAnchorId)
|
||||
|
||||
Toast.makeText(this, "Anchor hosted with code $shortCode", Toast.LENGTH_LONG)
|
||||
.show()
|
||||
Log.d("NORANGEBIT", "$shortCode")
|
||||
|
||||
cloudAnchorState = CloudAnchorState.HOSTED
|
||||
}
|
||||
@ -130,8 +124,8 @@ class MainActivity : AppCompatActivity() {
|
||||
.show()
|
||||
|
||||
private fun onResolveOkPressed(dialogValue: String) {
|
||||
val shortCode = Integer.parseInt(dialogValue)
|
||||
storageManager.getCloudAnchorID(shortCode) {
|
||||
val shortCode = dialogValue.toInt()
|
||||
cloudAnchorsHelper.getCloudAnchorId(shortCode) {
|
||||
cloudAnchor = arFragment.arSceneView.session
|
||||
.resolveCloudAnchor(it)
|
||||
|
||||
@ -146,7 +140,7 @@ class MainActivity : AppCompatActivity() {
|
||||
fun onClearClick(view: View) {
|
||||
cloudAnchor?.detach()
|
||||
cloudAnchor = null
|
||||
cloudAnchorState = CloudAnchorState.LOCAL
|
||||
cloudAnchorState = CloudAnchorState.NONE
|
||||
}
|
||||
|
||||
fun onResolveClick(view: View) {
|
||||
|
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
@ -29,12 +29,8 @@ import android.os.Build
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
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.Node
|
||||
import com.google.ar.sceneform.math.Vector3
|
||||
import com.google.ar.sceneform.rendering.*
|
||||
import com.google.ar.sceneform.ux.ArFragment
|
||||
import com.google.ar.sceneform.ux.TransformableNode
|
||||
@ -62,10 +58,6 @@ fun checkIsSupportedDeviceOrFinish(activity: Activity, tag: String): Boolean {
|
||||
return true
|
||||
}
|
||||
|
||||
operator fun ArFragment.invoke(λ: ArFragment.() -> Unit) = λ()
|
||||
|
||||
fun isTrackig(trackable: Trackable) = trackable.trackingState == TrackingState.TRACKING
|
||||
|
||||
fun buildRenderable(
|
||||
context: Context,
|
||||
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 {
|
||||
val anchorNode = AnchorNode(anchor)
|
||||
@ -142,7 +85,7 @@ fun addTransformableNodeToScene(arFragment: ArFragment, anchor: Anchor, renderab
|
||||
}
|
||||
|
||||
enum class CloudAnchorState {
|
||||
LOCAL,
|
||||
NONE,
|
||||
HOSTING,
|
||||
HOSTED,
|
||||
RESOLVING,
|
||||
|
Loading…
Reference in New Issue
Block a user