I am trying to host a cloud anchor on google arcore cloud api. I have included the api key in my manifest. I can also see the request that the android device makes when I want to host an anchor and there is also a response being sent back from the api as can be seen in the image below.
However, the cloud anchor state never changes to SUCCESS and I am never receiving the cloud anchor id back from google even though I have set up an update listener to do so as can be seen below. From debugging the program I can see that the AppAnchorState is never being changed from NONE but I haven't managed to gather any other information.
I am using both sceneform and arcore 1.7.0. Below is the code I am using to try and host my anchor and get a cloud anchor id back from the api.
Any help would be greatly appreciated as I have been struggling with the problem for hours at this stage.
public class ArActivity extends AppCompatActivity {
private enum AppAnchorState {
NONE,
HOSTING,
HOSTED,
RESOLVING,
RESOLVED
}
private AppAnchorState appAnchorState = AppAnchorState.NONE;
private static final String TAG = ArActivity.class.getSimpleName();
private static final double MIN_OPENGL_VERSION = 3.0;
private static final String GLTF_ASSET = "https://github.com/KhronosGroup/glTF-Sample-Models/raw/master/2.0/Duck/glTF/Duck.gltf";
private ArFragment arFragment;
private ModelRenderable renderable;
private SnackbarHelper snackbarHelper;
private Anchor cloudAnchor;
@Override
@SuppressWarnings({"AndroidApiChecker", "FutureReturnValueIgnored"})
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (!checkIsSupportedDeviceOrFinish(this)) {
return;
}
snackbarHelper = new SnackbarHelper();
setContentView(R.layout.activity_ux);
arFragment = (CustomArFragment) getSupportFragmentManager().findFragmentById(R.id.sceneform_fragment);
arFragment.getArSceneView().getScene().addOnUpdateListener(this::onUpdateFrame);
ModelRenderable.builder()
.setSource(this, RenderableSource.builder().setSource(
this,
Uri.parse(GLTF_ASSET),
RenderableSource.SourceType.GLTF2)
.build())
.setRegistryId(GLTF_ASSET)
.build()
.thenAccept(renderable -> this.renderable = renderable)
.exceptionally(
throwable -> {
Toast toast =
Toast.makeText(this, "Unable to load renderable " +
GLTF_ASSET, Toast.LENGTH_LONG);
toast.setGravity(Gravity.CENTER, 0, 0);
toast.show();
return null;
});
Button clearButton = findViewById(R.id.clear_button);
clearButton.setOnClickListener(view -> setCloudAnchor(null));
Button hostButton = findViewById(R.id.host_button);
hostButton.setOnClickListener(view -> hostModel());
arFragment.setOnTapArPlaneListener(
(HitResult hitResult, Plane plane, MotionEvent motionEvent) -> {
if (renderable == null) {
return;
}
// Create the Anchor.
Anchor anchor = hitResult.createAnchor();
setCloudAnchor(anchor);
AnchorNode anchorNode = new AnchorNode(cloudAnchor);
TransformableNode node = new TransformableNode(arFragment.getTransformationSystem());
node.setRenderable(renderable);
node.setParent(anchorNode);
arFragment.getArSceneView().getScene().addChild(anchorNode);
node.select();
});
}
private void hostModel() {
if (cloudAnchor != null) {
arFragment.getArSceneView().getSession().hostCloudAnchor(cloudAnchor);
appAnchorState = AppAnchorState.HOSTING;
snackbarHelper.showMessage(this, "Now hosting anchor...");
} else {
snackbarHelper.showMessage(this, "No anchor to host, Please create an anchor...");
}
}
private void setCloudAnchor (Anchor newAnchor){
if (cloudAnchor != null){
cloudAnchor.detach();
}
cloudAnchor = newAnchor;
appAnchorState = AppAnchorState.NONE;
snackbarHelper.hide(this);
}
private void onUpdateFrame(FrameTime frameTime){
checkUpdatedAnchor();
}
private synchronized void checkUpdatedAnchor(){
if (appAnchorState != AppAnchorState.HOSTING){
return;
}
Anchor.CloudAnchorState cloudState = cloudAnchor.getCloudAnchorState();
if (appAnchorState == AppAnchorState.HOSTING) {
if (cloudState.isError()) {
snackbarHelper.showMessageWithDismiss(this, "Error hosting anchor.. "
+ cloudState);
appAnchorState = AppAnchorState.NONE;
} else if (cloudState == Anchor.CloudAnchorState.SUCCESS) {
snackbarHelper.showMessageWithDismiss(this, "Anchor hosted with id "
+ cloudAnchor.getCloudAnchorId());
appAnchorState = AppAnchorState.HOSTED;
}
}
}
public static boolean checkIsSupportedDeviceOrFinish(final Activity activity) {
String openGlVersionString =
((ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE))
.getDeviceConfigurationInfo()
.getGlEsVersion();
if (Double.parseDouble(openGlVersionString) < MIN_OPENGL_VERSION) {
Log.e(TAG, "Sceneform requires OpenGL ES 3.0 later");
Toast.makeText(activity, "Sceneform requires OpenGL ES 3.0 or later", Toast.LENGTH_LONG)
.show();
activity.finish();
return false;
}
return true;
}
}
public class CustomArFragment extends ArFragment {
@Override
protected Config getSessionConfiguration(Session session) {
Config config = super.getSessionConfiguration(session);
config.setCloudAnchorMode(Config.CloudAnchorMode.ENABLED);
return config;
}
}
So i figured out what my problem was. I wasn't setting the cloud anchor up to listen for the change from the server. That is why I could see the activity on the google api but nothing was happening on the device.
All I had to do was change this piece of code:
private void hostModel() {
if (cloudAnchor != null) {
arFragment.getArSceneView().getSession().hostCloudAnchor(cloudAnchor);
appAnchorState = AppAnchorState.HOSTING;
snackbarHelper.showMessage(this, "Now hosting anchor...");
} else {
snackbarHelper.showMessage(this, "No anchor to host, Please create an anchor...");
}
}
and set cloudAnchor to listen for the changes:
private void hostModel() {
if (cloudAnchor != null) {
cloudAnchor = arFragment.getArSceneView().getSession().hostCloudAnchor(cloudAnchor);
appAnchorState = AppAnchorState.HOSTING;
snackbarHelper.showMessage(this, "Now hosting anchor...");
} else {
snackbarHelper.showMessage(this, "No anchor to host, Please create an anchor...");
}
}