/*************************************************************************** * Copyright 2006-2016 by Christian Ihle * * contact@kouchat.net * * * * This file is part of KouChat. * * * * KouChat is free software; you can redistribute it and/or modify * * it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or (at your option) any later version. * * * * KouChat is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * * Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with KouChat. * * If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ package net.usikkert.kouchat.android; import static android.test.MoreAsserts.*; import static org.fest.reflect.core.Reflection.*; import net.usikkert.kouchat.android.chatwindow.AndroidUserInterface; import net.usikkert.kouchat.android.controller.MainChatController; import net.usikkert.kouchat.android.util.RobotiumTestUtils; import net.usikkert.kouchat.misc.User; import net.usikkert.kouchat.settings.Settings; import net.usikkert.kouchat.testclient.TestClient; import com.larswerkman.holocolorpicker.ColorPicker; import com.robotium.solo.Solo; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.Color; import android.preference.PreferenceManager; import android.test.ActivityInstrumentationTestCase2; import android.text.Spannable; import android.text.style.ForegroundColorSpan; import android.widget.ImageView; import android.widget.TextView; /** * Tests changing message colors in the settings. * * @author Christian Ihle */ public class ColorTest extends ActivityInstrumentationTestCase2<MainChatController> { private static int originalOwnColor; private static int originalSystemColor; private static int newOwnColor; private static int newSystemColor; private static TestClient client; private Solo solo; private Settings settings; private User me; public ColorTest() { super(MainChatController.class); } public void setUp() { final MainChatController activity = getActivity(); solo = new Solo(getInstrumentation(), activity); // To get english text on the buttons to click RobotiumTestUtils.switchUserInterfaceToEnglish(activity); final AndroidUserInterface androidUserInterface = RobotiumTestUtils.getAndroidUserInterface(activity); settings = androidUserInterface.getSettings(); me = androidUserInterface.getMe(); if (client == null) { client = new TestClient(); client.logon(); originalOwnColor = settings.getOwnColor(); originalSystemColor = settings.getSysColor(); } } public void test01ClickingCancelAfterChangingOwnColorShouldNotSave() { sendOwnMessage("This is my original color"); checkTextColorAndClient("This is my original color", originalOwnColor); openSettings(); checkPreviewColor(originalOwnColor, 0); final ColorPicker colorPicker = openColorPicker("Set own message color"); moveColorWheelPointer(colorPicker, originalOwnColor, -150); cancelNewColor(); RobotiumTestUtils.goHome(solo); checkTextColor("This is my original color", originalOwnColor); sendOwnMessage("This is still my original color"); checkTextColorAndClient("This is still my original color", originalOwnColor); } public void test02ClickingOkAfterChangingOwnColorShouldSave() { openSettings(); final ColorPicker firstColorPicker = openColorPicker("Set own message color"); moveColorWheelPointer(firstColorPicker, originalOwnColor, -150); acceptNewColor(); final int firstColor = firstColorPicker.getColor(); assertEquals(firstColor, settings.getOwnColor()); checkPreviewColor(firstColor, 0); RobotiumTestUtils.goHome(solo); checkTextColor("This is my original color", originalOwnColor); sendOwnMessage("This is my first new color"); checkTextColorAndClient("This is my first new color", firstColor); openSettings(); checkPreviewColor(firstColor, 0); final ColorPicker secondColorPicker = openColorPicker("Set own message color"); moveColorWheelPointer(secondColorPicker, firstColor, -150); acceptNewColor(); final int secondColor = secondColorPicker.getColor(); assertEquals(secondColor, settings.getOwnColor()); checkPreviewColor(secondColor, 0); RobotiumTestUtils.goHome(solo); checkTextColor("This is my original color", originalOwnColor); checkTextColor("This is my first new color", firstColor); sendOwnMessage("This is my second new color"); checkTextColorAndClient("This is my second new color", secondColor); newOwnColor = secondColor; } public void test03ClickingCancelAfterChangingSystemColorShouldNotSave() { solo.sleep(500); checkTextColor("*** Welcome to KouChat", originalSystemColor); openSettings(); checkPreviewColor(originalSystemColor, 1); final ColorPicker colorPicker = openColorPicker("Set info message color"); moveColorWheelPointer(colorPicker, originalSystemColor, 150); cancelNewColor(); RobotiumTestUtils.goHome(solo); checkTextColor("*** Welcome to KouChat", originalSystemColor); setTopic("This is still the original info color"); checkTextColor("This is still the original info color", originalSystemColor); } public void test04ClickingOkAfterChangingSystemColorShouldSave() { openSettings(); final ColorPicker firstColorPicker = openColorPicker("Set info message color"); moveColorWheelPointer(firstColorPicker, originalSystemColor, 150); acceptNewColor(); final int firstColor = firstColorPicker.getColor(); assertEquals(firstColor, settings.getSysColor()); checkPreviewColor(firstColor, 1); RobotiumTestUtils.goHome(solo); checkTextColor("*** Welcome to KouChat", originalSystemColor); setTopic("This is the first new info color"); checkTextColor("This is the first new info color", firstColor); openSettings(); checkPreviewColor(firstColor, 1); final ColorPicker secondColorPicker = openColorPicker("Set info message color"); moveColorWheelPointer(secondColorPicker, firstColor, 150); acceptNewColor(); final int secondColor = secondColorPicker.getColor(); assertEquals(secondColor, settings.getSysColor()); checkPreviewColor(secondColor, 1); RobotiumTestUtils.goHome(solo); checkTextColor("*** Welcome to KouChat", originalSystemColor); checkTextColor("This is the first new info color", firstColor); setTopic("This is the second new info color"); checkTextColor("This is the second new info color", secondColor); newSystemColor = secondColor; } public void test05SettingsShouldSurviveRestart() { solo.sleep(500); assertNotEqual(originalOwnColor, newOwnColor); assertNotEqual(originalSystemColor, newSystemColor); checkTextColor("This is my second new color", newOwnColor); checkTextColor("This is the second new info color", newSystemColor); openSettings(); checkPreviewColor(newOwnColor, 0); checkPreviewColor(newSystemColor, 1); RobotiumTestUtils.goHome(solo); RobotiumTestUtils.quit(solo); solo.sleep(500); RobotiumTestUtils.launchMainChat(this); solo.sleep(500); sendOwnMessage("This is my saved color"); checkTextColor("This is my saved color", newOwnColor); checkTextColor("*** Welcome to KouChat", newSystemColor); openSettings(); checkPreviewColor(newOwnColor, 0); checkPreviewColor(newSystemColor, 1); } public void test06ChangingColorsShouldWorkWithPrivateChat() { RobotiumTestUtils.openPrivateChat(solo, getInstrumentation(), 2, 2, "Test"); sendOwnMessage("This is my original color in the private chat"); checkPrivateTextColorAndClient("This is my original color in the private chat", newOwnColor); goAway("This is the original info color in the private chat"); checkPrivateTextColor("This is the original info color in the private chat", newSystemColor); RobotiumTestUtils.goHome(solo); client.comeBack(); openSettings(); final ColorPicker ownColorPicker = openColorPicker("Set own message color"); moveColorWheelPointer(ownColorPicker, newOwnColor, -150); acceptNewColor(); final int ownColor = ownColorPicker.getColor(); final ColorPicker systemColorPicker = openColorPicker("Set info message color"); moveColorWheelPointer(systemColorPicker, newSystemColor, 150); acceptNewColor(); final int systemColor = systemColorPicker.getColor(); RobotiumTestUtils.goHome(solo); RobotiumTestUtils.openPrivateChat(solo, getInstrumentation(), 2, 2, "Test"); sendOwnMessage("This is my new color in the private chat"); checkPrivateTextColor("This is my original color in the private chat", newOwnColor); checkPrivateTextColorAndClient("This is my new color in the private chat", ownColor); goAway("This is the new info color in the private chat"); checkPrivateTextColor("This is the original info color in the private chat", newSystemColor); checkPrivateTextColor("This is the new info color in the private chat", systemColor); } public void test98ResetOriginalColorsInTheSettings() { final MainChatController activity = getActivity(); final SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity); final SharedPreferences.Editor editor = preferences.edit(); final String ownColorKey = activity.getString(R.string.settings_own_color_key); final String sysColorKey = activity.getString(R.string.settings_sys_color_key); editor.putInt(ownColorKey, originalOwnColor); editor.putInt(sysColorKey, originalSystemColor); editor.commit(); originalOwnColor = 0; originalSystemColor = 0; newOwnColor = 0; newSystemColor = 0; } public void test99Quit() { client.logoff(); RobotiumTestUtils.quit(solo); client = null; } public void tearDown() { solo.finishOpenedActivities(); solo = null; settings = null; me = null; setActivity(null); System.gc(); } private float[] hsvFrom(final int color) { final float[] hsv = new float[3]; Color.colorToHSV(color, hsv); return hsv; } private void cancelNewColor() { solo.sleep(100); solo.clickOnText("Cancel"); solo.sleep(200); } private void acceptNewColor() { solo.sleep(100); solo.clickOnText("OK"); solo.sleep(200); } private void moveColorWheelPointer(final ColorPicker colorPicker, final int expectedCurrentColor, final int degreesToMove) { final float[] expectedCurrentColorHsv = hsvFrom(expectedCurrentColor); final int currentColor = colorPicker.getColor(); final float[] currentColorHsv = hsvFrom(currentColor); final float[] currentPosition = getCurrentPosition(colorPicker); final float[] newPosition = calculatePosition(colorPicker, currentColorHsv, degreesToMove); assertEquals(expectedCurrentColor, colorPicker.getOldCenterColor()); assertEquals(expectedCurrentColorHsv[0], currentColorHsv[0], 1f); moveColorWheelPointer(currentPosition, newPosition); final int newColor = colorPicker.getColor(); final float[] newColorHsv = hsvFrom(newColor); final float degreesMoved = getDegreesMoved(currentColorHsv, newColorHsv); assertNotEqual(currentColor, newColor); assertEquals(Math.abs(degreesToMove), degreesMoved, 3f); } private void checkTextColorAndClient(final String text, final int expectedColor) { checkTextColor(text, expectedColor); assertEquals(expectedColor, client.getColorOfMessage(me, text)); } private void checkTextColor(final String text, final int expectedColor) { final TextView mainChatView = (TextView) solo.getView(R.id.mainChatView); final int colorForText = getColorForText(mainChatView, text); assertEquals(expectedColor, colorForText); } private void checkPrivateTextColorAndClient(final String text, final int expectedColor) { checkPrivateTextColor(text, expectedColor); assertEquals(expectedColor, client.getColorOfPrivateMessage(me, text)); } private void checkPrivateTextColor(final String text, final int expectedColor) { final TextView privateChatView = (TextView) solo.getView(R.id.privateChatView); final int colorForText = getColorForText(privateChatView, text); assertEquals(expectedColor, colorForText); } private void sendOwnMessage(final String text) { solo.sleep(100); RobotiumTestUtils.writeLine(solo, text); solo.sleep(200); } private void setTopic(final String topic) { RobotiumTestUtils.changeTopicTo(solo, getInstrumentation(), topic); } private void goAway(final String awayMessage) { solo.sleep(100); client.goAway(awayMessage); solo.sleep(100); } private void checkPreviewColor(final int expectedColor, final int previewIndex) { final ImageView colorPreviewImage = (ImageView) solo.getView(R.id.colorPreviewImage, previewIndex); final int colorFromPreviewImage = getColorFromPreviewImage(colorPreviewImage); assertEquals(expectedColor, colorFromPreviewImage); } private void openSettings() { solo.sleep(100); RobotiumTestUtils.openSettings(solo); solo.sleep(200); } private int getColorForText(final TextView textView, final String textToFind) { final Spannable allText = (Spannable) textView.getText(); final int textToFindIndex = allText.toString().indexOf(textToFind); final Spannable[] resultArray = new Spannable[1]; textView.post(new Runnable() { @Override public void run() { // subSequence does something on the ui thread resultArray[0] = (Spannable) allText.subSequence(textToFindIndex, textToFindIndex + textToFind.length()); } }); solo.sleep(200); final Spannable textToFindSpan = resultArray[0]; assertEquals(textToFind, textToFindSpan.toString()); final ForegroundColorSpan[] spans = textToFindSpan.getSpans(0, textToFindSpan.length(), ForegroundColorSpan.class); assertEquals(1, spans.length); return spans[0].getForegroundColor(); } private int getColorFromPreviewImage(final ImageView previewImage) { previewImage.buildDrawingCache(); final Bitmap drawingCache = previewImage.getDrawingCache(); final int pixelColor = drawingCache.getPixel(10, 10); previewImage.destroyDrawingCache(); return pixelColor; } private ColorPicker openColorPicker(final String colorPickerText) { solo.clickOnText(colorPickerText); solo.sleep(500); return solo.getView(ColorPicker.class, 0); } private void moveColorWheelPointer(final float[] fromPosition, final float[] toPosition) { solo.sleep(200); solo.drag(fromPosition[0], toPosition[0], fromPosition[1], toPosition[1], 10); solo.sleep(200); } private float getDegreesMoved(final float[] degreeOneHsv, final float[] degreeTwoHsv) { final float diff = Math.abs(degreeOneHsv[0] - degreeTwoHsv[0]); return Math.min(360 - diff, diff); } private float[] calculatePosition(final ColorPicker colorPicker, final float[] currentColorHsv, final int degreesToMove) { final float currentDegree = currentColorHsv[0]; final float newDegree = currentDegree + degreesToMove % 360; final float angle = (float) Math.toRadians(-newDegree); return getPosition(colorPicker, angle); } private float[] getCurrentPosition(final ColorPicker colorPicker) { final float mAngle = field("mAngle") .ofType(float.class) .in(colorPicker) .get(); return getPosition(colorPicker, mAngle); } private float[] getPosition(final ColorPicker colorPicker, final float angle) { final float mTranslationOffset = field("mTranslationOffset") .ofType(float.class) .in(colorPicker) .get(); final float[] calculatedPointerPosition = method("calculatePointerPosition") .withReturnType(float[].class) .withParameterTypes(float.class) .in(colorPicker) .invoke(angle); final int[] locationOnScreen = new int[2]; colorPicker.getLocationOnScreen(locationOnScreen); calculatedPointerPosition[0] += mTranslationOffset + locationOnScreen[0]; calculatedPointerPosition[1] += mTranslationOffset + locationOnScreen[1]; return calculatedPointerPosition; } }