Google Glass GDK Tap Gesture - google-glass

With GDK and sample code provide by Google the TAP gesture is not being recognized as a TAP. Is returned as LONG_PRESS everytime. Below is the code:
import com.google.android.glass.touchpad.Gesture;
import com.google.android.glass.touchpad.GestureDetector;
public class MainActivity extends Activity {
Logger log = Logger.getLogger("MainActivity");
private GestureDetector mGestureDetector;
// ...
#Override
protected void onCreate(Bundle savedInstanceState) {
// ...
mGestureDetector = createGestureDetector(this);
}
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
//Create a base listener for generic gestures
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
#Override
public boolean onGesture(Gesture gesture) {
log.info(gesture.name());
if (gesture == Gesture.TAP) {
// do something on tap
return true;
} else if (gesture == Gesture.TWO_TAP) {
// do something on two finger tap
return true;
} else if (gesture == Gesture.SWIPE_RIGHT) {
// do something on right (forward) swipe
return true;
} else if (gesture == Gesture.SWIPE_LEFT) {
// do something on left (backwards) swipe
return true;
}
return false;
}
});
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
// do something on finger count changes
}
});
gestureDetector.setScrollListener(new GestureDetector.ScrollListener() {
#Override
public boolean onScroll(float displacement, float delta, float velocity) {
// do something on scrolling
}
});
return gestureDetector;
}
/*
* Send generic motion events to the gesture detector
*/
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mGestureDetector != null) {
return mGestureDetector.onMotionEvent(event);
}
return false;
}
}
Am I missing something here or is this a bug?

If you're only looking to capture tap events for a UI (without using GestureDetector and everything), in Glass touchpad taps are registered as center clicking a d-pad, so you can simply intercept the KEYCODE_DPAD_CENTER key presses.
Try this:
public boolean onKeyDown(int keyCode, KeyEvent event) {
if(keyCode == KeyEvent.KEYCODE_DPAD_CENTER){
// The touchpad was tapped
return true;
}
return false;
}

I had the same problem as you and my answer could be strange but I avoided it using a switch instead of the if else structure. Moreover with this new code you will be able to capture the rest of the gestures.
I hope it will help you as well.
private GestureDetector createGestureDetector(Context context){
GestureDetector gestureDetector = new GestureDetector(context);
//Create a base listener for generic gestures
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
#Override
public boolean onGesture(Gesture gesture) {
Log.e(TAG,"gesture = " + gesture);
switch (gesture) {
case TAP:
Log.e(TAG,"TAP called.");
handleGestureTap();
break;
case LONG_PRESS:
Log.e(TAG,"LONG_PRESS called.");
return true;
case SWIPE_DOWN:
Log.e(TAG,"SWIPE_DOWN called.");
return true;
case SWIPE_LEFT:
Log.e(TAG,"SWIPE_LEFT called.");
return true;
case SWIPE_RIGHT:
Log.e(TAG,"SWIPE_RIGHT called.");
return true;
case SWIPE_UP:
Log.e(TAG,"SWIPE_UP called.");
return true;
case THREE_LONG_PRESS:
Log.e(TAG,"THREE_LONG_PRESS called.");
return true;
case THREE_TAP:
Log.e(TAG,"THREE_TAP called.");
return true;
case TWO_LONG_PRESS:
Log.e(TAG,"TWO_LONG_PRESS called.");
return true;
case TWO_SWIPE_DOWN:
Log.e(TAG,"TWO_SWIPE_DOWN called.");
return true;
case TWO_SWIPE_LEFT:
Log.e(TAG,"TWO_SWIPE_LEFT called.");
return true;
case TWO_SWIPE_RIGHT:
Log.e(TAG,"TWO_SWIPE_RIGHT called.");
return true;
case TWO_SWIPE_UP:
Log.e(TAG,"TWO_SWIPE_UP called.");
return true;
case TWO_TAP:
Log.e(TAG,"TWO_TAP called.");
return true;
}
return false;
}
});
gestureDetector.setFingerListener(new com.google.android.glass.touchpad.GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
// do something on finger count changes
Log.e(TAG,"onFingerCountChanged()");
}
});
gestureDetector.setScrollListener(new com.google.android.glass.touchpad.GestureDetector.ScrollListener() {
#Override
public boolean onScroll(float displacement, float delta, float velocity) {
// do something on scrolling
Log.e(TAG,"onScroll()");
return false;
}
});
return gestureDetector;
}

Copying and pasting the GestureDetector code from the GDK and modifying it is all you should need to do. If it's working for double tap then I'd suspect you may have some hardware issue with Glass.
Have you tried doing a Toast for Gesture.TAP? Perhaps TAP and LONG PRESS are the same?
The code below will call generateCard() when you tap Glass.
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
//Create a base listener for generic gestures
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
#Override
public boolean onGesture(Gesture gesture) {
if (gesture == Gesture.TAP) { // On Tap, generate a new number
generateCard();
return true;
} else if (gesture == Gesture.TWO_TAP) {
// do something on two finger tap
return true;
} else if (gesture == Gesture.SWIPE_RIGHT) {
// do something on right (forward) swipe
return true;
} else if (gesture == Gesture.SWIPE_LEFT) {
// do something on left (backwards) swipe
return true;
}
return false;
}
});
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
// do something on finger count changes
}
});
gestureDetector.setScrollListener(new GestureDetector.ScrollListener() {
#Override
public boolean onScroll(float displacement, float delta, float velocity) {
// do something on scrolling
return false;
}
});
return gestureDetector;
}
/*
* Send generic motion events to the gesture detector
*/
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mGestureDetector != null) {
return mGestureDetector.onMotionEvent(event);
}
return false;
}

Related

contextual action mode only works for one time

i did a contextual action mode and it is working very well when i click on the options that i created but the problem is it the action mode only works for one time and to enable it again i have exit the app and run it again
here's my code
Button.setOnLongClickListener(new View.OnLongClickListener() {
#Override
public boolean onLongClick(View v) {
if (actionMode != null) {
return false;
}
actionMode = startActionMode(startActionMode);
return true;
}
});
}
private ActionMode.Callback startActionMode = new ActionMode.Callback() {
#Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
mode.getMenuInflater().inflate(R.menu.menu12, menu);
mode.setTitle("choose your option");
return true;
}
#Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
#Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
switch (item.getItemId()) {
case R.id.item1:
Toast.makeText(MainActivity.this, "item 1 pressed", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
case R.id.item2:
Toast.makeText(MainActivity.this, "item 2 pressed", Toast.LENGTH_SHORT).show();
mode.finish();
return true;
default:
return false;
}
}
#Override
public void onDestroyActionMode(ActionMode mode) {
startActionMode = null;
}
};
}
Simply instead of
startActionMode = null;
use
actionMode = null;

numeric soft keyboard in android using ndk

I have a java code that displays the numeric soft keyboard in Android:
public class MainActivity extends Activity {
EditText ed1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ed1 = (EditText) findViewById(R.id.editText1);
ed1.setInputType(InputType.TYPE_CLASS_NUMBER);
}
}
My activity_main.xml file:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="numberkeypad.inputmethod.MainActivity" >
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:ems="10" >
</EditText>
The output is: numeric soft keyboard
I want to display the same keyboard using NDK JNI call and no EditText. I have implemented the default keyboard in this way using the following link:
How to show the soft keyboard on native activity
But I am facing a lot of trouble using the same methodology for the numeric keyboard. Any help would be great..Thanks!
Could not find a way to do this directly, had to override the onCreateInputConnection method of View class, and then make a JNI call to a function using the overridden method.
public class NumbersView extends View {
public NumbersView(Context context) {
super(context);
}
#Override
public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
switch(SystemKeyboardType){
case InputType.TYPE_CLASS_PHONE:
outAttrs.inputType |= InputType.TYPE_CLASS_PHONE;
break;
case InputType.TYPE_CLASS_TEXT:
outAttrs.inputType |= InputType.TYPE_CLASS_TEXT;
break;
case InputType.TYPE_CLASS_NUMBER:
outAttrs.inputType |= InputType.TYPE_CLASS_NUMBER;
break;
case InputType.TYPE_CLASS_DATETIME:
outAttrs.inputType |= InputType.TYPE_CLASS_DATETIME;
break;
default:
outAttrs.inputType |= InputType.TYPE_CLASS_TEXT;
break;
}
return inputConnection;
}
}
**/
#Override
protected void onCreate(Bundle savedInstanceState) {
calculateDeviceDPI();
super.onCreate(savedInstanceState);
myView = new NumbersView(getApplicationContext());
addContentView(myView,new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
myView.setFocusable(true);
myView.setFocusableInTouchMode(true);
//myView.requestFocus();
mContext = this;
}
public void displaySystemKeyboard(String keyboardType){
if(keyboardType.equals("text")) {
SystemKeyboardType = InputType.TYPE_CLASS_TEXT;
}
else if(keyboardType.equals("phone")) {
SystemKeyboardType = InputType.TYPE_CLASS_PHONE;
}
else if(keyboardType.equals("number")) {
SystemKeyboardType = InputType.TYPE_CLASS_NUMBER;
}
else if(keyboardType.equals("datetime")) {
SystemKeyboardType = InputType.TYPE_CLASS_DATETIME;
}
else {
SystemKeyboardType = InputType.TYPE_CLASS_DATETIME;
}
Context ctx = getApplicationContext();
InputMethodManager mgr = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
myView.requestFocus();
// only will trigger it if no physical keyboard is open
mgr.restartInput(myView);
mgr.showSoftInput(myView, 0);
}
public void hideSystemKeyboard(){
Context ctx = getApplicationContext();
View myView = this.getWindow().getDecorView();
InputMethodManager mgr = (InputMethodManager) ctx.getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(myView.getWindowToken(), 0);
}
And finally made a JNI call to the function:
if(pShow){
jmethodID showSysKeys = lJNIEnv->GetMethodID(lClassDeviceAPI,"displaySystemKeyboard","(Ljava/lang/String;)V");
if(showSysKeys == NULL){
LOGI("displaySystemKeyboard::Couldn't get void displaySystemKeyboard Method");
return;
}
jstring keyboardType = lJNIEnv->NewStringUTF(KeyboardType.c_str());
if(!keyboardType)
{
LOGI( "failed to alloc param string in java." );
return;
};
lJNIEnv->CallVoidMethod(lObjDeviceAPI,showSysKeys, keyboardType);
}
else{
jmethodID hideSysKeys = lJNIEnv->GetMethodID(lClassDeviceAPI,"hideSystemKeyboard","()V");
if(hideSysKeys == NULL){
LOGI("hideSystemKeyboard::Couldn't get void hideSystemKeyboard Method");
return;
}
lJNIEnv->CallVoidMethod(lObjDeviceAPI,hideSysKeys);
}
lJavaVM->DetachCurrentThread();

CardBuilder show more text

is it possible to arrange Show more button using GDK now? I have pretty big portion of text which I would like to split for few cards for example.
Thank you for help.
The issue with Google Glass is that you can't really "button" in the way that you're thinking. You can't tap on a certain part of the screen. You only can swipe down, up, left, right, and tap.
What you can do, is listen for those possible gestures and then act accordingly - maybe create a TextBox that can scroll and scroll through it on the swipes. Or maybe go to the next card/update the text in the card when you tap. Here is how you detect these actions:
You need to create a GestureDetector. Here is how I do it in my projects:
public class EXAMPLE {
private GestureDetector gestureDetector;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gestureDetector = createGestureDetector(this);
}
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetectorTemp = new GestureDetector(context, new GestureDetector.OnGestureListener() {
#Override
public boolean onDown(MotionEvent motionEvent) {
return false;
}
#Override
public void onShowPress(MotionEvent motionEvent) {
return false;
}
#Override
public boolean onSingleTapUp(MotionEvent motionEvent) {
return false;
}
#Override
public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent2, float distanceX, float distanceY) {
return false;
}
#Override
public void onLongPress(MotionEvent motionEvent) {
}
#Override
public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent2, float v, float v2) {
return false;
}
});
return gestureDetectorTemp;
}
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (gestureDetector != null) {
return gestureDetector.onTouchEvent(event);
}
return false;
}
}
That last part is very important. On any generic motion event, if the gestureDetector isn't null, you'll send the event through the gestureDetector for processing.
KEEP IN MIND ALSO that you need to understand what the return false; and return true; things mean. If you return false, then that means that the event wasn't consumed. If you return true, then the event is consumed. In other words, if you return true, then nothing else will activate, because the event gets 'eaten up,' but if you return false, this sends the event on to other functions which may do something when an action is taken.
Now just take this, and change the onSingleTapUp() method's contents to do what you want...something like
card.setText(nextSetOfText);
or
textView.setText(nextSetOfText);
You could split your long text into an array of strings with the maximum length that'll fit on the string, then just cycle to the next string in your array when the person taps.

ViewPager not working in Google Glass after XE16 update

My Glass got updated to XE16 and thereafter Viewpagers used in Glassware is not working. It is not possible to move to any of the pagers by swiping.If anybody has encountered this before,please do help.
Thanks
Heh. Yeah, the update removed certain standard things from happening (like gestures on the touchpad moving focus etc).
What you have to do is implement a gesturerecogniser/listener and implement the necessary fields, like so (don't forget to instantiate/implement/import etc etc etc in the activity)):
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
//Create a base listener for generic gestures
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
#Override
public boolean onGesture(Gesture gesture) {
if (gesture == Gesture.TAP) {
// do something on tap
//do ?
return false;
} else if (gesture == Gesture.TWO_TAP) {
// do something on two finger tap
return true;
} else if (gesture == Gesture.LONG_PRESS) {
// do something on long press
if (!showingMenu)
{
openOptionsMenu();
return true;
}
else
{
return false;
}
} else if (gesture == Gesture.SWIPE_RIGHT) {
// do something on right (forward) swipe
//next slide:
mPosition++;
if (mPosition >= cardArray.size())
{
mPosition = cardArray.size() -1;
}
mGallery.setSelection(mPosition);
return true;
} else if (gesture == Gesture.SWIPE_LEFT) {
// do something on left (backwards) swipe
//previous slide:
mPosition--;
if (mPosition < 0)
{
mPosition = 0;
}
mGallery.setSelection(mPosition);
return true;
}
return false;
}
});
gestureDetector.setFingerListener(new GestureDetector.FingerListener() {
#Override
public void onFingerCountChanged(int previousCount, int currentCount) {
// do something on finger count changes
}
});
/*gestureDetector.setScrollListener(new GestureDetector.ScrollListener() {
#Override
public boolean onScroll(float displacement, float delta, float velocity) {
// do something on scrolling
if (delta > 5.0f)
{
//scroll forwards:
//
}
else if (delta < -5.0f)
{
//scroll backwards:
//
}
return false;
}
});*/
return gestureDetector;
}
/*
* Send generic motion events to the gesture detector
*/
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mGestureDetector != null) {
return mGestureDetector.onMotionEvent(event);
}
return false;
}
I replaced my Viewpager with CardScrollView and it is pretty fast as well.
Do try that out.

Receiving touch events on CardScrollView

I have a CardScrollView that has multiple items in it and I would like to be able to pull up a menu on an item, similar to the built in Timeline.
I know Card cannot have a specific menu attached to it so I have the menu prepared at the Activity level.
However, something seems to be swallowing all onKeyDown events.
public class HostsView extends CardScrollView {
private String TAG = "HostsView";
private HostsCardScrollAdapter cards;
private Activity parent;
public HostsView(Activity parent, HostDatabase hostDb) {
super(parent);
cards = new HostsCardScrollAdapter(parent);
//populates the cards and what not
this.setAdapter(cards);
this.activate();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
//I never see this log
Log.d(TAG, "Key event " + event.toString());
if (keyCode == KeyEvent.KEYCODE_DPAD_CENTER) {
parent.openOptionsMenu();
return true;
}
return super.onKeyDown(keyCode, event);
}
}
If you only need to handle a simple tap on a card in a CardScrollView, you can call setOnItemClickListener to attach an AdapterView.OnItemClickListener, just as you would with a standard Android ListView. This is typically much simpler than working with GestureDetector for this basic use case.
yesterday I came across the same problem. I solved it with a GestureDetector, as the GDK documentation recommends. Here is the code I used:
private GestureDetector mGestureDetector;
#Override
public void onCreate(Bundle savedInstanceState) {
mGestureDetector = createGestureDetector(this);
}
private GestureDetector createGestureDetector(Context context) {
GestureDetector gestureDetector = new GestureDetector(context);
gestureDetector.setBaseListener( new GestureDetector.BaseListener() {
#Override
public boolean onGesture(Gesture gesture) {
if (gesture == Gesture.LONG_PRESS || gesture == Gesture.TAP) {
Log.d(MainActivity.TAG, "Tap"); //When I tap the touch panel, I only get LONG_PRESS
openOptionsMenu();
return true;
} else if (gesture == Gesture.TWO_TAP) {
return true;
} else if (gesture == Gesture.SWIPE_RIGHT) {
return true;
} else if (gesture == Gesture.SWIPE_LEFT) {
return true;
}
return false;
}
});
return gestureDetector;
}
#Override
public boolean onGenericMotionEvent(MotionEvent event) {
if (mGestureDetector != null) {
return mGestureDetector.onMotionEvent(event);
}
return false;
}
Your menu should open now!