1 /* 2 * Copyright 2018 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package androidx.emoji.text; 17 18 import static androidx.emoji.util.Emoji.EMOJI_WITH_ZWJ; 19 import static androidx.emoji.util.EmojiMatcher.hasEmoji; 20 import static androidx.emoji.util.EmojiMatcher.hasEmojiAt; 21 import static androidx.emoji.util.KeyboardUtil.del; 22 import static androidx.emoji.util.KeyboardUtil.forwardDel; 23 24 import static org.hamcrest.core.IsNot.not; 25 import static org.junit.Assert.assertThat; 26 27 import android.app.Instrumentation; 28 import android.support.test.InstrumentationRegistry; 29 import android.support.test.filters.LargeTest; 30 import android.support.test.filters.Suppress; 31 import android.support.test.rule.ActivityTestRule; 32 import android.support.test.runner.AndroidJUnit4; 33 import android.text.Editable; 34 import android.view.inputmethod.InputConnection; 35 import android.widget.EditText; 36 37 import androidx.emoji.test.R; 38 import androidx.emoji.util.KeyboardUtil; 39 import androidx.emoji.util.TestString; 40 import androidx.testutils.PollingCheck; 41 42 import org.junit.Before; 43 import org.junit.BeforeClass; 44 import org.junit.Rule; 45 import org.junit.Test; 46 import org.junit.runner.RunWith; 47 48 @LargeTest 49 @RunWith(AndroidJUnit4.class) 50 @Suppress 51 public class EmojiKeyboardTest { 52 53 @Rule 54 public ActivityTestRule<TestActivity> mActivityRule = new ActivityTestRule<>( 55 TestActivity.class); 56 private Instrumentation mInstrumentation; 57 58 @BeforeClass 59 public static void setupEmojiCompat() { 60 EmojiCompat.reset(TestConfigBuilder.config()); 61 } 62 63 @Before 64 public void setup() { 65 mInstrumentation = InstrumentationRegistry.getInstrumentation(); 66 } 67 68 @Test 69 public void testAppendWithSoftKeyboard() throws Exception { 70 TestActivity activity = mActivityRule.getActivity(); 71 final EditText editText = (EditText) activity.findViewById(R.id.editText); 72 final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix() 73 .withSuffix(); 74 75 final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme( 76 mInstrumentation, editText); 77 KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, 78 string.toString()); 79 Editable editable = editText.getEditableText(); 80 81 assertThat(editable, hasEmojiAt(EMOJI_WITH_ZWJ, string.emojiStartIndex(), 82 string.emojiEndIndex())); 83 } 84 85 @Test 86 public void testBackDeleteWithSoftKeyboard() throws Exception { 87 TestActivity activity = mActivityRule.getActivity(); 88 final EditText editText = (EditText) activity.findViewById(R.id.editText); 89 final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix() 90 .withSuffix(); 91 final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme( 92 mInstrumentation, editText); 93 KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString()); 94 95 // assert that emoji is there 96 final Editable editable = editText.getEditableText(); 97 assertThat(editable, hasEmoji()); 98 99 // put selection at the end of emoji and back delete 100 KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(), 101 string.emojiEndIndex()); 102 KeyboardUtil.deleteSurroundingText(mInstrumentation, inputConnection, 1, 0); 103 104 assertThat(editable, not(hasEmoji())); 105 } 106 107 @Test 108 public void testForwardDeleteWithSoftKeyboard() throws Exception { 109 TestActivity activity = mActivityRule.getActivity(); 110 final EditText editText = (EditText) activity.findViewById(R.id.editText); 111 final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix() 112 .withSuffix(); 113 final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme( 114 mInstrumentation, editText); 115 KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString()); 116 117 // assert that emoji is there 118 final Editable editable = editText.getEditableText(); 119 assertThat(editable, hasEmoji()); 120 121 // put selection at the begining of emoji and forward delete 122 KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(), 123 string.emojiStartIndex()); 124 KeyboardUtil.deleteSurroundingText(mInstrumentation, inputConnection, 0, 1); 125 126 127 assertThat(editable, not(hasEmoji())); 128 } 129 130 @Test 131 public void testBackDeleteWithHardwareKeyboard() throws Exception { 132 TestActivity activity = mActivityRule.getActivity(); 133 final EditText editText = (EditText) activity.findViewById(R.id.editText); 134 final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix() 135 .withSuffix(); 136 final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme( 137 mInstrumentation, editText); 138 KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString()); 139 140 // assert that emoji is there 141 final Editable editable = editText.getEditableText(); 142 assertThat(editable, hasEmoji()); 143 144 // put selection at the end of emoji and back delete 145 KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(), 146 string.emojiEndIndex()); 147 mInstrumentation.sendKeySync(del()); 148 mInstrumentation.waitForIdleSync(); 149 150 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 151 @Override 152 public boolean canProceed() { 153 return not(hasEmoji()).matches(true); 154 } 155 }); 156 assertThat(editable, not(hasEmoji())); 157 } 158 159 @Test 160 public void testForwardDeleteWithHardwareKeyboard() throws Exception { 161 TestActivity activity = mActivityRule.getActivity(); 162 final EditText editText = (EditText) activity.findViewById(R.id.editText); 163 final TestString string = new TestString(EMOJI_WITH_ZWJ).withPrefix() 164 .withSuffix(); 165 final InputConnection inputConnection = KeyboardUtil.initTextViewForSimulatedIme( 166 mInstrumentation, editText); 167 KeyboardUtil.setComposingTextInBatch(mInstrumentation, inputConnection, string.toString()); 168 169 // assert that emoji is there 170 final Editable editable = editText.getEditableText(); 171 assertThat(editable, hasEmoji()); 172 173 // put selection at the begining of emoji and forward delete 174 KeyboardUtil.setSelection(mInstrumentation, editText.getEditableText(), 175 string.emojiStartIndex()); 176 mInstrumentation.sendKeySync(forwardDel()); 177 mInstrumentation.waitForIdleSync(); 178 179 PollingCheck.waitFor(new PollingCheck.PollingCheckCondition() { 180 @Override 181 public boolean canProceed() { 182 return not(hasEmoji()).matches(true); 183 } 184 }); 185 assertThat(editable, not(hasEmoji())); 186 } 187 } 188