Fix crash when a dead key is pressed in the physical keyboard in Android

The root cause of the crash was unawareness of KeyCharacterMap.COMBINING_ACCENT_MASK flag in Mozc's hardware key event handling.  The return value of android.view.KeyEvent#getUnicodeChar() should have been masked with KeyCharacterMap.COMBINING_ACCENT_MASK before it is treated as a Unicode character.

Note that even with this CL, Mozc for Android still cannot handle dead keys correctly.  It should be addressed by another CL.

Closes Issue 248.

BUG=Issue mozc:248
TEST=manually done with Nexus 5 / Android 5.0.1 (LRX22C)

git-svn-id: https://mozc.googlecode.com/svn/trunk@463 a6090854-d499-a067-5803-1114d4e51264
diff --git a/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/CompactKeyEvent.java b/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/CompactKeyEvent.java
index 8ef460f..6b34c07 100644
--- a/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/CompactKeyEvent.java
+++ b/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/CompactKeyEvent.java
@@ -32,6 +32,7 @@
 import org.mozc.android.inputmethod.japanese.hardwarekeyboard.KeyEventMapperFactory.KeyEventMapper;
 import com.google.common.base.Preconditions;
 
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
 /**
@@ -42,13 +43,18 @@
   private int keyCode;
   private int metaState;
   private int unicodeCharacter;
+  private int combiningAccent;
   private int scanCode;
 
   public CompactKeyEvent(KeyEvent keyEvent) {
     Preconditions.checkNotNull(keyEvent);
     keyCode = keyEvent.getKeyCode();
     metaState = keyEvent.getMetaState();
-    unicodeCharacter = keyEvent.getUnicodeChar();
+    int flagedCodepoint = keyEvent.getUnicodeChar();
+    // TODO(team): Come up with a better definition of the "character" when
+    // KeyCharacterMap.COMBINING_ACCENT bit is set.
+    unicodeCharacter = flagedCodepoint & KeyCharacterMap.COMBINING_ACCENT_MASK;
+    combiningAccent = flagedCodepoint & KeyCharacterMap.COMBINING_ACCENT_MASK;
     scanCode = keyEvent.getScanCode();
   }
 
@@ -76,6 +82,14 @@
     this.metaState = metaState;
   }
 
+  public int getCombiningAccent() {
+    return combiningAccent;
+  }
+
+  public int getDeadChar(int character) {
+    return KeyCharacterMap.getDeadChar(combiningAccent, character);
+  }
+
   public int getUnicodeCharacter() {
     return unicodeCharacter;
   }
diff --git a/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecification.java b/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecification.java
index 0e25cb9..11e400c 100644
--- a/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecification.java
+++ b/src/android/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecification.java
@@ -116,6 +116,7 @@
    */
   @VisibleForTesting
   static boolean isPrintable(int codepoint) {
+    Preconditions.checkArgument(codepoint >= 0);
     if (Character.isISOControl(codepoint)) {
       return false;
     }
diff --git a/src/android/tests/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecificationTest.java b/src/android/tests/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecificationTest.java
index 6eeda12..1821d9c 100644
--- a/src/android/tests/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecificationTest.java
+++ b/src/android/tests/src/com/google/android/inputmethod/japanese/hardwarekeyboard/HardwareKeyboardSpecificationTest.java
@@ -47,6 +47,7 @@
 import android.test.MoreAsserts;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.view.InputDevice;
+import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
 
 import java.util.Collections;
@@ -102,6 +103,18 @@
     }
 
     {
+      KeyEvent keyEvent = new KeyEventMock(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_GRAVE,
+          0, '`' | KeyCharacterMap.COMBINING_ACCENT);
+      keyEvent.setSource(InputDevice.SOURCE_KEYBOARD);
+
+      ProtoCommands.KeyEvent mozcKeyEvent = keyboardSpecification.getMozcKeyEvent(keyEvent);
+      assertEquals('`', mozcKeyEvent.getKeyCode());
+
+      KeyEventInterface keyEventInterface = keyboardSpecification.getKeyEventInterface(keyEvent);
+      assertEquals(keyEvent, keyEventInterface.getNativeEvent().orNull());
+    }
+
+    {
       KeyEvent keyEvent = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SPACE);
       keyEvent.setSource(InputDevice.SOURCE_KEYBOARD);
 
diff --git a/src/mozc_version_template.txt b/src/mozc_version_template.txt
index e13d6b5..f54f736 100644
--- a/src/mozc_version_template.txt
+++ b/src/mozc_version_template.txt
@@ -1,6 +1,6 @@
 MAJOR=2
 MINOR=16
-BUILD=2002
+BUILD=2003
 REVISION=102
 # NACL_DICTIONARY_VERSION is the target version of the system dictionary to be
 # downloaded by NaCl Mozc.