Make widgets no-op for sdk < 19
Test: Existing tests passes, added more tests.
Bug: 35811035
Change-Id: I95197304ca1d7a2536358c6bc30c6d2160568ad3
diff --git a/api/26.0.0.txt b/api/26.0.0.txt
index 5b98882..c1b6f89 100644
--- a/api/26.0.0.txt
+++ b/api/26.0.0.txt
@@ -1854,9 +1854,9 @@
public final class EmojiTextViewHelper {
ctor public EmojiTextViewHelper(android.widget.TextView);
method public android.text.InputFilter[] getFilters(android.text.InputFilter[]);
- method public android.text.method.TransformationMethod getTransformationMethod(android.text.method.TransformationMethod);
method public void setAllCaps(boolean);
method public void updateTransformationMethod();
+ method public android.text.method.TransformationMethod wrapTransformationMethod(android.text.method.TransformationMethod);
}
}
diff --git a/api/current.txt b/api/current.txt
index 8757fb5..6826c22 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1854,9 +1854,9 @@
public final class EmojiTextViewHelper {
ctor public EmojiTextViewHelper(android.widget.TextView);
method public android.text.InputFilter[] getFilters(android.text.InputFilter[]);
- method public android.text.method.TransformationMethod getTransformationMethod(android.text.method.TransformationMethod);
method public void setAllCaps(boolean);
method public void updateTransformationMethod();
+ method public android.text.method.TransformationMethod wrapTransformationMethod(android.text.method.TransformationMethod);
}
}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
index 3e9153b..3743cee 100644
--- a/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditText.java
@@ -59,8 +59,8 @@
}
@Override
- public void setKeyListener(android.text.method.KeyListener input) {
- super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
+ public void setKeyListener(android.text.method.KeyListener keyListener) {
+ super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
}
@Override
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java b/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
index c3d5e84..0c3574c 100644
--- a/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiEditTextHelper.java
@@ -15,7 +15,10 @@
*/
package android.support.text.emoji.widget;
+import android.os.Build;
import android.support.annotation.NonNull;
+import android.support.annotation.RequiresApi;
+import android.support.text.emoji.EmojiCompat;
import android.support.v4.util.Preconditions;
import android.text.method.KeyListener;
import android.view.inputmethod.EditorInfo;
@@ -24,11 +27,43 @@
import android.widget.TextView;
/**
- * Utility class to enhance an EditText with emoji capability.
+ * Utility class to enhance custom EditText widgets with {@link EmojiCompat}.
+ * <p/>
+ * <pre>
+ * public class MyEmojiEditText extends EditText {
+ * public MyEmojiEditText(Context context) {
+ * super(context);
+ * init();
+ * }
+ * // ...
+ * private void init() {
+ * super.setKeyListener(getEmojiEditTextHelper().getKeyListener(getKeyListener()));
+ * }
+ *
+ * {@literal @}Override
+ * public void setKeyListener(android.text.method.KeyListener keyListener) {
+ * super.setKeyListener(getEmojiEditTextHelper().getKeyListener(keyListener));
+ * }
+ *
+ * {@literal @}Override
+ * public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
+ * InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
+ * return getEmojiEditTextHelper().onCreateInputConnection(inputConnection, outAttrs);
+ * }
+ *
+ * private EmojiEditTextHelper getEmojiEditTextHelper() {
+ * if (mEmojiEditTextHelper == null) {
+ * mEmojiEditTextHelper = new EmojiEditTextHelper(this);
+ * }
+ * return mEmojiEditTextHelper;
+ * }
+ * }
+ * </pre>
+ *
*/
public final class EmojiEditTextHelper {
- private final EditText mEditText;
- private final EmojiTextWatcher mTextWatcher;
+
+ private final HelperInternal mHelper;
/**
* Default constructor.
@@ -37,41 +72,30 @@
*/
public EmojiEditTextHelper(@NonNull final EditText editText) {
Preconditions.checkNotNull(editText, "editText cannot be null");
- mEditText = editText;
- mTextWatcher = new EmojiTextWatcher(mEditText);
- editText.addTextChangedListener(mTextWatcher);
- editText.setEditableFactory(EmojiEditableFactory.getInstance());
+ mHelper = Build.VERSION.SDK_INT >= 19 ? new HelperInternal19(editText)
+ : new HelperInternal();
}
/**
* Attaches EmojiCompat KeyListener to the widget. Should be called from {@link
* TextView#setKeyListener(KeyListener)}. Existing keyListener is wrapped into EmojiCompat
- * KeyListener.
- * <p/>
- * <pre><code> {@literal @}Override
- * public void setKeyListener(android.text.method.KeyListener input) {
- * super.setKeyListener(getEmojiEditTextHelper().getKeyListener(input));
- * }</code></pre>
+ * KeyListener. When used on devices running API 18 or below, this method returns
+ * {@code keyListener} that is given as a parameter.
*
* @param keyListener KeyListener passed into {@link TextView#setKeyListener(KeyListener)}
*
* @return a new KeyListener instance that wraps {@code keyListener}.
*/
-
+ @NonNull
public KeyListener getKeyListener(@NonNull final KeyListener keyListener) {
Preconditions.checkNotNull(keyListener, "keyListener cannot be null");
- return new EmojiKeyListener(keyListener);
+ return mHelper.getKeyListener(keyListener);
}
/**
* Updates the InputConnection with emoji support. Should be called from {@link
- * TextView#onCreateInputConnection(EditorInfo)}.
- * <p/>
- * <pre><code> {@literal @}Override
- * public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
- * InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
- * return getEmojiHelper().onCreateInputConnection(inputConnection, outAttrs);
- * }</code></pre>
+ * TextView#onCreateInputConnection(EditorInfo)}. When used on devices running API 18 or below,
+ * this method returns {@code inputConnection} that is given as a parameter.
*
* @param inputConnection InputConnection instance created by TextView
* @param outAttrs EditorInfo passed into
@@ -79,9 +103,52 @@
*
* @return a new InputConnection instance that wraps {@code inputConnection}
*/
+ @NonNull
public InputConnection onCreateInputConnection(@NonNull final InputConnection inputConnection,
@NonNull final EditorInfo outAttrs) {
Preconditions.checkNotNull(inputConnection, "inputConnection cannot be null");
- return new EmojiInputConnection(mEditText, inputConnection, outAttrs);
+ return mHelper.onCreateInputConnection(inputConnection, outAttrs);
+ }
+
+ private static class HelperInternal {
+
+ KeyListener getKeyListener(@NonNull KeyListener keyListener) {
+ return keyListener;
+ }
+
+ InputConnection onCreateInputConnection(@NonNull InputConnection inputConnection,
+ @NonNull EditorInfo outAttrs) {
+ return inputConnection;
+ }
+ }
+
+ @RequiresApi(19)
+ private static class HelperInternal19 extends HelperInternal {
+ private final EditText mEditText;
+ private final EmojiTextWatcher mTextWatcher;
+
+ HelperInternal19(@NonNull EditText editText) {
+ mEditText = editText;
+ mTextWatcher = new EmojiTextWatcher(mEditText);
+ mEditText.addTextChangedListener(mTextWatcher);
+ mEditText.setEditableFactory(EmojiEditableFactory.getInstance());
+ }
+
+ @Override
+ KeyListener getKeyListener(@NonNull final KeyListener keyListener) {
+ if (keyListener instanceof EmojiKeyListener) {
+ return keyListener;
+ }
+ return new EmojiKeyListener(keyListener);
+ }
+
+ @Override
+ InputConnection onCreateInputConnection(@NonNull final InputConnection inputConnection,
+ @NonNull final EditorInfo outAttrs) {
+ if (inputConnection instanceof EmojiInputConnection) {
+ return inputConnection;
+ }
+ return new EmojiInputConnection(mEditText, inputConnection, outAttrs);
+ }
}
}
diff --git a/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java b/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
index e88cc87..abd7410 100644
--- a/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
+++ b/emoji/core/src/android/support/text/emoji/widget/EmojiTextViewHelper.java
@@ -15,7 +15,11 @@
*/
package android.support.text.emoji.widget;
+import android.os.Build;
import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.annotation.RequiresApi;
+import android.support.text.emoji.EmojiCompat;
import android.support.v4.util.Preconditions;
import android.text.InputFilter;
import android.text.method.PasswordTransformationMethod;
@@ -23,11 +27,41 @@
import android.widget.TextView;
/**
- * Utility class to enhance a TextView with emoji capability.
+ * Utility class to enhance custom TextView widgets with {@link EmojiCompat}.
+ * <pre>
+ * public class MyEmojiTextView extends TextView {
+ * public MyEmojiTextView(Context context) {
+ * super(context);
+ * init();
+ * }
+ * // ..
+ * private void init() {
+ * getEmojiTextViewHelper().updateTransformationMethod();
+ * }
+ *
+ * {@literal @}Override
+ * public void setFilters(InputFilter[] filters) {
+ * super.setFilters(getEmojiTextViewHelper().getFilters(filters));
+ * }
+ *
+ * {@literal @}Override
+ * public void setAllCaps(boolean allCaps) {
+ * super.setAllCaps(allCaps);
+ * getEmojiTextViewHelper().setAllCaps(allCaps);
+ * }
+ *
+ * private EmojiTextViewHelper getEmojiTextViewHelper() {
+ * if (mEmojiTextViewHelper == null) {
+ * mEmojiTextViewHelper = new EmojiTextViewHelper(this);
+ * }
+ * return mEmojiTextViewHelper;
+ * }
+ * }
+ * </pre>
*/
public final class EmojiTextViewHelper {
- private final TextView mTextView;
- private final EmojiInputFilter mEmojiInputFilter;
+
+ private final HelperInternal mHelper;
/**
* Default constructor.
@@ -36,77 +70,126 @@
*/
public EmojiTextViewHelper(@NonNull TextView textView) {
Preconditions.checkNotNull(textView, "textView cannot be null");
- mTextView = textView;
- mEmojiInputFilter = new EmojiInputFilter(textView);
+ mHelper = Build.VERSION.SDK_INT >= 19 ? new HelperInternal19(textView)
+ : new HelperInternal();
}
/**
* Updates widget's TransformationMethod so that the transformed text can be processed.
- * Should be called in the widget constructor.
+ * Should be called in the widget constructor. When used on devices running API 18 or below,
+ * this method does nothing.
*
- * @see #getTransformationMethod(TransformationMethod)
+ * @see #wrapTransformationMethod(TransformationMethod)
*/
public void updateTransformationMethod() {
- final TransformationMethod transformationMethod = mTextView.getTransformationMethod();
- if (transformationMethod != null
- && !(transformationMethod instanceof PasswordTransformationMethod)) {
- mTextView.setTransformationMethod(getTransformationMethod(transformationMethod));
- }
+ mHelper.updateTransformationMethod();
}
/**
* Appends EmojiCompat InputFilters to the widget InputFilters. Should be called by {@link
- * TextView#setFilters(InputFilter[])} to update the InputFilters.
- * <p/>
- * <pre><code> {@literal @}Override
- * public void setFilters(InputFilter[] filters) {
- * super.setFilters(getEmojiTextViewHelper().getFilters(filters));
- * }</code></pre>
+ * TextView#setFilters(InputFilter[])} to update the InputFilters. When used on devices running
+ * API 18 or below, this method returns {@code filters} that is given as a parameter.
*
* @param filters InputFilter array passed to {@link TextView#setFilters(InputFilter[])}
*
* @return same copy if the array already contains EmojiCompat InputFilter. A new array copy if
* not.
*/
+ @NonNull
public InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
- final int count = filters.length;
- for (int i = 0; i < count; i++) {
- if (filters[i] instanceof EmojiInputFilter) {
- return filters;
- }
- }
- final InputFilter[] newFilters = new InputFilter[filters.length + 1];
- System.arraycopy(filters, 0, newFilters, 0, count);
- newFilters[count] = mEmojiInputFilter;
- return newFilters;
+ return mHelper.getFilters(filters);
}
/**
- * Returns transformation method that can update the transformed text to display emojis.
+ * Returns transformation method that can update the transformed text to display emojis. When
+ * used on devices running API 18 or below, this method returns {@code transformationMethod}
+ * that is given as a parameter.
*
* @param transformationMethod instance to be wrapped
*/
- public TransformationMethod getTransformationMethod(
- final TransformationMethod transformationMethod) {
- return new EmojiTransformationMethod(transformationMethod);
+ @Nullable
+ public TransformationMethod wrapTransformationMethod(
+ @Nullable TransformationMethod transformationMethod) {
+ return mHelper.wrapTransformationMethod(transformationMethod);
}
/**
- * Call when allCaps is set on TextView.
- * <p/>
- * <pre><code> {@literal @}Override
- * public void setAllCaps(boolean allCaps) {
- * super.setAllCaps(allCaps);
- * getEmojiTextViewHelper().setAllCaps(allCaps);
- * }</code></pre>
+ * Call when allCaps is set on TextView. When used on devices running API 18 or below, this
+ * method does nothing.
*
* @param allCaps allCaps parameter passed to {@link TextView#setAllCaps(boolean)}
*/
public void setAllCaps(boolean allCaps) {
- // When allCaps is set to false TextView sets the transformation method to be null. We
- // are only interested when allCaps is set to true in order to wrap the original method.
- if (allCaps) {
- updateTransformationMethod();
+ mHelper.setAllCaps(allCaps);
+ }
+
+ private static class HelperInternal {
+
+ void updateTransformationMethod() {
+ // do nothing
}
+
+ InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
+ return filters;
+ }
+
+ TransformationMethod wrapTransformationMethod(TransformationMethod transformationMethod) {
+ return transformationMethod;
+ }
+
+ void setAllCaps(boolean allCaps) {
+ // do nothing
+ }
+ }
+
+ @RequiresApi(19)
+ private static class HelperInternal19 extends HelperInternal {
+ private final TextView mTextView;
+ private final EmojiInputFilter mEmojiInputFilter;
+
+ HelperInternal19(TextView textView) {
+ mTextView = textView;
+ mEmojiInputFilter = new EmojiInputFilter(textView);
+ }
+
+ @Override
+ void updateTransformationMethod() {
+ final TransformationMethod tm = mTextView.getTransformationMethod();
+ if (tm != null && !(tm instanceof PasswordTransformationMethod)) {
+ mTextView.setTransformationMethod(wrapTransformationMethod(tm));
+ }
+ }
+
+ @Override
+ InputFilter[] getFilters(@NonNull final InputFilter[] filters) {
+ final int count = filters.length;
+ for (int i = 0; i < count; i++) {
+ if (filters[i] instanceof EmojiInputFilter) {
+ return filters;
+ }
+ }
+ final InputFilter[] newFilters = new InputFilter[filters.length + 1];
+ System.arraycopy(filters, 0, newFilters, 0, count);
+ newFilters[count] = mEmojiInputFilter;
+ return newFilters;
+ }
+
+ @Override
+ TransformationMethod wrapTransformationMethod(TransformationMethod transformationMethod) {
+ if (transformationMethod instanceof EmojiTransformationMethod) {
+ return transformationMethod;
+ }
+ return new EmojiTransformationMethod(transformationMethod);
+ }
+
+ @Override
+ void setAllCaps(boolean allCaps) {
+ // When allCaps is set to false TextView sets the transformation method to be null. We
+ // are only interested when allCaps is set to true in order to wrap the original method.
+ if (allCaps) {
+ updateTransformationMethod();
+ }
+ }
+
}
}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java
new file mode 100644
index 0000000..a607801
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperPre19Test.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 android.support.text.emoji.widget;
+
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.method.KeyListener;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(maxSdkVersion = 18)
+public class EmojiEditTextHelperPre19Test {
+ EmojiEditTextHelper mEmojiEditTextHelper;
+
+ @Before
+ public void setup() {
+ final EditText editText = mock(EditText.class);
+ mEmojiEditTextHelper = new EmojiEditTextHelper(editText);
+ verifyNoMoreInteractions(editText);
+ }
+
+ @Test
+ public void testGetKeyListener_returnsSameKeyListener() {
+ final KeyListener param = mock(KeyListener.class);
+ final KeyListener keyListener = mEmojiEditTextHelper.getKeyListener(
+ param);
+
+ assertSame(param, keyListener);
+ }
+
+ @Test
+ public void testGetOnCreateInputConnection_returnsSameInputConnection() {
+ final InputConnection param = mock(InputConnection.class);
+ final InputConnection inputConnection = mEmojiEditTextHelper.onCreateInputConnection(param,
+ null);
+
+ assertSame(param, inputConnection);
+ }
+
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java
new file mode 100644
index 0000000..b7d8f5b
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiEditTextHelperTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 android.support.text.emoji.widget;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.TargetApi;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.text.emoji.EmojiCompat;
+import android.text.method.KeyListener;
+import android.view.inputmethod.InputConnection;
+import android.widget.EditText;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = 19)
+@TargetApi(19)
+public class EmojiEditTextHelperTest {
+ EmojiEditTextHelper mEmojiEditTextHelper;
+ EditText mEditText;
+
+ @Before
+ public void setup() {
+ EmojiCompat.reset(mock(EmojiCompat.class));
+ mEditText = new EditText(InstrumentationRegistry.getTargetContext());
+ mEmojiEditTextHelper = new EmojiEditTextHelper(mEditText);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetKeyListener_withNull_throwsException() {
+ mEmojiEditTextHelper.getKeyListener(null);
+ }
+
+ @Test
+ public void testGetKeyListener_returnsEmojiKeyListener() {
+ final KeyListener keyListener = mEmojiEditTextHelper.getKeyListener(
+ mock(KeyListener.class));
+
+ assertThat(keyListener, instanceOf(EmojiKeyListener.class));
+ }
+
+ @Test
+ public void testGetKeyListener_doesNotCreateNewInstance() {
+ KeyListener mockKeyListener = mock(KeyListener.class);
+ final KeyListener keyListener1 = mEmojiEditTextHelper.getKeyListener(mockKeyListener);
+ final KeyListener keyListener2 = mEmojiEditTextHelper.getKeyListener(keyListener1);
+ assertSame(keyListener1, keyListener2);
+ }
+
+ @Test(expected = NullPointerException.class)
+ public void testGetOnCreateInputConnection_withNull_throwsException() {
+ mEmojiEditTextHelper.onCreateInputConnection(null, null);
+ }
+
+ @Test
+ public void testGetOnCreateInputConnection_returnsEmojiInputConnection() {
+ final InputConnection inputConnection = mEmojiEditTextHelper.onCreateInputConnection(
+ mock(InputConnection.class), null);
+
+ assertThat(inputConnection, instanceOf(EmojiInputConnection.class));
+ }
+
+ @Test
+ public void testGetOnCreateInputConnection_doesNotCreateNewInstance() {
+ final InputConnection ic1 = mEmojiEditTextHelper.onCreateInputConnection(
+ mock(InputConnection.class), null);
+ final InputConnection ic2 = mEmojiEditTextHelper.onCreateInputConnection(ic1, null);
+
+ assertSame(ic1, ic2);
+ }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java
new file mode 100644
index 0000000..6d68aad
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperPre19Test.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 android.support.text.emoji.widget;
+
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
+
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.InputFilter;
+import android.text.method.TransformationMethod;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(maxSdkVersion = 18)
+public class EmojiTextViewHelperPre19Test {
+ EmojiTextViewHelper mTextViewHelper;
+ TextView mTextView;
+
+ @Before
+ public void setup() {
+ mTextView = new TextView(InstrumentationRegistry.getTargetContext());
+ mTextViewHelper = new EmojiTextViewHelper(mTextView);
+ }
+
+ @Test
+ public void testUpdateTransformationMethod_doesNotUpdateTransformationMethod() {
+ final TransformationMethod tm = mock(TransformationMethod.class);
+ mTextView.setTransformationMethod(tm);
+
+ mTextViewHelper.updateTransformationMethod();
+
+ assertSame(tm, mTextView.getTransformationMethod());
+ }
+
+ @Test
+ public void testGetFilters_returnsSameFilters() {
+ final InputFilter existingFilter = mock(InputFilter.class);
+ final InputFilter[] filters = new InputFilter[]{existingFilter};
+
+ final InputFilter[] newFilters = mTextViewHelper.getFilters(filters);
+
+ assertSame(filters, newFilters);
+ }
+
+ @Test
+ public void testGetTransformationMethod_returnSameTransformationMethod() {
+ assertNull(mTextViewHelper.wrapTransformationMethod(null));
+
+ final TransformationMethod tm = mock(TransformationMethod.class);
+ assertSame(tm, mTextViewHelper.wrapTransformationMethod(tm));
+ }
+
+ @Test
+ public void testSetAllCaps_doesNotUpdateTransformationMethod() {
+ final TransformationMethod tm = mock(TransformationMethod.class);
+ mTextView.setTransformationMethod(tm);
+ mTextViewHelper.setAllCaps(true);
+ assertSame(tm, mTextView.getTransformationMethod());
+
+ mTextViewHelper.setAllCaps(false);
+ assertSame(tm, mTextView.getTransformationMethod());
+ }
+}
diff --git a/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java
new file mode 100644
index 0000000..9a5ccbd
--- /dev/null
+++ b/emoji/core/tests/java/android/support/text/emoji/widget/EmojiTextViewHelperTest.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * 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 android.support.text.emoji.widget;
+
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.TestCase.assertEquals;
+
+import static org.hamcrest.CoreMatchers.hasItem;
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
+import static org.mockito.Mockito.mock;
+
+import android.annotation.TargetApi;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SdkSuppress;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.text.InputFilter;
+import android.text.method.PasswordTransformationMethod;
+import android.text.method.TransformationMethod;
+import android.widget.TextView;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.Arrays;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+@SdkSuppress(minSdkVersion = 19)
+@TargetApi(19)
+public class EmojiTextViewHelperTest {
+ EmojiTextViewHelper mTextViewHelper;
+ TextView mTextView;
+
+ @Before
+ public void setup() {
+ mTextView = new TextView(InstrumentationRegistry.getTargetContext());
+ mTextViewHelper = new EmojiTextViewHelper(mTextView);
+ }
+
+ @Test
+ public void testUpdateTransformationMethod() {
+ mTextView.setTransformationMethod(mock(TransformationMethod.class));
+
+ mTextViewHelper.updateTransformationMethod();
+
+ assertThat(mTextView.getTransformationMethod(),
+ instanceOf(EmojiTransformationMethod.class));
+ }
+
+ @Test
+ public void testUpdateTransformationMethod_doesNotUpdateForPasswordTransformation() {
+ final PasswordTransformationMethod transformationMethod =
+ new PasswordTransformationMethod();
+ mTextView.setTransformationMethod(transformationMethod);
+
+ mTextViewHelper.updateTransformationMethod();
+
+ assertEquals(transformationMethod, mTextView.getTransformationMethod());
+ }
+
+ @Test
+ public void testUpdateTransformationMethod_doesNotCreateNewInstance() {
+ mTextView.setTransformationMethod(mock(TransformationMethod.class));
+
+ mTextViewHelper.updateTransformationMethod();
+ final TransformationMethod tm = mTextView.getTransformationMethod();
+ assertThat(tm, instanceOf(EmojiTransformationMethod.class));
+
+ // call the function again
+ mTextViewHelper.updateTransformationMethod();
+ assertSame(tm, mTextView.getTransformationMethod());
+ }
+
+ @Test
+ public void testGetFilters() {
+ final InputFilter existingFilter = mock(InputFilter.class);
+ final InputFilter[] filters = new InputFilter[]{existingFilter};
+
+ final InputFilter[] newFilters = mTextViewHelper.getFilters(filters);
+
+ assertEquals(2, newFilters.length);
+ assertThat(Arrays.asList(newFilters), hasItem(existingFilter));
+ assertNotNull(findEmojiInputFilter(newFilters));
+ }
+
+ @Test
+ public void testGetFilters_doesNotAddSecondInstance() {
+ final InputFilter existingFilter = mock(InputFilter.class);
+ final InputFilter[] filters = new InputFilter[]{existingFilter};
+
+ InputFilter[] newFilters = mTextViewHelper.getFilters(filters);
+ EmojiInputFilter emojiInputFilter = findEmojiInputFilter(newFilters);
+ assertNotNull(emojiInputFilter);
+
+ // run it again with the updated filters and see that it does not add new filter
+ newFilters = mTextViewHelper.getFilters(newFilters);
+
+ assertEquals(2, newFilters.length);
+ assertThat(Arrays.asList(newFilters), hasItem(existingFilter));
+ assertThat(Arrays.asList(newFilters), hasItem(emojiInputFilter));
+ }
+
+ private EmojiInputFilter findEmojiInputFilter(final InputFilter[] filters) {
+ for (int i = 0; i < filters.length; i++) {
+ if (filters[i] instanceof EmojiInputFilter) {
+ return (EmojiInputFilter) filters[i];
+ }
+ }
+ return null;
+ }
+
+ @Test
+ public void testWrapTransformationMethod() {
+ assertThat(mTextViewHelper.wrapTransformationMethod(null),
+ instanceOf(EmojiTransformationMethod.class));
+ }
+
+ @Test
+ public void testWrapTransformationMethod_doesNotCreateNewInstance() {
+ final TransformationMethod tm1 = mTextViewHelper.wrapTransformationMethod(null);
+ final TransformationMethod tm2 = mTextViewHelper.wrapTransformationMethod(tm1);
+ assertSame(tm1, tm2);
+ }
+
+ @Test
+ public void testSetAllCaps_withTrueSetsTransformationMethod() {
+ mTextView.setTransformationMethod(mock(TransformationMethod.class));
+ mTextViewHelper.setAllCaps(true);
+ assertThat(mTextView.getTransformationMethod(),
+ instanceOf(EmojiTransformationMethod.class));
+ }
+
+ @Test
+ public void testSetAllCaps_withFalseDoesNotSetTransformationMethod() {
+ mTextView.setTransformationMethod(null);
+ mTextViewHelper.setAllCaps(false);
+ assertNull(mTextView.getTransformationMethod());
+ }
+
+ @Test
+ public void testSetAllCaps_withPasswordTransformationDoesNotSetTransformationMethod() {
+ final PasswordTransformationMethod transformationMethod =
+ new PasswordTransformationMethod();
+ mTextView.setTransformationMethod(transformationMethod);
+ mTextViewHelper.setAllCaps(true);
+ assertSame(transformationMethod, mTextView.getTransformationMethod());
+ }
+}