このメソッドは、引数で渡されたテキストの各文字に対応する KeyCode を入力するものです。
そのため、typeText("日本語") としても"日本語"は入力されませんし、ソフトキーボードが日本語キーボードのときに typeText("andoroido") とすると、"あんどろいど" と入力されます。
また困ったことに、ソフトキーボードが日本語キーボードのときに typeText("12345") とすると、全角で入力されます。orz
日本語を入力するには、setText() で直接セットするしかありません。
そのための ViewAction を実装したクラスを用意しました。
public void testInputJapanese() {
onView(R.id.editText1).perform(clearText(), new InputTextAction("日本語"));
onView(R.id.editText1).check(matches(withText("日本語")));
}
public final class InputTextAction implements ViewAction {
private final String mText;
public InputTextAction(String text) {
checkNotNull(text);
mText = text;
}
@SuppressWarnings("unchecked")
@Override
public Matcher getConstraints() {
return allOf(isDisplayed(), isAssignableFrom(EditText.class));
}
@Override
public void perform(UiController uiController, View view) {
((EditText) view).setText(mText);
}
@Override
public String getDescription() {
return "set text";
}
}
ちなみに typeText() の実体は TypeTextAction クラスです。
ViewActions.java
public final class ViewActions {
...
public static ViewAction typeText(String stringToBeTyped) {
return new TypeTextAction(stringToBeTyped);
}
}
こちらでは UiController の injectString() を利用しています。また、SearchView にも入力できるみたいです。
TypeTextAction.java
public final class TypeTextAction implements ViewAction {
private static final String TAG = TypeTextAction.class.getSimpleName();
private final String stringToBeTyped;
/**
* Constructs {@link TypeTextAction} with given string. If the string is empty it results in no-op
* (nothing is typed).
*
* @param stringToBeTyped String To be typed by {@link TypeTextAction}
*/
public TypeTextAction(String stringToBeTyped) {
checkNotNull(stringToBeTyped);
this.stringToBeTyped = stringToBeTyped;
}
@SuppressWarnings("unchecked")
@Override
public Matcher getConstraints() {
Matcher matchers = allOf(isDisplayed());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
return allOf(matchers, supportsInputMethods());
} else {
// SearchView does not support input methods itself (rather it delegates to an internal text
// view for input).
return allOf(matchers, anyOf(supportsInputMethods(), isAssignableFrom(SearchView.class)));
}
}
@Override
public void perform(UiController uiController, View view) {
// No-op if string is empty.
if (stringToBeTyped.length() == 0) {
Log.w(TAG, "Supplied string is empty resulting in no-op (nothing is typed).");
return;
}
// Perform a click.
new GeneralClickAction(Tap.SINGLE, GeneralLocation.CENTER, Press.PINPOINT)
.perform(uiController, view);
uiController.loopMainThreadUntilIdle();
try {
if (!uiController.injectString(stringToBeTyped)) {
Log.e(TAG, "Failed to type text: " + stringToBeTyped);
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(new RuntimeException("Failed to type text: " + stringToBeTyped))
.build();
}
} catch (InjectEventSecurityException e) {
Log.e(TAG, "Failed to type text: " + stringToBeTyped);
throw new PerformException.Builder()
.withActionDescription(this.getDescription())
.withViewDescription(HumanReadables.describe(view))
.withCause(e)
.build();
}
}
@Override
public String getDescription() {
return "type text";
}
}
UiController はインタフェースで、実装クラスは UiControllerImpl.java です。
UiControllerImpl.java
@Override
public boolean injectString(String str) throws InjectEventSecurityException {
checkNotNull(str);
checkState(Looper.myLooper() == mainLooper, "Expecting to be on main thread!");
initialize();
// No-op if string is empty.
if (str.length() == 0) {
Log.w(TAG, "Supplied string is empty resulting in no-op (nothing is typed).");
return true;
}
boolean eventInjected = false;
KeyCharacterMap keyCharacterMap = getKeyCharacterMap();
// TODO(user): Investigate why not use (as suggested in javadoc of keyCharacterMap.getEvents):
// http://developer.android.com/reference/android/view/KeyEvent.html#KeyEvent(long,
// java.lang.String, int, int)
KeyEvent[] events = keyCharacterMap.getEvents(str.toCharArray());
checkNotNull(events, "Failed to get events for string " + str);
Log.d(TAG, String.format("Injecting string: \"%s\"", str));
for (KeyEvent event : events) {
checkNotNull(event, String.format("Failed to get event for character (%c) with key code (%s)",
event.getKeyCode(), event.getUnicodeChar()));
eventInjected = false;
for (int attempts = 0; !eventInjected && attempts < 4; attempts++) {
attempts++;
// We have to change the time of an event before injecting it because
// all KeyEvents returned by KeyCharacterMap.getEvents() have the same
// time stamp and the system rejects too old events. Hence, it is
// possible for an event to become stale before it is injected if it
// takes too long to inject the preceding ones.
event = KeyEvent.changeTimeRepeat(event, SystemClock.uptimeMillis(), 0);
eventInjected = injectKeyEvent(event);
}
if (!eventInjected) {
Log.e(TAG, String.format("Failed to inject event for character (%c) with key code (%s)",
event.getUnicodeChar(), event.getKeyCode()));
break;
}
}
return eventInjected;
}
0 件のコメント:
コメントを投稿