Log in or register to post comments

Show and hide a View

October 22, 2012 - 10:25am #1

Hi

 

I'm working with de ImageTargets example, i want to show a View when trackable is detected, and hide the View when there's no trackables detected.

I already have the layout, and can show the View on screen, but i don't know how to hide the view when the trackable is no longer on camera.

Can someone please help me?

Show and hide a View

November 28, 2012 - 8:29am #14

Hi Warren, is this related to Android or to Unity ?

if that's about Unity, please post it in the Unity section of the Forum.

Show and hide a View

November 28, 2012 - 8:10am #13

How do i make the ImageTracker have a transparent shader so that i can have stuff coming up from below the 'ground'

I tried to change to Ulint /trans shader but it swaps it back at runtime.

Show and hide a View

November 1, 2012 - 2:14pm #12

OK, the problem could likely be that you only send a message to the Handler for each trackable detected (from the _renderFrame() code in ImageTargets.cpp), but maybe you also need to say that a certain Trackable (e.g. "Stones" trackable, or "Chips" trackable), which was tracked in the previous frame, it is no longer active in the current frame;

so, you probably need to keep track of the Trackable names that are active at each render frame (see line "state.getNumActiveTrackables()" and also "state.getActiveTrackable( i )" in renderFrame() method in ImageTargets.cpp);

for instance, at a given frame you might have "Stones" trackable and the "Chips" trackable both active (so state.getNumActiveTrackables() will be = 2); but at the next frame, suppose "Stones" gets lost, then the state object of QCAR will only report "Chips" as active trackable; so you'll need to compare the trackable names at the current frame with the array of names at the previous frame, so to realize that "Stones" was there before, but it is no longer there at the current frame;

this will allow you to detect that "Stones" got lost, and thus it will allow you to fire an event (i.e. to send a message to the Handler); 

in this message you can specify that the trackable was lost by putting an integer code in the "message.what" field and the name of the trackable in the message.obj (like you do now);

for instance, you can say message.what = 1 to indicate a target detected, and message.what = 0 to indicate a target lost.

so, for instance the following might be used to say that "Stones" was lost:

message.obj = "Stones";

message.what = 0; // 0 means lost (in our own convention)

while the following could indicate that "Chips" was detected:

message.obj = "Chips";

message.what = 1; //1 means detected  (in our own convention)

 

I hope this heps.

 

Show and hide a View

October 31, 2012 - 10:11am #11

Hi

That's a temporary code to get an id to send it to a data base, but works fine.

My doubt it's on the part of the first "if".

Whit the code I can show the View, but i need to hide it with a button to execute "view.setVisibility(View.GONE);", y want to hide the View if the traclable it's lost from camera, that's why a used "  if (msg!=null)"  but it's not working, i think i'm using a wrong variable or missing something. in that part.

Show and hide a View

October 31, 2012 - 9:00am #10

Hi, happy to hear I was helpful :-)

About your code: it looks all right, but not sure what you mean by doing "id = 1" or "id = 2" (it's not clear how the id variable is used in your code) .... also, what is your doubt in particular?

 

 

Show and hide a View

October 31, 2012 - 8:59am #9

Hi Alessandro

 

Thank you for the explanation, that helped me a lot.

Now i using the example and now i can show and hide my view with a Button using the instructions you told meSmile.

I have a small doubt, I want to hide the view if it does not detect the trackable, I send my code for review, I think I'm leaving overlook something:

ImageTargets.cpp

 

protected void onResume()

    {

     DebugLog.LOGD("ImageTargets::onResume");

          super.onResume();

          QCAR.onResume();

 

              ImageTargetsRenderer.mainActivityHandler = new Handler() {

                  @Override

                  public void handleMessage(Message msg) {

                 String text = (String) msg.obj;

                 if (msg!=null) {

                 mid.setVisibility(View.VISIBLE);

                 if (text.equals("stones")) {

                 id="1";}

                 else {

                 id="2";

                 }

                 }

                 else {

                 mid.setVisibility(View.GONE);

                 }

                   }     

              };

    }

 

 

 

Show and hide a View

October 26, 2012 - 1:49pm #8

You can choose how many classes to create in Java and how you spread the code through the application (so there are many ways of achieveing the same result); 

the only couple of RULES to keep in mind when working with JNI are these:

If you want to call a native (C++) method from a Java class:

1. the native function must be declared as "native" within tthe same class (e.g. "private void native myNativeFunction();)  ,

2. and the function name in native code must "reflect" the name of the Java class from which the method is called, e.g.:

So, suppose you have a class called MyClass in a package called "com.qualcomm" (so the full class name is "com.qualcomm.MyClass") and in this class you have declared a "private void native myNativeMethod()",   then the C++ function will have to be named like that:

JNIEXPORT void JNICALL  Java_com_qualcomm_MyClass_myNativeMethod (JNIEnv* env, jobject javaObject) {   /* some code */  }

NOTE that the jobject javaObject argument represents the MyClass instance that is invoking your native method.

 

Second rule: for what concerns calling Java methods from a native C++ code, you need to use the CallVoidMethod (or CallIntMethod, CallFloatMethod, depending on the return type) by passing the javaObject that represents a certain Java class instance (for instance an instance of com.qualcomm.MyClass),;

consider the following example taken from Dominoes.cpp (see displayMessage() method):

jstring js = javaEnv->NewStringUTF(message);

jmethodID method = javaEnv->GetMethodID(javaClass, "displayMessage", "(Ljava/lang/String;)V");

javaEnv->CallVoidMethod(javaObj, method, js); 

As you can see here we invoke the Java method "displayMessage()" by using CallVoidMethod and by passing "javaObj" as argument; in this example, the javaClass represents the DominoesRenderer class and the javaObject is an instance of DominoesRenderer in this case because those two variables have been initialized in the Java_com_qualcomm_QCARSamples_Dominoes_DominoesRenderer_initNativeCallback,

but it could have been a different class as well, if we initialized those somewhere else; so it really depends how you want to structure your application (e.g. spreading into multiple classes or just in a few).

I hope this can be of help;

I can also suggest to have a look at the JNI tutorial at:

http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/jniTOC.html

This can help get you started with all sort of JNI acrobacies :-)

 

 

 

Show and hide a View

October 26, 2012 - 10:31am #7

Hi Alessandro

Actually I had found this information, this is how I show in this moment the View on screen.

My problem it's i don't know how i need to program the JNI to show and hide the View when trackable it's detected.

I've been reading the code of Dominoes example, i think i need a new java class for this, isn't it? or, can I add the code to the existing ImageTargetsRenderer.java where I added the Handler?

 

Thanks in advance

Show and hide a View

October 23, 2012 - 8:16am #6

Hi, concerning the link that you cannot acess, I'm copying the text here below:

 

The Vuforia samples handle tracking events in the native renderFrame method, which is called on the GL thread. In order to make changes to the Android UI in response to a tracking event, two concepts must be used: JNI (Java Native Interface) calls from native code to Java, and cross-thread calls from the GL thread to the main thread. The latter is required because the Android UI can only be modified from the main (UI) thread.

 

The following code snippets show how to display an Android Toast message when a target is first found. Start with the ImageTargets sample and make the following changes to ImageTargets.cpp:

 

int lastTrackableId = -1;

JNIEXPORT void JNICALL
Java_com_qualcomm_QCARSamples_ImageTargets_ImageTargetsRenderer_renderFrame(JNIEnv* env, jobject obj)
{
...

// Did we find any targets this frame?
for(int tIdx = 0; tIdx < state.getNumActiveTrackables(); tIdx++)
{
// Get the target:
const QCAR::Trackable* trackable = state.getActiveTrackable(tIdx);

// Compare this target's id to a globally stored id
// If this is a new target, find the displayMessage java method and
// call it with the target's name
if (trackable->getId() != lastTrackableId) {
jstring js = env->NewStringUTF(trackable->getName());
jclass javaClass = env->GetObjectClass(obj);
jmethodID method = env->GetMethodID(javaClass, "displayMessage", "(Ljava/lang/String;)V");
env->CallVoidMethod(obj, method, js);
lastTrackableId = trackable->getId();
}

...
}

...
}

This code uses JNI calls to find the displayMessage method of the ImageTargetsRenderer Java class. Note the "env" and "obj" variables are passed in as arguments to the renderFrame method. The lastTrackableId global variable is used to ensure the message is only displayed once when the target becomes active.

 

Next, add the following to ImageTargetsRenderer.java:

// A handler object for sending messages to the main activity thread
public static Handler mainActivityHandler;

// Called from native to display a message
public void displayMessage(String text)
{
// We use a handler because this thread cannot change the UI
Message message = new Message();
message.obj = text;
mainActivityHandler.sendMessage(message);
}

This is the method that the native code will call when the target becomes active. This method will be called from the GL thread, and uses a Handler to queue up a message on the main (UI) thread.

Finally, add the following to ImageTargets.java:

protected void onResume()
{
super.onResume();

// Create a new handler for the renderer thread to use
// This is necessary as only the main thread can make changes to the UI
ImageTargetsRenderer.mainActivityHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
Context context = getApplicationContext();
String text = (String) msg.obj;
int duration = Toast.LENGTH_SHORT;
Toast toast = Toast.makeText(context, text, duration);
toast.show();
}
};

...
}

Here we create a new Handler from the onResume method, which runs on the main (UI) thread, and assign it to the public variable we added to the ImageTargetsRenderer class. When this Handler receives a message it displays a Toast on the screen with the included message (a Toast is a notification that is overlaid on the screen for a few seconds). The Dominoes sample includes more code for changing the UI (e.g. showing/hiding buttons) from native code

Show and hide a View

October 23, 2012 - 8:01am #5

Hi again Alessandro

 

Thanks for the response

I think I understand a little the idea but I have not entirely clear. I'll keep investigating and reading a little more.

Unfortunately i can't enter the link you posted, because when i try to enter, this message appears: You are not authorized to access this page.

I don't know if you can send the information of the page, or maybe give me a little idea?

Thanks for the comparison, and thanks in advance.

Show and hide a View

October 23, 2012 - 12:13am #4

Hi, in ImageTargets.cpp you will find the code that checks if there are any active trackables in the current view (see the "for loop" with "state.getNumActiveTrackables()" in the _renderFrame method)

So, that is the place where you will probably have to plug in your native code that detects whether or not you have some active trackables in the current frame.

From here, you can then call some  method in Java code in your Java activity;
for instance you could define a method "hideMyView()" in your Java activity (that will set your you to invisible), and then call that method from the native code above.

Also, because your "hideMyView" method will make UI modifications (i.e. hiding a view), you will need to make sure that part is called within the main UI thread;
so I would recommend you take a look at this Post here below, which explains precisely how to do that:

https://ar.qualcomm.at/content/android-how-can-i-update-my-ui-response-tracking-events

One last note about setVisibility( VIEW.INVISIBLE ) vs. setVisibility( VIEW.GONE ); you can use eiher one or the other, but there is a subtle difference between the two:

View.GONE This view is invisible, and it doesn't take any space for layout purposes.

View.INVISIBLE This view is invisible, but it still takes up space for layout purposes.

 

Show and hide a View

October 22, 2012 - 1:19pm #3

Hi

I've been investigating, the line i think is view.setVisibility(view.INVISIBLE), but i think i need to change the ImageTargets.cpp?

That's my question. 

I'm not shure if this is right.

Thanks in advance.

Show and hide a View

October 22, 2012 - 12:50pm #2

Hi, a View (in Android) can be hidden just by calling view.setVisibility( VIEW.GONE );

does it answer your question? 

Log in or register to post comments