Merge "Introduce Backspace implemenation for flag emoji sequence."
This commit is contained in:
committed by
Android (Google) Code Review
commit
5653fb10a7
@@ -164,6 +164,8 @@ public class Emoji {
|
||||
|
||||
public static int VARIATION_SELECTOR_16 = 0xFE0F;
|
||||
|
||||
public static int CANCEL_TAG = 0xE007F;
|
||||
|
||||
// Returns true if the given code point is regional indicator symbol.
|
||||
public static boolean isRegionalIndicatorSymbol(int codepoint) {
|
||||
return 0x1F1E6 <= codepoint && codepoint <= 0x1F1FF;
|
||||
@@ -188,4 +190,13 @@ public class Emoji {
|
||||
public static boolean isKeycapBase(int codePoint) {
|
||||
return ('0' <= codePoint && codePoint <= '9') || codePoint == '#' || codePoint == '*';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the character can be a part of tag_spec in emoji tag sequence.
|
||||
*
|
||||
* Note that 0xE007F (CANCEL TAG) is not included.
|
||||
*/
|
||||
public static boolean isTagSpecChar(int codePoint) {
|
||||
return 0xE0020 <= codePoint && codePoint <= 0xE007E;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,8 +145,11 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
|
||||
// The number of following RIS code points is even.
|
||||
final int STATE_EVEN_NUMBERED_RIS = 11;
|
||||
|
||||
// The offset is in emoji tag sequence.
|
||||
final int STATE_IN_TAG_SEQUENCE = 12;
|
||||
|
||||
// The state machine has been stopped.
|
||||
final int STATE_FINISHED = 12;
|
||||
final int STATE_FINISHED = 13;
|
||||
|
||||
int deleteCharCount = 0; // Char count to be deleted by backspace.
|
||||
int lastSeenVSCharCount = 0; // Char count of previous variation selector.
|
||||
@@ -173,6 +176,8 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
|
||||
state = STATE_BEFORE_KEYCAP;
|
||||
} else if (Emoji.isEmoji(codePoint)) {
|
||||
state = STATE_BEFORE_EMOJI;
|
||||
} else if (codePoint == Emoji.CANCEL_TAG) {
|
||||
state = STATE_IN_TAG_SEQUENCE;
|
||||
} else {
|
||||
state = STATE_FINISHED;
|
||||
}
|
||||
@@ -275,6 +280,20 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
|
||||
state = STATE_FINISHED;
|
||||
}
|
||||
break;
|
||||
case STATE_IN_TAG_SEQUENCE:
|
||||
if (Emoji.isTagSpecChar(codePoint)) {
|
||||
deleteCharCount += 2; /* Char count of emoji tag spec character. */
|
||||
// Keep the same state.
|
||||
} else if (Emoji.isEmoji(codePoint)) {
|
||||
deleteCharCount += Character.charCount(codePoint);
|
||||
state = STATE_FINISHED;
|
||||
} else {
|
||||
// Couldn't find tag_base character. Delete the last tag_term character.
|
||||
deleteCharCount = 2; // for U+E007F
|
||||
state = STATE_FINISHED;
|
||||
}
|
||||
// TODO: Need handle emoji variation selectors. Issue 35224297
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("state " + state + " is unknown");
|
||||
}
|
||||
|
||||
@@ -37,23 +37,12 @@ public class BackspaceTest extends KeyListenerTestCase {
|
||||
// Sync the state to the TextView and call onKeyDown with KEYCODE_DEL key event.
|
||||
// Then update the state to the result of TextView.
|
||||
private void backspace(final EditorState state, int modifiers) {
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
mTextView.setText(state.mText, BufferType.EDITABLE);
|
||||
mTextView.setKeyListener(mKeyListener);
|
||||
mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
|
||||
}
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
assertTrue(mTextView.hasWindowFocus());
|
||||
mTextView.setText(state.mText, BufferType.EDITABLE);
|
||||
mTextView.setKeyListener(mKeyListener);
|
||||
mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
|
||||
|
||||
final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
|
||||
}
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
|
||||
|
||||
state.mText = mTextView.getText();
|
||||
state.mSelectionStart = mTextView.getSelectionStart();
|
||||
@@ -247,6 +236,51 @@ public class BackspaceTest extends KeyListenerTestCase {
|
||||
state.assertEquals("U+1F1FA U+1F1F8 |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("|");
|
||||
|
||||
// Incomplete sequence. (no tag_term: U+E007E)
|
||||
state.setByString("'a' U+1F3F4 U+E0067 'b' |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+1F3F4 U+E0067 |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+1F3F4 |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' |");
|
||||
|
||||
// No tag_base
|
||||
state.setByString("'a' U+E0067 U+E007F 'b' |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+E0067 U+E007F |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+E0067 |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' |");
|
||||
|
||||
// Isolated tag chars
|
||||
state.setByString("'a' U+E0067 U+E0067 'b' |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+E0067 U+E0067 |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+E0067 |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' |");
|
||||
|
||||
// Isolated tab term.
|
||||
state.setByString("'a' U+E007F U+E007F 'b' |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+E007F U+E007F |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+E007F |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' |");
|
||||
|
||||
// Immediate tag_term after tag_base
|
||||
state.setByString("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b' |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+1F3F4 U+E007F U+1F3F4 U+E007F |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' U+1F3F4 U+E007F |");
|
||||
backspace(state, 0);
|
||||
state.assertEquals("'a' |");
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
|
||||
@@ -37,23 +37,12 @@ public class ForwardDeleteTest extends KeyListenerTestCase {
|
||||
// Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
|
||||
// Then update the state to the result of TextView.
|
||||
private void forwardDelete(final EditorState state, int modifiers) {
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
mTextView.setText(state.mText, BufferType.EDITABLE);
|
||||
mTextView.setKeyListener(mKeyListener);
|
||||
mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
|
||||
}
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
assertTrue(mTextView.hasWindowFocus());
|
||||
mTextView.setText(state.mText, BufferType.EDITABLE);
|
||||
mTextView.setKeyListener(mKeyListener);
|
||||
mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
|
||||
|
||||
final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
|
||||
}
|
||||
});
|
||||
mInstrumentation.waitForIdleSync();
|
||||
mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
|
||||
|
||||
state.mText = mTextView.getText();
|
||||
state.mSelectionStart = mTextView.getSelectionStart();
|
||||
@@ -186,6 +175,46 @@ public class ForwardDeleteTest extends KeyListenerTestCase {
|
||||
state.assertEquals("| U+1F1FA");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("|");
|
||||
|
||||
// Incomplete sequence. (no tag_term:U+E007E)
|
||||
state.setByString("| 'a' U+1F3F4 U+E0067 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| U+1F3F4 U+E0067 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| 'b'");
|
||||
|
||||
// No tag_base
|
||||
state.setByString("| 'a' U+E0067 U+E007F 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| 'b'");
|
||||
|
||||
// Isolated tag chars
|
||||
state.setByString("| 'a' U+E0067 U+E0067 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| 'b'");
|
||||
|
||||
// Isolated tag base.
|
||||
state.setByString("| 'a' U+1F3F4 U+1F3F4 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| U+1F3F4 U+1F3F4 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| U+1F3F4 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| 'b'");
|
||||
|
||||
// Isolated tab term.
|
||||
state.setByString("| 'a' U+E007F U+E007F 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| 'b'");
|
||||
|
||||
// Immediate tag_term after tag_base
|
||||
state.setByString("| 'a' U+1F3F4 U+E007F U+1F3F4 U+E007F 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| U+1F3F4 U+E007F U+1F3F4 U+E007F 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| U+1F3F4 U+E007F 'b'");
|
||||
forwardDelete(state, 0);
|
||||
state.assertEquals("| 'b'");
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
|
||||
@@ -17,41 +17,26 @@
|
||||
package android.text.method;
|
||||
|
||||
import android.app.Instrumentation;
|
||||
import android.test.ActivityInstrumentationTestCase2;
|
||||
import android.text.format.DateUtils;
|
||||
import android.test.InstrumentationTestCase;
|
||||
import android.view.KeyEvent;
|
||||
import android.widget.EditText;
|
||||
import android.widget.TextViewActivity;
|
||||
|
||||
import com.android.frameworks.coretests.R;
|
||||
|
||||
public abstract class KeyListenerTestCase extends
|
||||
ActivityInstrumentationTestCase2<TextViewActivity> {
|
||||
public abstract class KeyListenerTestCase extends InstrumentationTestCase {
|
||||
|
||||
protected TextViewActivity mActivity;
|
||||
protected Instrumentation mInstrumentation;
|
||||
protected EditText mTextView;
|
||||
|
||||
public KeyListenerTestCase() {
|
||||
super(TextViewActivity.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
mActivity = getActivity();
|
||||
mInstrumentation = getInstrumentation();
|
||||
mTextView = (EditText) mActivity.findViewById(R.id.textview);
|
||||
|
||||
mActivity.runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
// Ensure that the screen is on for this test.
|
||||
mTextView.setKeepScreenOn(true);
|
||||
}
|
||||
});
|
||||
|
||||
assertTrue(mActivity.waitForWindowFocus(5 * DateUtils.SECOND_IN_MILLIS));
|
||||
mTextView = new EditText(mInstrumentation.getContext());
|
||||
}
|
||||
|
||||
protected static KeyEvent getKey(int keycode, int metaState) {
|
||||
|
||||
Reference in New Issue
Block a user