Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5653fb10 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Introduce Backspace implemenation for flag emoji sequence."

parents 85f86032 d5eff80a
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -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;
    }
}
+20 −1
Original line number Diff line number Diff line
@@ -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");
            }
+49 −15
Original line number Diff line number Diff line
@@ -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());

        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_DEL, modifiers);
        mActivity.runOnUiThread(new Runnable() {
            public void run() {
        mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
            }
        });
        mInstrumentation.waitForIdleSync();

        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
+44 −15
Original line number Diff line number Diff line
@@ -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());

        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
        mActivity.runOnUiThread(new Runnable() {
            public void run() {
        mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
            }
        });
        mInstrumentation.waitForIdleSync();

        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
+3 −18
Original line number Diff line number Diff line
@@ -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) {