Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2b60234a authored by Yabin Huang's avatar Yabin Huang
Browse files

Add more ConcurrentMultiUserTest

Bug: 350562427
Test: atest com.android.server.inputmethod.multisessiontest.ConcurrentMultiUserTest
Flag: TEST_ONLY
Change-Id: I056b49a4454233762348d7567e0918eeae7b3c0f
parent 177af6b6
Loading
Loading
Loading
Loading
+109 −5
Original line number Diff line number Diff line
@@ -23,10 +23,15 @@ import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentat
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.getResponderUserId;
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.launchActivityAsUserSync;
import static com.android.compatibility.common.util.concurrentuser.ConcurrentUserActivityUtils.sendBundleAndWaitForReply;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_DISPLAY_ID;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_EDITTEXT_CENTER;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_IME_SHOWN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_REQUEST_CODE;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_RESULT_CODE;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REPLY_IME_HIDDEN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_DISPLAY_ID;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_EDITTEXT_POSITION;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_HIDE_IME;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_IME_STATUS;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_SHOW_IME;

import static com.google.common.truth.Truth.assertWithMessage;

@@ -66,6 +71,7 @@ public final class ConcurrentMultiUserTest {
    private static final ComponentName TEST_ACTIVITY = new ComponentName(
            getInstrumentation().getTargetContext().getPackageName(),
            MainActivity.class.getName());
    private static final long WAIT_TIME_MS = 3000L;
    private final Context mContext = getInstrumentation().getTargetContext();
    private final InputMethodManager mInputMethodManager =
            mContext.getSystemService(InputMethodManager.class);
@@ -96,7 +102,7 @@ public final class ConcurrentMultiUserTest {
    }

    @Test
    public void driverShowImeNotAffectPassenger() {
    public void driverShowImeNotAffectPassenger() throws Exception {
        assertDriverImeHidden();
        assertPassengerImeHidden();

@@ -104,6 +110,33 @@ public final class ConcurrentMultiUserTest {
        assertPassengerImeHidden();
    }

    @Test
    public void passengerShowImeNotAffectDriver() throws Exception {
        assertDriverImeHidden();
        assertPassengerImeHidden();

        showPassengerImeAndAssert();
        assertDriverImeHidden();
    }

    @Test
    public void driverHideImeNotAffectPassenger() throws Exception {
        showDriverImeAndAssert();
        showPassengerImeAndAssert();

        hideDriverImeAndAssert();
        assertPassengerImeShown();
    }

    @Test
    public void passengerHideImeNotAffectDriver() throws Exception {
        showDriverImeAndAssert();
        showPassengerImeAndAssert();

        hidePassengerImeAndAssert();
        assertDriverImeShown();
    }

    @Test
    public void imeListNotEmpty() {
        List<InputMethodInfo> driverImeList = mInputMethodManager.getInputMethodList();
@@ -156,6 +189,11 @@ public final class ConcurrentMultiUserTest {
        setImeForUser(passenger, driver);
    }

    private void assertDriverImeShown() {
        assertWithMessage("Driver IME should be shown")
                .that(mActivity.isMyImeVisible()).isTrue();
    }

    private void assertDriverImeHidden() {
        assertWithMessage("Driver IME should be hidden")
                .that(mActivity.isMyImeVisible()).isFalse();
@@ -167,13 +205,79 @@ public final class ConcurrentMultiUserTest {
        Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
                mPeerUserId, bundleToSend);
        assertWithMessage("Passenger IME should be hidden")
                .that(receivedBundle.getInt(KEY_RESULT_CODE)).isEqualTo(REPLY_IME_HIDDEN);
                .that(receivedBundle.getBoolean(KEY_IME_SHOWN, /* defaultValue= */ true)).isFalse();
    }

    private void assertPassengerImeShown() {
        final Bundle bundleToSend = new Bundle();
        bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_IME_STATUS);
        Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
                mPeerUserId, bundleToSend);
        assertWithMessage("Passenger IME should be shown")
                .that(receivedBundle.getBoolean(KEY_IME_SHOWN)).isTrue();
    }

    private void showDriverImeAndAssert() {
    private void showDriverImeAndAssert() throws Exception {
        //  WindowManagerInternal only allows the top focused display to show IME, so this method
        //  taps the driver display in case it is not the top focused display.
        moveDriverDisplayToTop();

        mActivity.showMyImeAndWait();
    }

    private void hideDriverImeAndAssert() {
        mActivity.hideMyImeAndWait();
    }

    private void showPassengerImeAndAssert() throws Exception {
        // WindowManagerInternal only allows the top focused display to show IME, so this method
        // taps the passenger display in case it is not the top focused display.
        movePassengerDisplayToTop();

        Bundle bundleToSend = new Bundle();
        bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_SHOW_IME);
        Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
                mPeerUserId, bundleToSend);

        assertWithMessage("Passenger IME should be shown")
                .that(receivedBundle.getBoolean(KEY_IME_SHOWN)).isTrue();
    }

    private void hidePassengerImeAndAssert() {
        Bundle bundleToSend = new Bundle();
        bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_HIDE_IME);
        Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
                mPeerUserId, bundleToSend);

        assertWithMessage("Passenger IME should be hidden")
                .that(receivedBundle.getBoolean(KEY_IME_SHOWN, /* defaultValue= */ true)).isFalse();
    }

    private void moveDriverDisplayToTop() throws Exception {
        float[] driverEditTextCenter = mActivity.getEditTextCenter();
        SystemUtil.runShellCommand(mUiAutomation, String.format("input tap %f %f",
                driverEditTextCenter[0], driverEditTextCenter[1]));
        // TODO(b/350562427): get rid of Thread.sleep().
        Thread.sleep(WAIT_TIME_MS);
    }

    private void movePassengerDisplayToTop() throws Exception {
        final Bundle bundleToSend = new Bundle();
        bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_EDITTEXT_POSITION);
        Bundle receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
                mPeerUserId, bundleToSend);
        final float[] passengerEditTextCenter = receivedBundle.getFloatArray(KEY_EDITTEXT_CENTER);

        bundleToSend.putInt(KEY_REQUEST_CODE, REQUEST_DISPLAY_ID);
        receivedBundle = sendBundleAndWaitForReply(TEST_ACTIVITY.getPackageName(),
                mPeerUserId, bundleToSend);
        final int passengerDisplayId = receivedBundle.getInt(KEY_DISPLAY_ID);
        SystemUtil.runShellCommand(mUiAutomation, String.format("input -d %d tap %f %f",
                passengerDisplayId, passengerEditTextCenter[0], passengerEditTextCenter[1]));
        // TODO(b/350562427): get rid of Thread.sleep().
        Thread.sleep(WAIT_TIME_MS);
    }

    /**
     * Disables/enables IME for {@code user1}, then verifies that the IME settings for {@code user1}
     * has changed as expected and {@code user2} stays the same.
+76 −17
Original line number Diff line number Diff line
@@ -16,20 +16,25 @@

package com.android.server.inputmethod.multisessiontest;

import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_DISPLAY_ID;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_EDITTEXT_CENTER;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_IME_SHOWN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_REQUEST_CODE;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.KEY_RESULT_CODE;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REPLY_IME_HIDDEN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REPLY_IME_SHOWN;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_DISPLAY_ID;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_EDITTEXT_POSITION;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_HIDE_IME;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_IME_STATUS;
import static com.android.server.inputmethod.multisessiontest.TestRequestConstants.REQUEST_SHOW_IME;

import android.app.Activity;
import android.os.Bundle;
import android.os.Process;
import android.util.Log;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;

import androidx.annotation.WorkerThread;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;

import com.android.compatibility.common.util.PollingCheck;
@@ -43,7 +48,6 @@ public final class MainActivity extends ConcurrentUserActivityBase {
    private static final long WAIT_IME_TIMEOUT_MS = 3000;

    private EditText mEditor;
    private InputMethodManager mImm;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
@@ -52,19 +56,56 @@ public final class MainActivity extends ConcurrentUserActivityBase {
                + Process.myUserHandle().getIdentifier() + " on display "
                + getDisplay().getDisplayId());
        setContentView(R.layout.main_activity);
        mImm = getSystemService(InputMethodManager.class);
        mEditor = requireViewById(R.id.edit_text);
    }

    @Override
    protected void onResume() {
        super.onResume();
        Log.v(TAG, "onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();
        Log.v(TAG, "onPause");
    }

    @Override
    protected void onStop() {
        super.onStop();
        Log.v(TAG, "onResume");
    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        Log.v(TAG, "onWindowFocusChanged " + hasFocus);
    }

    @Override
    @WorkerThread
    protected Bundle onBundleReceived(Bundle receivedBundle) {
        final int requestCode = receivedBundle.getInt(KEY_REQUEST_CODE);
        Log.v(TAG, "onBundleReceived() with request code:" + requestCode);
        final Bundle replyBundle = new Bundle();
        switch (requestCode) {
            case REQUEST_IME_STATUS:
                replyBundle.putInt(KEY_RESULT_CODE,
                        isMyImeVisible() ? REPLY_IME_SHOWN : REPLY_IME_HIDDEN);
                replyBundle.putBoolean(KEY_IME_SHOWN, isMyImeVisible());
                break;
            case REQUEST_SHOW_IME:
                showMyImeAndWait();
                replyBundle.putBoolean(KEY_IME_SHOWN, isMyImeVisible());
                break;
            case REQUEST_HIDE_IME:
                hideMyImeAndWait();
                replyBundle.putBoolean(KEY_IME_SHOWN, isMyImeVisible());
                break;
            case REQUEST_EDITTEXT_POSITION:
                replyBundle.putFloatArray(KEY_EDITTEXT_CENTER, getEditTextCenter());
                break;
            case REQUEST_DISPLAY_ID:
                replyBundle.putInt(KEY_DISPLAY_ID, getDisplay().getDisplayId());
                break;
            default:
                throw new RuntimeException("Received undefined request code:" + requestCode);
@@ -77,23 +118,41 @@ public final class MainActivity extends ConcurrentUserActivityBase {
        return insets == null ? false : insets.isVisible(WindowInsetsCompat.Type.ime());
    }

    float[] getEditTextCenter() {
        final float editTextCenterX = mEditor.getX() + 0.5f * mEditor.getWidth();
        final float editTextCenterY = mEditor.getY() + 0.5f * mEditor.getHeight();
        return new float[]{editTextCenterX, editTextCenterY};
    }

    @WorkerThread
    void showMyImeAndWait() {
        Log.v(TAG, "showSoftInput");
        runOnUiThread(() -> {
            // requestFocus() must run on UI thread.
            // View#requestFocus() and WindowInsetsControllerCompat#show() must run on UI thread.
            if (!mEditor.requestFocus()) {
                Log.e(TAG, "Failed to focus on mEditor");
                return;
            }
            if (!mImm.showSoftInput(mEditor, /* flags= */ 0)) {
                Log.e(TAG, String.format("Failed to show my IME as user %d, "
                                + "mEditor:focused=%b,hasWindowFocus=%b",
                        Process.myUserHandle().getIdentifier(),
                        mEditor.isFocused(), mEditor.hasWindowFocus()));
            }
            // Compared to mImm.showSoftInput(), the call below is the recommended way to show the
            // keyboard because it is guaranteed to be scheduled after the window is focused.
            Log.v(TAG, "showSoftInput");
            WindowCompat.getInsetsController(getWindow(), mEditor).show(
                    WindowInsetsCompat.Type.ime());
        });
        PollingCheck.waitFor(WAIT_IME_TIMEOUT_MS, () -> isMyImeVisible(),
                String.format("My IME (user %d) didn't show up",
                String.format("%s: My IME (user %d) didn't show up", TAG,
                        Process.myUserHandle().getIdentifier()));
    }

    @WorkerThread
    void hideMyImeAndWait() {
        runOnUiThread(() -> {
            Log.v(TAG, "hideSoftInput");
            // WindowInsetsControllerCompat#hide() must run on UI thread.
            WindowCompat.getInsetsController(getWindow(), mEditor)
                    .hide(WindowInsetsCompat.Type.ime());
        });
        PollingCheck.waitFor(WAIT_IME_TIMEOUT_MS, () -> !isMyImeVisible(),
                String.format("%s: My IME (user %d) is still shown", TAG,
                        Process.myUserHandle().getIdentifier()));
    }
}
+7 −3
Original line number Diff line number Diff line
@@ -21,9 +21,13 @@ final class TestRequestConstants {
    }

    public static final String KEY_REQUEST_CODE = "key_request_code";
    public static final String KEY_RESULT_CODE = "key_result_code";
    public static final String KEY_EDITTEXT_CENTER = "key_edittext_center";
    public static final String KEY_DISPLAY_ID = "key_display_id";
    public static final String KEY_IME_SHOWN = "key_ime_shown";

    public static final int REQUEST_IME_STATUS = 1;
    public static final int REPLY_IME_SHOWN = 2;
    public static final int REPLY_IME_HIDDEN = 3;
    public static final int REQUEST_SHOW_IME = 2;
    public static final int REQUEST_HIDE_IME = 3;
    public static final int REQUEST_EDITTEXT_POSITION = 4;
    public static final int REQUEST_DISPLAY_ID = 5;
}