From 2bcc775b01a1d3ad6561207a859e6e867080e3fb Mon Sep 17 00:00:00 2001 From: Isaac Murchie Date: Wed, 7 May 2014 15:55:56 -0700 Subject: [PATCH] Allow for encoding of non-ASCII text in Android --- .../android/bootstrap/AndroidElement.java | 10 +- .../bootstrap/utils/UnicodeEncoder.java | 32 ++++++ .../android/apidemos/keyboard-specs.js | 108 ++++++++++++++++-- 3 files changed, 139 insertions(+), 11 deletions(-) create mode 100644 lib/devices/android/bootstrap/src/io/appium/android/bootstrap/utils/UnicodeEncoder.java diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java index b30e40830..17a0b300b 100644 --- a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/AndroidElement.java @@ -3,6 +3,7 @@ package io.appium.android.bootstrap; import io.appium.android.bootstrap.exceptions.InvalidCoordinatesException; import io.appium.android.bootstrap.exceptions.NoAttributeFoundException; import io.appium.android.bootstrap.utils.Point; +import io.appium.android.bootstrap.utils.UnicodeEncoder; import android.graphics.Rect; import android.os.Build; @@ -232,7 +233,14 @@ public class AndroidElement { } public boolean setText(final String text) throws UiObjectNotFoundException { - return el.setText(text); + if (UnicodeEncoder.needsEncoding(text)) { + Logger.info("Sending Unicode text to element: " + text); + String encodedText = UnicodeEncoder.encode(text); + return el.setText(encodedText); + } else { + Logger.info("Sending plain text to element: " + text); + return el.setText(text); + } } public boolean performMultiPointerGesture(PointerCoords[] ...touches) { diff --git a/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/utils/UnicodeEncoder.java b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/utils/UnicodeEncoder.java new file mode 100644 index 000000000..613fd7346 --- /dev/null +++ b/lib/devices/android/bootstrap/src/io/appium/android/bootstrap/utils/UnicodeEncoder.java @@ -0,0 +1,32 @@ +package io.appium.android.bootstrap.utils; + +import java.nio.charset.Charset; + + +public class UnicodeEncoder { + private static final Charset M_UTF7 = Charset.forName("x-IMAP-mailbox-name"); + private static final Charset ASCII = Charset.forName("US-ASCII"); + + + public static String encode(final String text) { + byte[] encoded = text.getBytes(M_UTF7); + return new String(encoded, ASCII); + } + + public static boolean needsEncoding(final String text) { + char[] chars = text.toCharArray(); + for (int i = 0; i < chars.length; i++) { + int cp = Character.codePointAt(chars, i); + if (cp > 0x7F) { + if (cp >= 0xE000 && cp <= 0xE040) { + // Selenium uses a Unicode PUA to cover certain special characters + // see https://code.google.com/p/selenium/source/browse/java/client/src/org/openqa/selenium/Keys.java + // these should juse be passed through as is. + return false; + } + return true; + } + } + return false; + } +} diff --git a/test/functional/android/apidemos/keyboard-specs.js b/test/functional/android/apidemos/keyboard-specs.js index 08d4c8e75..99cc41fc0 100644 --- a/test/functional/android/apidemos/keyboard-specs.js +++ b/test/functional/android/apidemos/keyboard-specs.js @@ -1,23 +1,22 @@ "use strict"; var setup = require("../../common/setup-base") - , desired = require("./desired"), - _ = require('underscore'); + , desired = require("./desired") + , _ = require('underscore') + , androidReset = require('../../../helpers/reset').androidReset; describe("apidemo - keyboard -", function () { var driver; setup(this, _.defaults({appActivity: "view.Controls1" }, desired)) - .then(function (d) { driver = d; }); + .then(function (d) { driver = d; }); + + beforeEach(function (done) { + androidReset('com.example.android.apis', 'view.Controls1').nodeify(done); + }); it('should be able to edit a text field', function (done) { var testText = "this is awesome!"; - var el = function () { - return driver.elementByClassName('android.widget.EditText'); - }; - driver - .resolve(el()).clear().text().should.become("") - .then(el).sendKeys(testText).text().should.become(testText) - .nodeify(done); + runTextEditTest(testText, done); }); //todo: not working in nexus 7 @@ -29,7 +28,96 @@ describe("apidemo - keyboard -", function () { driver .resolve(el()).clear().text().should.become("") .then(el).sendKeys(testText).text().should.become(testText) + .sleep(2) .then(el).clear().text().should.become("") .nodeify(done); }); + + describe('editing unicode text field', function () { + it('should be able to send &-', function (done) { + var testText = '&-'; + runTextEditTest(testText, done); + }); + + it('should be able to send & and - in other text', function (done) { + var testText = 'In the mid-1990s he ate fish & chips as mayor-elect.'; + runTextEditTest(testText, done); + }); + + it('should be able to send - in text', function (done) { + var testText = 'Super-test.'; + runTextEditTest(testText, done); + }); + + it('should be able to send & in text', function (done) { + var testText = 'Fish & chips'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send roman characters with diacritics', function (done) { + var testText = 'Áé Œ ù ḍ'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Arabic', function (done) { + var testText = 'تجريب'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Hebrew', function (done) { + var testText = 'בדיקות'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Tamil', function (done) { + var testText = 'சோதனை'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Hindi', function (done) { + var testText = 'परीक्षण'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Gujarati', function (done) { + var testText = 'પરીક્ષણ'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Bengali', function (done) { + var testText = 'টেস্টিং'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Chinese', function (done) { + var testText = '测试'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Japanese', function (done) { + var testText = '検査'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Georgian', function (done) { + var testText = 'ტესტირება'; + runTextEditTest(testText, done); + }); + + it.skip('should be able to send Russian', function (done) { + var testText = 'тестирование'; + runTextEditTest(testText, done); + }); + }); + + var runTextEditTest = function (testText, done) { + var el = function () { + return driver.elementByClassName('android.widget.EditText'); + }; + driver + .sleep(1) + .resolve(el()).clear().text().should.become('') + .then(el).sendKeys(testText).text().should.become(testText) + .nodeify(done); + }; });