diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 23cab4f..c6b9544 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -33,6 +33,7 @@
android:screenOrientation="portrait"/>
+
\ No newline at end of file
diff --git a/res/layout/hover_emulator.xml b/res/layout/hover_emulator.xml
new file mode 100644
index 0000000..365ece9
--- /dev/null
+++ b/res/layout/hover_emulator.xml
@@ -0,0 +1,11 @@
+
+
+
+
\ No newline at end of file
diff --git a/src/com/examples/customtouch/HoverEmulatorActivity.java b/src/com/examples/customtouch/HoverEmulatorActivity.java
new file mode 100644
index 0000000..42ede5e
--- /dev/null
+++ b/src/com/examples/customtouch/HoverEmulatorActivity.java
@@ -0,0 +1,45 @@
+package com.examples.customtouch;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * Created by Dave Smith
+ * Xcellent Creations, Inc.
+ * Date: 12/5/12
+ * HoverEmulatorActivity
+ * Transform touch events into hover events
+ */
+public class HoverEmulatorActivity extends Activity implements View.OnHoverListener {
+
+ public static final String TAG = "HoverEmulatorActivity";
+
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.hover_emulator);
+
+ findViewById(R.id.button_hover).setOnHoverListener(this);
+ }
+
+ @Override
+ public boolean onHover(View v, MotionEvent event) {
+ Log.i(TAG, "Hover Event "+getHoverName(event));
+ return false;
+ }
+
+ private String getHoverName(MotionEvent event) {
+ switch (event.getAction()) {
+ case MotionEvent.ACTION_HOVER_ENTER:
+ return "HOVER_ENTER";
+ case MotionEvent.ACTION_HOVER_MOVE:
+ return "HOVER_MOVE";
+ case MotionEvent.ACTION_HOVER_EXIT:
+ return "HOVER_EXIT";
+ default:
+ return "";
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/examples/customtouch/HoverEmulatorButton.java b/src/com/examples/customtouch/HoverEmulatorButton.java
new file mode 100644
index 0000000..54222db
--- /dev/null
+++ b/src/com/examples/customtouch/HoverEmulatorButton.java
@@ -0,0 +1,99 @@
+package com.examples.customtouch;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.widget.Button;
+
+/**
+ * Created by Dave Smith
+ * Xcellent Creations, Inc.
+ * Date: 12/5/12
+ * HoverEmulatorButton
+ * Button that transforms single pointer events into hovers and multitouch events into taps
+ */
+public class HoverEmulatorButton extends Button {
+
+ public HoverEmulatorButton(Context context) {
+ super(context);
+ }
+
+ public HoverEmulatorButton(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public HoverEmulatorButton(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ switch (event.getPointerCount()) {
+ case 1:
+ handleSingleTouchEvent(event);
+ break;
+ default:
+ handleMultitouchEvent(event);
+ break;
+ }
+
+ return true;
+ }
+
+ private void handleSingleTouchEvent(MotionEvent event) {
+ switch(event.getAction()) {
+ case MotionEvent.ACTION_DOWN:
+ event.setAction(MotionEvent.ACTION_HOVER_ENTER);
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ event.setAction(MotionEvent.ACTION_HOVER_EXIT);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ event.setAction(MotionEvent.ACTION_HOVER_MOVE);
+ break;
+ default:
+ //Ignore unknown events
+ return;
+ }
+
+ //Forward the converted event to the proper callback
+ super.dispatchGenericMotionEvent(event);
+ }
+
+ /*
+ * Forward all events with multiple fingers to super as if they were single pointer
+ * touch events
+ */
+ private void handleMultitouchEvent(MotionEvent event) {
+ //Construct a new event that only contains a single pointer
+ MotionEvent newEvent = MotionEvent.obtain(
+ event.getDownTime(),
+ event.getEventTime(),
+ 0,
+ event.getX(),
+ event.getY(),
+ event.getMetaState()
+ );
+
+ switch (event.getActionMasked()) {
+ case MotionEvent.ACTION_POINTER_DOWN:
+ newEvent.setAction(MotionEvent.ACTION_DOWN);
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ case MotionEvent.ACTION_CANCEL:
+ newEvent.setAction(MotionEvent.ACTION_UP);
+ break;
+ case MotionEvent.ACTION_MOVE:
+ //Leave this even unchanged
+ newEvent.setAction(MotionEvent.ACTION_MOVE);
+ break;
+ default:
+ //Ignore unknown events
+ return;
+ }
+
+ //Forward the new event to super
+ super.onTouchEvent(newEvent);
+ }
+}
diff --git a/src/com/examples/customtouch/MainActivity.java b/src/com/examples/customtouch/MainActivity.java
index 67d3333..6b54640 100644
--- a/src/com/examples/customtouch/MainActivity.java
+++ b/src/com/examples/customtouch/MainActivity.java
@@ -19,7 +19,7 @@ public class MainActivity extends ListActivity implements OnItemClickListener {
"Pan Example", "Pan Gesture Example",
"Multi-Touch Example", "Touch Forward Example",
"Touch Delegate Example", "Touch Listener Example",
- "Move Logger Example"};
+ "Move Logger Example", "Hover Emulator"};
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -53,6 +53,9 @@ public void onItemClick(AdapterView> parent, View view, int position, long id)
case 6: //Move Logger View
startActivity(new Intent(this, MoveLoggerActivity.class));
break;
+ case 7: //Hover emulator
+ startActivity(new Intent(this, HoverEmulatorActivity.class));
+ break;
default:
break;
}