Skip to content
This repository has been archived by the owner on Jul 7, 2022. It is now read-only.

Commit

Permalink
keyboard service test introduced
Browse files Browse the repository at this point in the history
  • Loading branch information
sealor committed Mar 3, 2016
1 parent 6bbc9aa commit 4711d76
Show file tree
Hide file tree
Showing 13 changed files with 337 additions and 33 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ android {
buildToolsVersion "21.1.2"

defaultConfig {
applicationId "io.github.sealor.prototype.android.espresso.ui.testing"
applicationId "io.github.sealor.prototype.android.espresso.keyboard.testing"
minSdkVersion 19
targetSdkVersion 21
versionCode 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package io.github.sealor.prototype.android.espresso.keyboard.testing;


import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.provider.Settings;
import android.view.inputmethod.InputMethodManager;

public class KeyboardSwitchHelper {

public static final int POLLING_PERIOD_IN_MILLIS = 1000;

private final Activity activity;
private final String packageName;
private final ContentResolver contentResolver;
private final InputMethodManager inputMethodManager;

public KeyboardSwitchHelper(Activity activity) {
this.activity = activity;
this.packageName = activity.getPackageName();
this.contentResolver = activity.getContentResolver();
this.inputMethodManager = (InputMethodManager) activity.getSystemService(Context.INPUT_METHOD_SERVICE);
}

private String retrieveCurrentKeyboardName() {
return Settings.Secure.getString(this.contentResolver, Settings.Secure.DEFAULT_INPUT_METHOD);
}

private boolean isAppKeyboardTheCurrentKeyboard() {
return retrieveCurrentKeyboardName().startsWith(this.packageName);
}

private boolean isTestActivityFocused() {
return this.activity.hasWindowFocus();
}

private void showKeyboardPickerDialog() {
this.inputMethodManager.showInputMethodPicker();
}

private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

public void showKeyboardPickerDialogIfNeededAndWaitForSwitch() {
if (!isAppKeyboardTheCurrentKeyboard()) {
showKeyboardPickerDialog();

do {
sleep(POLLING_PERIOD_IN_MILLIS);
} while (!isTestActivityFocused());
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package io.github.sealor.prototype.android.espresso.keyboard.testing;

import android.content.Intent;
import android.os.IBinder;
import android.support.test.InstrumentationRegistry;
import android.support.test.rule.ActivityTestRule;
import android.support.test.rule.ServiceTestRule;

import org.junit.Rule;
import org.junit.Test;

import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.util.concurrent.TimeoutException;

import static android.support.test.espresso.Espresso.onView;
import static android.support.test.espresso.action.ViewActions.click;
import static android.support.test.espresso.assertion.ViewAssertions.matches;
import static android.support.test.espresso.matcher.ViewMatchers.withId;
import static android.support.test.espresso.matcher.ViewMatchers.withText;

public class MainActivityInstrumentationTest {

@Rule
public ActivityTestRule<MainActivity> activityTestRule = new ActivityTestRule<>(MainActivity.class);

@Rule
public final ServiceTestRule mServiceRule = new ServiceTestRule();

@Test
public void validateEditTextWithKeyboardInput() throws TimeoutException {
KeyboardSwitchHelper helper = new KeyboardSwitchHelper(this.activityTestRule.getActivity());
helper.showKeyboardPickerDialogIfNeededAndWaitForSwitch();

Intent serviceIntent = new Intent(InstrumentationRegistry.getTargetContext(), MyKeyboard.class);
IBinder binder = mServiceRule.bindService(serviceIntent);
MyKeyboard keyboard = retrieveMyKeyboardInstance(binder);

onView(withId(R.id.input)).perform(click());
keyboard.onText("Stefan");
onView(withId(R.id.button)).perform(click());
onView(withId(R.id.output)).check(matches(withText("Hello Stefan!")));
}

private MyKeyboard retrieveMyKeyboardInstance(IBinder binder) {
try {
Class wrapperClass = Class.forName("android.inputmethodservice.IInputMethodWrapper");
Field mTargetField = wrapperClass.getDeclaredField("mTarget");
mTargetField.setAccessible(true);

WeakReference<MyKeyboard> weakReference = (WeakReference<MyKeyboard>) mTargetField.get(binder);
return weakReference.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}

This file was deleted.

18 changes: 16 additions & 2 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -1,22 +1,36 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.sealor.prototype.android.espresso.ui.testing">
package="io.github.sealor.prototype.android.espresso.keyboard.testing">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">

<activity
android:name="io.github.sealor.prototype.android.espresso.ui.testing.MainActivity"
android:name="io.github.sealor.prototype.android.espresso.keyboard.testing.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

<service
android:name="io.github.sealor.prototype.android.espresso.keyboard.testing.MyKeyboard"
android:permission="android.permission.BIND_INPUT_METHOD">
<intent-filter>
<action android:name="android.view.InputMethod" />
</intent-filter>

<meta-data
android:name="android.view.im"
android:resource="@xml/method" />
</service>

</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package io.github.sealor.prototype.android.espresso.ui.testing;
package io.github.sealor.prototype.android.espresso.keyboard.testing;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package io.github.sealor.prototype.android.espresso.keyboard.testing;

import android.inputmethodservice.InputMethodService;
import android.inputmethodservice.Keyboard;
import android.inputmethodservice.KeyboardView;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.inputmethod.EditorInfo;

public class MyKeyboard extends InputMethodService implements KeyboardView.OnKeyboardActionListener {

public final static int KEYCODE_ENTER = -10;

private Keyboard keyboardLayout;
private KeyboardView keyboardView;

private boolean shifted = false;

@Override
public void onInitializeInterface() {
super.onInitializeInterface();

this.keyboardLayout = new Keyboard(this, R.xml.qwertz);
}

@Override
public void onStartInput(EditorInfo attribute, boolean restarting) {
super.onStartInput(attribute, restarting);
}

@Override
public void onFinishInput() {
super.onFinishInput();

if (this.keyboardView != null) {
this.keyboardView.closing();
}
}

@Override
public View onCreateInputView() {
Log.i("tag", "createInputView");
this.keyboardView = (KeyboardView) getLayoutInflater().inflate(R.layout.keyboardview, null);
this.keyboardView.setKeyboard(this.keyboardLayout);
this.keyboardView.setOnKeyboardActionListener(this);
return this.keyboardView;
}

private void sendTypedKey(int keyEventCode) {
getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyEventCode));
getCurrentInputConnection().sendKeyEvent(new KeyEvent(KeyEvent.ACTION_UP, keyEventCode));
}

private void updateShiftState() {
this.keyboardView.setShifted(this.shifted);
this.keyboardLayout.setShifted(this.shifted);
}

@Override
public void onKey(int primaryCode, int[] keyCodes) {
Log.d("tag", "onKey: " + primaryCode);

if (primaryCode > 0) {
String text = String.valueOf((char) primaryCode);
if (this.keyboardLayout.isShifted()) {
text = text.toUpperCase();
}
onText(text);
} else if (primaryCode == Keyboard.KEYCODE_DELETE) {
sendTypedKey(KeyEvent.KEYCODE_DEL);
} else if (primaryCode == Keyboard.KEYCODE_SHIFT) {
shifted = !shifted;
updateShiftState();
} else if (primaryCode == MyKeyboard.KEYCODE_ENTER) {
sendTypedKey(KeyEvent.KEYCODE_ENTER);
}
}

@Override
public void onText(CharSequence text) {
Log.d("tag", "onText: " + text);

getCurrentInputConnection().commitText(text, 1);

shifted = false;
updateShiftState();
}

@Override
public void onPress(int primaryCode) {
Log.d("tag", "onPress: " + primaryCode);
}

@Override
public void onRelease(int primaryCode) {
Log.d("tag", "onRelease: " + primaryCode);
}

@Override
public void swipeDown() {
}

@Override
public void swipeLeft() {
}

@Override
public void swipeRight() {
}

@Override
public void swipeUp() {
}
}
2 changes: 1 addition & 1 deletion app/src/main/res/layout/activity_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="io.github.sealor.prototype.android.espresso.ui.testing.MainActivity">
tools:context="io.github.sealor.prototype.android.espresso.keyboard.testing.MainActivity">

<TextView
android:id="@+id/inputLabel"
Expand Down
6 changes: 6 additions & 0 deletions app/src/main/res/layout/keyboardview.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<android.inputmethodservice.KeyboardView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyboardView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true" />
2 changes: 1 addition & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<resources>
<string name="app_name">Prototype Android Espresso UI Testing</string>
<string name="app_name">Prototype Android Espresso Keyboard Testing</string>
<string name="action_settings">Settings</string>
<string name="type_your_name">Type your name:</string>
<string name="greet_me">greet me</string>
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/xml/method.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<input-method />
Loading

0 comments on commit 4711d76

Please sign in to comment.