diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyDown.java b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyDown.java
new file mode 100644
index 0000000000..1126f01012
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyDown.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * This annotation is intended to be used on methods to receive action down
+ * event on a key. This annotation can be used on methods of classes which
+ * implements {@link android.view.KeyEvent.Callback}.
+ *
+ *
+ * The annotation value should be one or several of
+ * {@link android.view.KeyEvent} constant fields which name contains KEYCODE. If
+ * not set, the method name will be used as the {@link android.view.KeyEvent}
+ * .KEYCODE_* field name.
+ *
+ *
+ * The method may return a boolean, void, or a
+ * {@link Boolean}. If returning void, it will be considered as
+ * returning true (ie: the method has handled the event).
+ *
+ *
+ * The method MAY have one parameter:
+ *
+ *
+ * - A {@link android.view.KeyEvent} parameter to know which key has been down
+ *
+ *
+ *
+ *
+ * Example :
+ *
+ *
+ *
+ * @EActivity
+ * public class MyActivity extends Activity {
+ *
+ * @KeyDown
+ * void enter() {
+ * // ...
+ * }
+ *
+ * @KeyDown
+ * void onEnter() {
+ * // ...
+ * }
+ *
+ * @KeyDown
+ * void onEnterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyDown
+ * void enterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyDown(KeyEvent.KEYCODE_0)
+ * void keyZeroIsDown(KeyEvent keyEvent) {
+ * // ...
+ * }
+ *
+ * @KeyDown({ KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_N })
+ * boolean multipleKeys(KeyEvent keyEvent) {
+ * return false;
+ * }
+ * }
+ *
+ *
+ * @see android.view.KeyEvent
+ * @see android.view.KeyEvent.Callback
+ * @see android.view.KeyEvent.Callback#onKeyDown(int, android.view.KeyEvent)
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface KeyDown {
+
+ /**
+ * The {@link android.view.KeyEvent} class constants which name contains
+ * KEYCODE.
+ *
+ * @return the value of the key code
+ */
+ int[] value() default {};
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyLongPress.java b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyLongPress.java
new file mode 100644
index 0000000000..be5ff79bdc
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyLongPress.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * This annotation is intended to be used on methods to receive long press event
+ * on a key. This annotation can be used on methods of classes which implements
+ * {@link android.view.KeyEvent.Callback}.
+ *
+ *
+ * The annotation value should be one or several of
+ * {@link android.view.KeyEvent} constant fields which name contains KEYCODE. If
+ * not set, the method name will be used as the {@link android.view.KeyEvent}
+ * .KEYCODE_* field name.
+ *
+ *
+ * The method may return a boolean, void, or a
+ * {@link Boolean}. If returning void, it will be considered as
+ * returning true (ie: the method has handled the event).
+ *
+ *
+ * The method MAY have one parameter:
+ *
+ *
+ * - A {@link android.view.KeyEvent} parameter to know which key has been down
+ *
+ *
+ *
+ *
+ * Example :
+ *
+ *
+ *
+ * @EActivity
+ * public class MyActivity extends Activity {
+ *
+ * @KeyLongPress
+ * void enter() {
+ * // ...
+ * }
+ *
+ * @KeyLongPress
+ * void onEnter() {
+ * // ...
+ * }
+ *
+ * @KeyLongPress
+ * void onEnterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyLongPress
+ * void enterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyLongPress(KeyEvent.KEYCODE_0)
+ * void keyZeroIsLongPressed(KeyEvent keyEvent) {
+ * // ...
+ * }
+ *
+ * @KeyLongPress({ KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_N })
+ * boolean multipleKeys(KeyEvent keyEvent) {
+ * return false;
+ * }
+ * }
+ *
+ *
+ * @see android.view.KeyEvent
+ * @see android.view.KeyEvent.Callback
+ * @see android.view.KeyEvent.Callback#onKeyLongPress(int, android.view.KeyEvent)
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface KeyLongPress {
+
+ /**
+ * The {@link android.view.KeyEvent} class constants which name contains
+ * KEYCODE.
+ *
+ * @return the value of the key code
+ */
+ int[] value() default {};
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyMultiple.java b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyMultiple.java
new file mode 100644
index 0000000000..f444308afd
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyMultiple.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * This annotation is intended to be used on methods to receive action multiple
+ * event on a key. This annotation can be used on methods of classes which
+ * implements {@link android.view.KeyEvent.Callback}.
+ *
+ *
+ * The annotation value should be one or several of
+ * {@link android.view.KeyEvent} constant fields which name contains KEYCODE. If
+ * not set, the method name will be used as the {@link android.view.KeyEvent}
+ * .KEYCODE_* field name.
+ *
+ *
+ * The method may return a boolean, void, or a
+ * {@link Boolean}. If returning void, it will be considered as
+ * returning true (ie: the method has handled the event).
+ *
+ *
+ * The method MAY have one or two parameter:
+ *
+ *
+ * - A {@link android.view.KeyEvent} parameter to know which key has been down
+ *
+ * - A
int or {@link Integer} paramter to know the key is how
+ * many times repeated
+ *
+ *
+ *
+ * Example :
+ *
+ *
+ *
+ * @EActivity
+ * public class MyActivity extends Activity {
+ *
+ * @KeyMultiple
+ * void enter() {
+ * // ...
+ * }
+ *
+ * @KeyMultiple
+ * void onEnter() {
+ * // ...
+ * }
+ *
+ * @KeyMultiple
+ * void onEnterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyMultiple
+ * void enterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyMultiple(KeyEvent.KEYCODE_0)
+ * void keyZeroMultiple(KeyEvent keyEvent) {
+ * // ...
+ * }
+ *
+ * @KeyMultiple({ KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_N })
+ * boolean multipleKeys(KeyEvent keyEvent) {
+ * return false;
+ * }
+ * }
+ *
+ *
+ * @see android.view.KeyEvent
+ * @see android.view.KeyEvent.Callback
+ * @see android.view.KeyEvent.Callback#onKeyMultiple(int, int, android.view.KeyEvent)
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface KeyMultiple {
+
+ /**
+ * The {@link android.view.KeyEvent} class constants which name contains
+ * KEYCODE.
+ *
+ * @return the value of the key code
+ */
+ int[] value() default {};
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyUp.java b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyUp.java
new file mode 100644
index 0000000000..4b16b417e7
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-api/src/main/java/org/androidannotations/annotations/KeyUp.java
@@ -0,0 +1,103 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.annotations;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ *
+ * This annotation is intended to be used on methods to receive action up event
+ * on a key. This annotation can be used on methods of classes which implements
+ * {@link android.view.KeyEvent.Callback}.
+ *
+ *
+ * The annotation value should be one or several of
+ * {@link android.view.KeyEvent} constant fields which name contains KEYCODE. If
+ * not set, the method name will be used as the {@link android.view.KeyEvent}
+ * .KEYCODE_* field name.
+ *
+ *
+ * The method may return a boolean, void, or a
+ * {@link Boolean}. If returning void, it will be considered as
+ * returning true (ie: the method has handled the event).
+ *
+ *
+ * The method MAY have one parameter:
+ *
+ *
+ * - A {@link android.view.KeyEvent} parameter to know which key has been down
+ *
+ *
+ *
+ *
+ * Example :
+ *
+ *
+ *
+ * @EActivity
+ * public class MyActivity extends Activity {
+ *
+ * @KeyUp
+ * void enter() {
+ * // ...
+ * }
+ *
+ * @KeyUp
+ * void onEnter() {
+ * // ...
+ * }
+ *
+ * @KeyUp
+ * void onEnterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyUp
+ * void enterPressed() {
+ * // ...
+ * }
+ *
+ * @KeyUp(KeyEvent.KEYCODE_0)
+ * void keyZeroIsUp(KeyEvent keyEvent) {
+ * // ...
+ * }
+ *
+ * @KeyUp({ KeyEvent.KEYCODE_M, KeyEvent.KEYCODE_N })
+ * boolean multipleKeys(KeyEvent keyEvent) {
+ * return false;
+ * }
+ * }
+ *
+ *
+ * @see android.view.KeyEvent
+ * @see android.view.KeyEvent.Callback
+ * @see android.view.KeyEvent.Callback#onKeyUp(int, android.view.KeyEvent)
+ */
+@Retention(RetentionPolicy.CLASS)
+@Target(ElementType.METHOD)
+public @interface KeyUp {
+
+ /**
+ * The {@link android.view.KeyEvent} class constants which name contains
+ * KEYCODE.
+ *
+ * @return the value of the key code
+ */
+ int[] value() default {};
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/AndroidManifest.xml b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/AndroidManifest.xml
index b88c744268..a42c42c7ae 100644
--- a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/AndroidManifest.xml
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/AndroidManifest.xml
@@ -81,6 +81,7 @@
+
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/keyevents/KeyEventsActivity.java b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/keyevents/KeyEventsActivity.java
new file mode 100644
index 0000000000..20297a5c01
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/main/java/org/androidannotations/test/keyevents/KeyEventsActivity.java
@@ -0,0 +1,73 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.test.keyevents;
+
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.KeyDown;
+import org.androidannotations.annotations.KeyLongPress;
+import org.androidannotations.annotations.KeyMultiple;
+import org.androidannotations.annotations.KeyUp;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+
+@EActivity
+public class KeyEventsActivity extends Activity {
+
+ boolean isEnterDown = false;
+ boolean isUKeyUp = false;
+ boolean isWMultiple = false;
+ boolean isNineMultiple = false;
+ int nineMultipleCount;
+ boolean isELongPressed = false;
+ boolean isELongPressedInAnnotatedClass = false;
+
+ @KeyDown
+ void enterPressed() {
+ isEnterDown = true;
+ }
+
+ @KeyUp
+ void u() {
+ isUKeyUp = true;
+ }
+
+ @KeyMultiple({ KeyEvent.KEYCODE_9, KeyEvent.KEYCODE_W })
+ void multiple(int count, KeyEvent keyEvent) {
+ switch (keyEvent.getKeyCode()) {
+ case KeyEvent.KEYCODE_W:
+ isWMultiple = true;
+ break;
+ case KeyEvent.KEYCODE_9:
+ isNineMultiple = true;
+ nineMultipleCount = count;
+ }
+ }
+
+ @KeyLongPress(KeyEvent.KEYCODE_E)
+ boolean eLongPress() {
+ isELongPressed = true;
+ return false;
+ }
+
+ @Override
+ public boolean onKeyLongPress(int keyCode, KeyEvent event) {
+ if (keyCode == KeyEvent.KEYCODE_E) {
+ isELongPressedInAnnotatedClass = true;
+ }
+ return super.onKeyLongPress(keyCode, event);
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/keyevents/KeyEventsActivityTest.java b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/keyevents/KeyEventsActivityTest.java
new file mode 100644
index 0000000000..97de4d146e
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations-test/src/test/java/org/androidannotations/test/keyevents/KeyEventsActivityTest.java
@@ -0,0 +1,109 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.test.keyevents;
+
+import static org.fest.assertions.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.Robolectric;
+import org.robolectric.RobolectricTestRunner;
+
+import android.view.KeyEvent;
+
+@RunWith(RobolectricTestRunner.class)
+public class KeyEventsActivityTest {
+
+ private KeyEventsActivity activity;
+
+ @Before
+ public void setUp() {
+ activity = Robolectric.buildActivity(KeyEventsActivity_.class).create().get();
+ }
+
+ @Test
+ public void subclassTakesPrecedenceInKeyEventHandling() {
+ KeyEvent keyEvent = mock(KeyEvent.class);
+ int keyCode = KeyEvent.KEYCODE_E;
+
+ activity.onKeyLongPress(keyCode, keyEvent);
+
+ assertThat(activity.isELongPressed).isTrue();
+ assertThat(activity.isELongPressedInAnnotatedClass).isFalse();
+ }
+
+ @Test
+ public void keyDownKeyCodeNameFromMethod() {
+ KeyEvent keyEvent = mock(KeyEvent.class);
+ int keyCode = KeyEvent.KEYCODE_ENTER;
+
+ activity.onKeyDown(keyCode, keyEvent);
+
+ assertThat(activity.isEnterDown).isTrue();
+ }
+
+ @Test
+ public void keyUpKeyCodeNameFromMethod() {
+ KeyEvent keyEvent = mock(KeyEvent.class);
+ int keyCode = KeyEvent.KEYCODE_U;
+
+ activity.onKeyUp(keyCode, keyEvent);
+
+ assertThat(activity.isUKeyUp).isTrue();
+ }
+
+ @Test
+ public void multipleArguments() {
+ KeyEvent keyEvent = mock(KeyEvent.class);
+ int keyCode = KeyEvent.KEYCODE_W;
+ int count = 1;
+
+ when(keyEvent.getKeyCode()).thenReturn(keyCode);
+
+ activity.onKeyMultiple(keyCode, count, keyEvent);
+
+ assertThat(activity.isWMultiple).isTrue();
+ assertThat(activity.isNineMultiple).isFalse();
+ }
+
+ @Test
+ public void keyMultipleWithCount() {
+ KeyEvent keyEvent = mock(KeyEvent.class);
+ int keyCode = KeyEvent.KEYCODE_9;
+ int count = 9;
+
+ when(keyEvent.getKeyCode()).thenReturn(keyCode);
+
+ activity.onKeyMultiple(keyCode, count, keyEvent);
+
+ assertThat(activity.isNineMultiple).isTrue();
+ assertThat(activity.nineMultipleCount).isEqualTo(count);
+ }
+
+ @Test
+ public void goodMethodReturnIfKeyLongPress() {
+ KeyEvent keyEvent = mock(KeyEvent.class);
+ int keyCode = KeyEvent.KEYCODE_E;
+
+ boolean eKeyLongPressReturn = activity.onKeyLongPress(keyCode, keyEvent);
+
+ assertThat(activity.isELongPressed).isTrue();
+ assertThat(eKeyLongPressReturn).isFalse();
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/CanonicalNameConstants.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/CanonicalNameConstants.java
index 5ac9290b79..3b827dd67e 100644
--- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/CanonicalNameConstants.java
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/CanonicalNameConstants.java
@@ -77,6 +77,7 @@ public final class CanonicalNameConstants {
public static final String VIEW_GROUP = "android.view.ViewGroup";
public static final String CONTEXT = "android.content.Context";
public static final String KEY_EVENT = "android.view.KeyEvent";
+ public static final String KEY_EVENT_CALLBACK = "android.view.KeyEvent.Callback";
public static final String LAYOUT_INFLATER = "android.view.LayoutInflater";
public static final String FRAGMENT_ACTIVITY = "android.support.v4.app.FragmentActivity";
public static final String FRAGMENT = "android.app.Fragment";
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/KeyCodeHelper.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/KeyCodeHelper.java
new file mode 100644
index 0000000000..0b8bfe558f
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/helper/KeyCodeHelper.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.helper;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import javax.lang.model.element.AnnotationMirror;
+import javax.lang.model.element.Element;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.element.VariableElement;
+import javax.lang.model.util.ElementFilter;
+
+import org.androidannotations.AndroidAnnotationsEnvironment;
+
+public class KeyCodeHelper extends TargetAnnotationHelper {
+
+ public static final String KEYCODE_PREFIX = "KEYCODE";
+ public static final int KEYCODE_NOT_FOUND = -1;
+
+ private static final Pattern METHOD_NAME_PATTERN = Pattern.compile("^(on)?(.+?)(Pressed)?$");
+
+ private Map keyCodesByName;
+ private Map keyNamesByCode;
+
+ public KeyCodeHelper(AndroidAnnotationsEnvironment environment, String annotationName) {
+ super(environment, annotationName);
+ }
+
+ public int[] extractKeyCode(Element element) {
+ int[] value = extractAnnotationValueParameter(element);
+ if (value.length == 0) {
+ Matcher matcher = METHOD_NAME_PATTERN.matcher(element.getSimpleName());
+ if (matcher.matches()) {
+ String extractedKeyName = matcher.group(2).toLowerCase();
+ String constantName = CaseHelper.camelCaseToUpperSnakeCase(KEYCODE_PREFIX, extractedKeyName, "");
+ int keyCode = getKeyCodeForName(constantName);
+ if (keyCode == KEYCODE_NOT_FOUND) {
+ return value;
+ } else {
+ value = new int[]{keyCode};
+ }
+ }
+ }
+ return value;
+ }
+
+ public int getKeyCodeForName(String fieldName) {
+ if (keyCodesByName == null) {
+ keyCodesByName = new HashMap<>();
+ List keyEventEnclosedFieldElements = getKeyEventEnclosedFieldElements();
+ for (VariableElement element : keyEventEnclosedFieldElements) {
+ if (element.getSimpleName().toString().contains(KEYCODE_PREFIX)) {
+ keyCodesByName.put(element.getSimpleName().toString(), (Integer) element.getConstantValue());
+ }
+ }
+ }
+ Integer keyCode = keyCodesByName.get(fieldName);
+ return keyCode != null ? keyCode : KEYCODE_NOT_FOUND;
+ }
+
+ public String getFieldNameForKeyCode(int keyCode) {
+ if (keyNamesByCode == null) {
+ keyNamesByCode = new HashMap<>();
+ List keyEventEnclosedFieldElements = getKeyEventEnclosedFieldElements();
+ for (VariableElement element : keyEventEnclosedFieldElements) {
+ if (element.getSimpleName().toString().contains(KEYCODE_PREFIX)) {
+ keyNamesByCode.put((Integer) element.getConstantValue(), element.getSimpleName().toString());
+ }
+ }
+ }
+ return keyNamesByCode.get(keyCode);
+ }
+
+ private List getKeyEventEnclosedFieldElements() {
+ TypeElement keyEventElement = getElementUtils().getTypeElement(CanonicalNameConstants.KEY_EVENT);
+ return ElementFilter.fieldsIn(keyEventElement.getEnclosedElements());
+ }
+
+ public boolean uniqueKeyCode(Element element, String targetAnnotationClass) {
+ int[] elementsKeyCodes = extractKeyCode(element);
+ if (elementsKeyCodes.length == 0) {
+ return false;
+ }
+
+ Set uniqueKeyCodes = new HashSet<>(elementsKeyCodes.length);
+ for (int keyCode : elementsKeyCodes) {
+ uniqueKeyCodes.add(keyCode);
+ }
+ Element enclosingElement = element.getEnclosingElement();
+ List extends Element> enclosedMethodElements = ElementFilter.methodsIn(enclosingElement.getEnclosedElements());
+ for (Element oneEnclosedElement : enclosedMethodElements) {
+ if (oneEnclosedElement != element) {
+ List extends AnnotationMirror> annotationMirrors = oneEnclosedElement.getAnnotationMirrors();
+ for (AnnotationMirror annotationMirror : annotationMirrors) {
+ if (annotationMirror.getAnnotationType().asElement().toString().equals(targetAnnotationClass)) {
+ int[] keyCodes = extractKeyCode(oneEnclosedElement);
+ for (int keyCode : keyCodes) {
+ if (uniqueKeyCodes.contains(keyCode)) {
+ return false;
+ } else {
+ uniqueKeyCodes.add(keyCode);
+ }
+ }
+ }
+ }
+ }
+ }
+ return true;
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EComponentWithViewSupportHolder.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EComponentWithViewSupportHolder.java
index 0c6f8f57cf..86b76b596c 100644
--- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EComponentWithViewSupportHolder.java
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/EComponentWithViewSupportHolder.java
@@ -44,9 +44,10 @@
import com.sun.codemodel.JFieldRef;
import com.sun.codemodel.JInvocation;
import com.sun.codemodel.JMethod;
+import com.sun.codemodel.JSwitch;
import com.sun.codemodel.JVar;
-public abstract class EComponentWithViewSupportHolder extends EComponentHolder {
+public abstract class EComponentWithViewSupportHolder extends EComponentHolder implements HasKeyEventCallbackMethods {
protected ViewNotifierHelper viewNotifierHelper;
private JMethod onViewChanged;
@@ -60,10 +61,12 @@ public abstract class EComponentWithViewSupportHolder extends EComponentHolder {
protected JMethod findSupportFragmentByTag;
private Map textWatcherHolders = new HashMap<>();
private Map onSeekBarChangeListenerHolders = new HashMap<>();
+ private KeyEventCallbackMethodsDelegate keyEventCallbackMethodsDelegate;
public EComponentWithViewSupportHolder(AndroidAnnotationsEnvironment environment, TypeElement annotatedElement) throws Exception {
super(environment, annotatedElement);
viewNotifierHelper = new ViewNotifierHelper(this);
+ keyEventCallbackMethodsDelegate = new KeyEventCallbackMethodsDelegate<>(this);
}
public JBlock getOnViewChangedBody() {
@@ -283,4 +286,49 @@ private OnSeekBarChangeListenerHolder createOnSeekBarChangeListenerHolder(JField
return new OnSeekBarChangeListenerHolder(this, onSeekbarChangeListenerClass);
}
+ @Override
+ public JSwitch getOnKeyDownSwitchBody() {
+ return keyEventCallbackMethodsDelegate.getOnKeyDownSwitchBody();
+ }
+
+ @Override
+ public JVar getOnKeyDownKeyEventParam() {
+ return keyEventCallbackMethodsDelegate.getOnKeyDownKeyEventParam();
+ }
+
+ @Override
+ public JSwitch getOnKeyLongPressSwitchBody() {
+ return keyEventCallbackMethodsDelegate.getOnKeyLongPressSwitchBody();
+ }
+
+ @Override
+ public JVar getOnKeyLongPressKeyEventParam() {
+ return keyEventCallbackMethodsDelegate.getOnKeyLongPressKeyEventParam();
+ }
+
+ @Override
+ public JSwitch getOnKeyMultipleSwitchBody() {
+ return keyEventCallbackMethodsDelegate.getOnKeyMultipleSwitchBody();
+ }
+
+ @Override
+ public JVar getOnKeyMultipleKeyEventParam() {
+ return keyEventCallbackMethodsDelegate.getOnKeyMultipleKeyEventParam();
+ }
+
+ @Override
+ public JVar getOnKeyMultipleCountParam() {
+ return keyEventCallbackMethodsDelegate.getOnKeyMultipleCountParam();
+ }
+
+ @Override
+ public JSwitch getOnKeyUpSwitchBody() {
+ return keyEventCallbackMethodsDelegate.getOnKeyUpSwitchBody();
+ }
+
+ @Override
+ public JVar getOnKeyUpKeyEventParam() {
+ return keyEventCallbackMethodsDelegate.getOnKeyUpKeyEventParam();
+ }
+
}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/HasKeyEventCallbackMethods.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/HasKeyEventCallbackMethods.java
new file mode 100644
index 0000000000..d9e0f9addf
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/HasKeyEventCallbackMethods.java
@@ -0,0 +1,39 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.holder;
+
+import com.sun.codemodel.JSwitch;
+import com.sun.codemodel.JVar;
+
+public interface HasKeyEventCallbackMethods extends GeneratedClassHolder {
+ JSwitch getOnKeyDownSwitchBody();
+
+ JVar getOnKeyDownKeyEventParam();
+
+ JSwitch getOnKeyLongPressSwitchBody();
+
+ JVar getOnKeyLongPressKeyEventParam();
+
+ JSwitch getOnKeyMultipleSwitchBody();
+
+ JVar getOnKeyMultipleKeyEventParam();
+
+ JVar getOnKeyMultipleCountParam();
+
+ JSwitch getOnKeyUpSwitchBody();
+
+ JVar getOnKeyUpKeyEventParam();
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/KeyEventCallbackMethodsDelegate.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/KeyEventCallbackMethodsDelegate.java
new file mode 100644
index 0000000000..b24672d6d1
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/holder/KeyEventCallbackMethodsDelegate.java
@@ -0,0 +1,145 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.holder;
+
+import static com.sun.codemodel.JExpr._super;
+import static com.sun.codemodel.JMod.PUBLIC;
+
+import com.sun.codemodel.JBlock;
+import com.sun.codemodel.JMethod;
+import com.sun.codemodel.JSwitch;
+import com.sun.codemodel.JVar;
+
+public class KeyEventCallbackMethodsDelegate extends GeneratedClassHolderDelegate {
+
+ private JSwitch onKeyDownSwitchBody;
+ private JVar onKeyDownKeyEventParam;
+ private JSwitch onKeyLongPressSwitchBody;
+ private JVar onKeyLongPressKeyEventParam;
+ private JSwitch onKeyUpSwitchBody;
+ private JVar onKeyUpKeyEventParam;
+ private JSwitch onKeyMultipleSwitchBody;
+ private JVar onKeyMultipleCountParam;
+ private JVar onKeyMultipleKeyEventParam;
+
+ public KeyEventCallbackMethodsDelegate(T holder) {
+ super(holder);
+ }
+
+ private void createOnKeyDownMethod() {
+ JMethod method = getGeneratedClass().method(PUBLIC, codeModel().BOOLEAN, "onKeyDown");
+ method.annotate(Override.class);
+ JVar keyCode = method.param(codeModel().INT, "keyCode");
+ onKeyDownKeyEventParam = method.param(getClasses().KEY_EVENT, "keyEvent");
+ JBlock methodBody = method.body();
+ onKeyDownSwitchBody = methodBody._switch(keyCode);
+ methodBody._return(_super().invoke(method).arg(keyCode).arg(onKeyDownKeyEventParam));
+ }
+
+ private void createOnKeyLongPressMethod() {
+ JMethod method = getGeneratedClass().method(PUBLIC, codeModel().BOOLEAN, "onKeyLongPress");
+ method.annotate(Override.class);
+ JVar keyCode = method.param(codeModel().INT, "keyCode");
+ onKeyLongPressKeyEventParam = method.param(getClasses().KEY_EVENT, "keyEvent");
+ JBlock methodBody = method.body();
+ onKeyLongPressSwitchBody = methodBody._switch(keyCode);
+ methodBody._return(_super().invoke(method).arg(keyCode).arg(onKeyLongPressKeyEventParam));
+ }
+
+ private void createOnKeyMultipleMethod() {
+ JMethod method = getGeneratedClass().method(PUBLIC, codeModel().BOOLEAN, "onKeyMultiple");
+ method.annotate(Override.class);
+ JVar keyCode = method.param(codeModel().INT, "keyCode");
+ onKeyMultipleCountParam = method.param(codeModel().INT, "count");
+ onKeyMultipleKeyEventParam = method.param(getClasses().KEY_EVENT, "keyEvent");
+ JBlock methodBody = method.body();
+ onKeyMultipleSwitchBody = methodBody._switch(keyCode);
+ methodBody._return(_super().invoke(method).arg(keyCode).arg(onKeyMultipleCountParam).arg(onKeyDownKeyEventParam));
+ }
+
+ private void createOnKeyUpMethod() {
+ JMethod method = getGeneratedClass().method(PUBLIC, codeModel().BOOLEAN, "onKeyUp");
+ method.annotate(Override.class);
+ JVar keyCode = method.param(codeModel().INT, "keyCode");
+ onKeyUpKeyEventParam = method.param(getClasses().KEY_EVENT, "keyEvent");
+ JBlock methodBody = method.body();
+ onKeyUpSwitchBody = methodBody._switch(keyCode);
+ methodBody._return(_super().invoke(method).arg(keyCode).arg(onKeyUpKeyEventParam));
+ }
+
+ public JSwitch getOnKeyDownSwitchBody() {
+ if (onKeyDownSwitchBody == null) {
+ createOnKeyDownMethod();
+ }
+ return onKeyDownSwitchBody;
+ }
+
+ public JVar getOnKeyDownKeyEventParam() {
+ if (onKeyDownKeyEventParam == null) {
+ createOnKeyDownMethod();
+ }
+ return onKeyDownKeyEventParam;
+ }
+
+ public JSwitch getOnKeyLongPressSwitchBody() {
+ if (onKeyLongPressSwitchBody == null) {
+ createOnKeyLongPressMethod();
+ }
+ return onKeyLongPressSwitchBody;
+ }
+
+ public JVar getOnKeyLongPressKeyEventParam() {
+ if (onKeyLongPressKeyEventParam == null) {
+ createOnKeyLongPressMethod();
+ }
+ return onKeyLongPressKeyEventParam;
+ }
+
+ public JSwitch getOnKeyMultipleSwitchBody() {
+ if (onKeyMultipleSwitchBody == null) {
+ createOnKeyMultipleMethod();
+ }
+ return onKeyMultipleSwitchBody;
+ }
+
+ public JVar getOnKeyMultipleKeyEventParam() {
+ if (onKeyMultipleKeyEventParam == null) {
+ createOnKeyMultipleMethod();
+ }
+ return onKeyMultipleKeyEventParam;
+ }
+
+ public JVar getOnKeyMultipleCountParam() {
+ if (onKeyMultipleCountParam == null) {
+ createOnKeyMultipleMethod();
+ }
+ return onKeyMultipleCountParam;
+ }
+
+ public JSwitch getOnKeyUpSwitchBody() {
+ if (onKeyUpSwitchBody == null) {
+ createOnKeyUpMethod();
+ }
+ return onKeyUpSwitchBody;
+ }
+
+ public JVar getOnKeyUpKeyEventParam() {
+ if (onKeyUpKeyEventParam == null) {
+ createOnKeyUpMethod();
+ }
+ return onKeyUpKeyEventParam;
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java
index 1292b8816d..6f995cc725 100644
--- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/CorePlugin.java
@@ -64,6 +64,10 @@
import org.androidannotations.internal.core.handler.ItemClickHandler;
import org.androidannotations.internal.core.handler.ItemLongClickHandler;
import org.androidannotations.internal.core.handler.ItemSelectHandler;
+import org.androidannotations.internal.core.handler.KeyDownHandler;
+import org.androidannotations.internal.core.handler.KeyLongPressHandler;
+import org.androidannotations.internal.core.handler.KeyMultipleHandler;
+import org.androidannotations.internal.core.handler.KeyUpHandler;
import org.androidannotations.internal.core.handler.LongClickHandler;
import org.androidannotations.internal.core.handler.NonConfigurationInstanceHandler;
import org.androidannotations.internal.core.handler.OnActivityResultHandler;
@@ -177,6 +181,10 @@ public List> getHandlers(AndroidAnnotationsEnvironment andr
annotationHandlers.add(new SeekBarProgressChangeHandler(androidAnnotationEnv));
annotationHandlers.add(new SeekBarTouchStartHandler(androidAnnotationEnv));
annotationHandlers.add(new SeekBarTouchStopHandler(androidAnnotationEnv));
+ annotationHandlers.add(new KeyDownHandler(androidAnnotationEnv));
+ annotationHandlers.add(new KeyLongPressHandler(androidAnnotationEnv));
+ annotationHandlers.add(new KeyMultipleHandler(androidAnnotationEnv));
+ annotationHandlers.add(new KeyUpHandler(androidAnnotationEnv));
annotationHandlers.add(new ServiceActionHandler(androidAnnotationEnv));
annotationHandlers.add(new InstanceStateHandler(androidAnnotationEnv));
annotationHandlers.add(new HttpsClientHandler(androidAnnotationEnv));
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/AbstractKeyEventHandler.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/AbstractKeyEventHandler.java
new file mode 100644
index 0000000000..270d1104c8
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/AbstractKeyEventHandler.java
@@ -0,0 +1,105 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.internal.core.handler;
+
+import static com.sun.codemodel.JExpr.TRUE;
+import static com.sun.codemodel.JExpr.invoke;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.type.TypeKind;
+import javax.lang.model.type.TypeMirror;
+
+import org.androidannotations.AndroidAnnotationsEnvironment;
+import org.androidannotations.ElementValidation;
+import org.androidannotations.helper.KeyCodeHelper;
+import org.androidannotations.helper.ValidatorParameterHelper;
+import org.androidannotations.holder.HasKeyEventCallbackMethods;
+
+import com.sun.codemodel.JBlock;
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JSwitch;
+
+public abstract class AbstractKeyEventHandler extends CoreBaseAnnotationHandler {
+
+ protected final KeyCodeHelper annotationHelper;
+
+ public AbstractKeyEventHandler(Class> targetClass, AndroidAnnotationsEnvironment environment) {
+ super(targetClass, environment);
+ this.annotationHelper = new KeyCodeHelper(environment, getTarget());
+ }
+
+ @Override
+ protected void validate(Element element, ElementValidation validation) {
+ coreValidatorHelper.enclosingElementExtendsKeyEventCallback(element, validation);
+
+ validatorHelper.isNotPrivate(element, validation);
+
+ validatorHelper.doesntThrowException(element, validation);
+
+ if (!annotationHelper.uniqueKeyCode(element, getTarget())) {
+ validation.addError(element, "%s " + element.getSimpleName() + " keyCode is not unique");
+ }
+
+ ExecutableElement executableElement = (ExecutableElement) element;
+
+ validatorHelper.returnTypeIsVoidOrBoolean(executableElement, validation);
+
+ String[] paramTypes = getParamTypes();
+ ValidatorParameterHelper.AnyOrderParamValidator param = validatorHelper.param.anyOrder();
+ if (paramTypes.length > 0) {
+ for (String paramType : paramTypes) {
+ param.type(paramType).optional();
+ }
+ param.validate(executableElement, validation);
+ }
+ }
+
+ @Override
+ public void process(Element element, HasKeyEventCallbackMethods holder) throws Exception {
+ String methodName = element.getSimpleName().toString();
+
+ ExecutableElement executableElement = (ExecutableElement) element;
+ TypeMirror returnType = executableElement.getReturnType();
+
+ boolean returnMethodResult = returnType.getKind() != TypeKind.VOID;
+
+ JSwitch switchBody = getSwitchBody(holder);
+
+ int[] keyCodes = annotationHelper.extractKeyCode(element);
+ for (int keyCode : keyCodes) {
+ String keyCodeFieldName = annotationHelper.getFieldNameForKeyCode(keyCode);
+ JBlock switchCaseBody = switchBody._case(getClasses().KEY_EVENT.staticRef(keyCodeFieldName)).body();
+
+ JInvocation methodCall = invoke(methodName);
+
+ if (returnMethodResult) {
+ switchCaseBody._return(methodCall);
+ } else {
+ switchCaseBody.add(methodCall);
+ switchCaseBody._return(TRUE);
+ }
+
+ passParametersToMethodCall(element, holder, methodCall);
+ }
+ }
+
+ public abstract String[] getParamTypes();
+
+ public abstract JSwitch getSwitchBody(HasKeyEventCallbackMethods holder);
+
+ public abstract void passParametersToMethodCall(Element element, HasKeyEventCallbackMethods holder, JInvocation methodCall);
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyDownHandler.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyDownHandler.java
new file mode 100644
index 0000000000..a06e8228e8
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyDownHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.internal.core.handler;
+
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+
+import org.androidannotations.AndroidAnnotationsEnvironment;
+import org.androidannotations.annotations.KeyDown;
+import org.androidannotations.helper.CanonicalNameConstants;
+import org.androidannotations.holder.HasKeyEventCallbackMethods;
+
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JSwitch;
+
+public class KeyDownHandler extends AbstractKeyEventHandler {
+
+ public KeyDownHandler(AndroidAnnotationsEnvironment environment) {
+ super(KeyDown.class, environment);
+ }
+
+ @Override
+ public String[] getParamTypes() {
+ return new String[] { CanonicalNameConstants.KEY_EVENT };
+ }
+
+ @Override
+ public JSwitch getSwitchBody(HasKeyEventCallbackMethods holder) {
+ return holder.getOnKeyDownSwitchBody();
+ }
+
+ @Override
+ public void passParametersToMethodCall(Element element, HasKeyEventCallbackMethods holder, JInvocation methodCall) {
+ ExecutableElement executableElement = (ExecutableElement) element;
+ List extends VariableElement> parameters = executableElement.getParameters();
+ if (parameters.size() == 1) {
+ methodCall.arg(holder.getOnKeyDownKeyEventParam());
+ }
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyLongPressHandler.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyLongPressHandler.java
new file mode 100644
index 0000000000..c0862670d8
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyLongPressHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.internal.core.handler;
+
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+
+import org.androidannotations.AndroidAnnotationsEnvironment;
+import org.androidannotations.annotations.KeyLongPress;
+import org.androidannotations.helper.CanonicalNameConstants;
+import org.androidannotations.holder.HasKeyEventCallbackMethods;
+
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JSwitch;
+
+public class KeyLongPressHandler extends AbstractKeyEventHandler {
+
+ public KeyLongPressHandler(AndroidAnnotationsEnvironment environment) {
+ super(KeyLongPress.class, environment);
+ }
+
+ @Override
+ public String[] getParamTypes() {
+ return new String[] { CanonicalNameConstants.KEY_EVENT };
+ }
+
+ @Override
+ public JSwitch getSwitchBody(HasKeyEventCallbackMethods holder) {
+ return holder.getOnKeyLongPressSwitchBody();
+ }
+
+ @Override
+ public void passParametersToMethodCall(Element element, HasKeyEventCallbackMethods holder, JInvocation methodCall) {
+ ExecutableElement executableElement = (ExecutableElement) element;
+ List extends VariableElement> parameters = executableElement.getParameters();
+ if (parameters.size() == 1) {
+ methodCall.arg(holder.getOnKeyLongPressKeyEventParam());
+ }
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyMultipleHandler.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyMultipleHandler.java
new file mode 100644
index 0000000000..f03ad6d53d
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyMultipleHandler.java
@@ -0,0 +1,66 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.internal.core.handler;
+
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+
+import org.androidannotations.AndroidAnnotationsEnvironment;
+import org.androidannotations.annotations.KeyMultiple;
+import org.androidannotations.helper.CanonicalNameConstants;
+import org.androidannotations.holder.HasKeyEventCallbackMethods;
+
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JSwitch;
+
+public class KeyMultipleHandler extends AbstractKeyEventHandler {
+
+ public KeyMultipleHandler(AndroidAnnotationsEnvironment environment) {
+ super(KeyMultiple.class, environment);
+ }
+
+ @Override
+ public String[] getParamTypes() {
+ return new String[] { CanonicalNameConstants.KEY_EVENT, int.class.getName() };
+ }
+
+ @Override
+ public JSwitch getSwitchBody(HasKeyEventCallbackMethods holder) {
+ return holder.getOnKeyMultipleSwitchBody();
+ }
+
+ @Override
+ public void passParametersToMethodCall(Element element, HasKeyEventCallbackMethods holder, JInvocation methodCall) {
+ ExecutableElement executableElement = (ExecutableElement) element;
+ List extends VariableElement> parameters = executableElement.getParameters();
+ if (parameters.size() == 1) {
+ if (parameters.get(0).asType().toString().equals(int.class.getName())) {
+ methodCall.arg(holder.getOnKeyMultipleCountParam());
+ } else {
+ methodCall.arg(holder.getOnKeyMultipleKeyEventParam());
+ }
+ } else if (parameters.size() == 2) {
+ if (parameters.get(0).asType().toString().equals(int.class.getName())) {
+ methodCall.arg(holder.getOnKeyMultipleCountParam()).arg(holder.getOnKeyMultipleKeyEventParam());
+ } else {
+ methodCall.arg(holder.getOnKeyMultipleKeyEventParam()).arg(holder.getOnKeyMultipleCountParam());
+ }
+ }
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyUpHandler.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyUpHandler.java
new file mode 100644
index 0000000000..b589bf0361
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/handler/KeyUpHandler.java
@@ -0,0 +1,56 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.internal.core.handler;
+
+import java.util.List;
+
+import javax.lang.model.element.Element;
+import javax.lang.model.element.ExecutableElement;
+import javax.lang.model.element.VariableElement;
+
+import org.androidannotations.AndroidAnnotationsEnvironment;
+import org.androidannotations.annotations.KeyUp;
+import org.androidannotations.helper.CanonicalNameConstants;
+import org.androidannotations.holder.HasKeyEventCallbackMethods;
+
+import com.sun.codemodel.JInvocation;
+import com.sun.codemodel.JSwitch;
+
+public class KeyUpHandler extends AbstractKeyEventHandler {
+
+ public KeyUpHandler(AndroidAnnotationsEnvironment environment) {
+ super(KeyUp.class, environment);
+ }
+
+ @Override
+ public String[] getParamTypes() {
+ return new String[] { CanonicalNameConstants.KEY_EVENT };
+ }
+
+ @Override
+ public JSwitch getSwitchBody(HasKeyEventCallbackMethods holder) {
+ return holder.getOnKeyUpSwitchBody();
+ }
+
+ @Override
+ public void passParametersToMethodCall(Element element, HasKeyEventCallbackMethods holder, JInvocation methodCall) {
+ ExecutableElement executableElement = (ExecutableElement) element;
+ List extends VariableElement> parameters = executableElement.getParameters();
+ if (parameters.size() == 1) {
+ methodCall.arg(holder.getOnKeyUpKeyEventParam());
+ }
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/helper/CoreValidatorHelper.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/helper/CoreValidatorHelper.java
index 64df5f7ed1..2173c72289 100644
--- a/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/helper/CoreValidatorHelper.java
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/main/java/org/androidannotations/internal/core/helper/CoreValidatorHelper.java
@@ -399,4 +399,12 @@ public void usesEnqueueIfHasId(Element element, ElementValidation valid) {
valid.addError("An id only can be used with Propagation.ENQUEUE");
}
}
+
+ public void extendsKeyEventCallback(Element element, ElementValidation validation) {
+ extendsType(element, CanonicalNameConstants.KEY_EVENT_CALLBACK, validation);
+ }
+
+ public void enclosingElementExtendsKeyEventCallback(Element element, ElementValidation validation) {
+ extendsKeyEventCallback(element.getEnclosingElement(), validation);
+ }
}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEvents.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEvents.java
new file mode 100644
index 0000000000..be803b8517
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEvents.java
@@ -0,0 +1,129 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.keyevents;
+
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.KeyDown;
+import org.androidannotations.annotations.KeyMultiple;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+
+@EActivity
+public class ActivityWithKeyEvents extends Activity {
+
+ @KeyDown
+ void a() {
+ }
+
+ @KeyDown
+ void onB() {
+ }
+
+ @KeyDown
+ void cPressed() {
+ }
+
+ @KeyDown
+ void onDPressed() {
+ }
+
+ @KeyDown(KeyEvent.KEYCODE_E)
+ void e() {
+ }
+
+ @KeyDown
+ void f(KeyEvent keyEvent) {
+ }
+
+ @KeyDown(KeyEvent.KEYCODE_G)
+ void g(KeyEvent keyEvent) {
+ }
+
+ @KeyDown({ KeyEvent.KEYCODE_0, KeyEvent.KEYCODE_1 })
+ void digits1(KeyEvent keyEvent) {
+ }
+
+ @KeyDown({ KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_3 })
+ void digits2() {
+ }
+
+ @KeyDown
+ boolean h() {
+ return true;
+ }
+
+ @KeyDown
+ boolean i(KeyEvent keyEvent) {
+ return true;
+ }
+
+ @KeyDown(KeyEvent.KEYCODE_J)
+ boolean j() {
+ return true;
+ }
+
+ @KeyDown({ KeyEvent.KEYCODE_K, KeyEvent.KEYCODE_L })
+ boolean kl() {
+ return true;
+ }
+
+ @KeyMultiple
+ void m() {
+ }
+
+ @KeyMultiple
+ void n(int count) {
+ }
+
+ @KeyMultiple
+ void o(KeyEvent keyEvent) {
+ }
+
+ @KeyMultiple
+ void p(int count, KeyEvent keyEvent) {
+ }
+
+ @KeyMultiple
+ void q(KeyEvent keyEvent, int count) {
+ }
+
+ @KeyMultiple
+ boolean r() {
+ return true;
+ }
+
+ @KeyMultiple
+ boolean s(KeyEvent event, int count) {
+ return true;
+ }
+
+ @KeyMultiple
+ boolean t(int count, KeyEvent event) {
+ return true;
+ }
+
+ @KeyMultiple(KeyEvent.KEYCODE_U)
+ boolean u(int count) {
+ return true;
+ }
+
+ @KeyMultiple({ KeyEvent.KEYCODE_V, KeyEvent.KEYCODE_W })
+ boolean vw(KeyEvent event) {
+ return true;
+ }
+
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEventsWithNotUniqueKeycode.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEventsWithNotUniqueKeycode.java
new file mode 100644
index 0000000000..4a515276a5
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEventsWithNotUniqueKeycode.java
@@ -0,0 +1,34 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.keyevents;
+
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.KeyDown;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+
+@EActivity
+public class ActivityWithKeyEventsWithNotUniqueKeycode extends Activity {
+
+ @KeyDown
+ void escape() {
+ }
+
+ @KeyDown({ KeyEvent.KEYCODE_2, KeyEvent.KEYCODE_ESCAPE })
+ void esc() {
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEventsWithWrongParameter.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEventsWithWrongParameter.java
new file mode 100644
index 0000000000..4441e88f57
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/ActivityWithKeyEventsWithWrongParameter.java
@@ -0,0 +1,36 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.keyevents;
+
+import org.androidannotations.annotations.EActivity;
+import org.androidannotations.annotations.KeyDown;
+import org.androidannotations.annotations.KeyMultiple;
+
+import android.app.Activity;
+import android.view.KeyEvent;
+
+@EActivity
+public class ActivityWithKeyEventsWithWrongParameter extends Activity {
+
+ @KeyDown
+ void escape(String keyEvent) {
+ }
+
+ @KeyMultiple(KeyEvent.KEYCODE_E)
+ void e(String count) {
+ }
+
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/FragmentWithKeyEvents.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/FragmentWithKeyEvents.java
new file mode 100644
index 0000000000..c8ec30d196
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/FragmentWithKeyEvents.java
@@ -0,0 +1,29 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.keyevents;
+
+import org.androidannotations.annotations.EFragment;
+import org.androidannotations.annotations.KeyDown;
+
+import android.app.Fragment;
+
+@EFragment
+public class FragmentWithKeyEvents extends Fragment {
+
+ @KeyDown
+ void escape() {
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/KeyEventTest.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/KeyEventTest.java
new file mode 100644
index 0000000000..875adeaefb
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/KeyEventTest.java
@@ -0,0 +1,51 @@
+/**
+ * Copyright (C) 2010-2015 eBusiness Information, Excilys Group
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed To in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package org.androidannotations.keyevents;
+
+
+import org.androidannotations.internal.AndroidAnnotationProcessor;
+import org.androidannotations.testutils.AAProcessorTestHelper;
+import org.junit.Before;
+import org.junit.Test;
+
+public class KeyEventTest extends AAProcessorTestHelper {
+
+ @Before
+ public void setUp() {
+ addManifestProcessorParameter(KeyEventTest.class);
+ addProcessor(AndroidAnnotationProcessor.class);
+ }
+
+ @Test
+ public void compileTestWithTypeImplementsKeyEventCallback() {
+ assertCompilationSuccessful(compileFiles(ActivityWithKeyEvents.class));
+ }
+
+ @Test
+ public void compileTestWithTypeDoesNotImplementKeyEventCallback() {
+ assertCompilationError(compileFiles(FragmentWithKeyEvents.class));
+ }
+
+ @Test
+ public void compileTestForParameterizedMethodWithWrongType() {
+ assertCompilationError(compileFiles(ActivityWithKeyEventsWithWrongParameter.class));
+ }
+
+ @Test
+ public void compileTestWithNotUniqueKeycode() {
+ assertCompilationError(compileFiles(ActivityWithKeyEventsWithNotUniqueKeycode.class));
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/R.java b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/R.java
new file mode 100644
index 0000000000..4994a31c01
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/java/org/androidannotations/keyevents/R.java
@@ -0,0 +1,7 @@
+package org.androidannotations.keyevents;
+
+public class R {
+ public static final class id {
+ public static final int menu = 0x7f06000a;
+ }
+}
diff --git a/AndroidAnnotations/androidannotations-core/androidannotations/src/test/resources/org/androidannotations/keyevents/AndroidManifest.xml b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/resources/org/androidannotations/keyevents/AndroidManifest.xml
new file mode 100644
index 0000000000..f0c70bccd7
--- /dev/null
+++ b/AndroidAnnotations/androidannotations-core/androidannotations/src/test/resources/org/androidannotations/keyevents/AndroidManifest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+