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

Commit 136ca1e8 authored by android-build-team Robot's avatar android-build-team Robot Committed by Android (Google) Code Review
Browse files

Merge changes Ic196ef31,Ifeb8d038

* changes:
  Uses a custom JUnit rule to preserve value of autofill service settings.
  Moar PERF tests for autofill.
parents a311b3f1 e4d05388
Loading
Loading
Loading
Loading
+94 −27
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.os.Looper;
import android.os.Bundle;
import android.os.Bundle;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.PerfStatusReporter;
import android.perftests.utils.SettingsHelper;
import android.perftests.utils.SettingsHelper;
import android.perftests.utils.SettingsStateKeeperRule;
import android.perftests.utils.ShellHelper;
import android.perftests.utils.ShellHelper;
import android.util.Log;
import android.util.Log;
import android.view.View;
import android.view.View;
@@ -42,6 +43,7 @@ import java.util.Arrays;
import org.junit.Test;
import org.junit.Test;
import org.junit.After;
import org.junit.After;
import org.junit.Before;
import org.junit.Before;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Rule;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.Parameterized.Parameters;
@@ -67,6 +69,10 @@ public class AutofillPerfTest {
        mLayoutId = layoutId;
        mLayoutId = layoutId;
    }
    }


    @ClassRule
    public static final SettingsStateKeeperRule mServiceSettingsKeeper = new SettingsStateKeeperRule(
            InstrumentationRegistry.getTargetContext(), Settings.Secure.AUTOFILL_SERVICE);

    @Rule
    @Rule
    public ActivityTestRule<StubActivity> mActivityRule =
    public ActivityTestRule<StubActivity> mActivityRule =
            new ActivityTestRule<StubActivity>(StubActivity.class);
            new ActivityTestRule<StubActivity>(StubActivity.class);
@@ -97,11 +103,6 @@ public class AutofillPerfTest {
        MyAutofillService.resetStaticState();
        MyAutofillService.resetStaticState();
    }
    }


    @After
    public void cleanup() {
        resetService();
    }

    /**
    /**
     * This is the baseline test for focusing the 2 views when autofill is disabled.
     * This is the baseline test for focusing the 2 views when autofill is disabled.
     */
     */
@@ -109,7 +110,7 @@ public class AutofillPerfTest {
    public void testFocus_noService() throws Throwable {
    public void testFocus_noService() throws Throwable {
        resetService();
        resetService();


        focusTest();
        focusTest(false);
    }
    }


    /**
    /**
@@ -121,13 +122,7 @@ public class AutofillPerfTest {
        MyAutofillService.newCannedResponse().reply();
        MyAutofillService.newCannedResponse().reply();
        setService();
        setService();


        // Must first focus in a field to trigger autofill and wait for service response
        focusTest(true);
        // outside the loop
        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
        MyAutofillService.getLastFillRequest();

        // Test properly speaking
        focusTest();


        // Sanity check
        // Sanity check
        MyAutofillService.assertNoAsyncErrors();
        MyAutofillService.assertNoAsyncErrors();
@@ -144,13 +139,7 @@ public class AutofillPerfTest {
                .reply();
                .reply();
        setService();
        setService();


        // Must first focus in a field to trigger autofill and wait for service response
        focusTest(true);
        // outside the loop
        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
        MyAutofillService.getLastFillRequest();

        // Test properly speaking
        focusTest();


        // Sanity check
        // Sanity check
        MyAutofillService.assertNoAsyncErrors();
        MyAutofillService.assertNoAsyncErrors();
@@ -168,29 +157,107 @@ public class AutofillPerfTest {
                .reply();
                .reply();
        setService();
        setService();


        focusTest(true);

        // Sanity check
        MyAutofillService.assertNoAsyncErrors();
    }

    private void focusTest(boolean waitForService) throws Throwable {
        // Must first focus in a field to trigger autofill and wait for service response
        // Must first focus in a field to trigger autofill and wait for service response
        // outside the loop
        // outside the loop
        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
        if (waitForService) {
            MyAutofillService.getLastFillRequest();
            MyAutofillService.getLastFillRequest();
        }
        mActivityRule.runOnUiThread(() -> {
            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
            while (state.keepRunning()) {
                mUsername.requestFocus();
                mPassword.requestFocus();
            }
        });
    }


        focusTest();
    /**
     * This is the baseline test for changing the 2 views when autofill is disabled.
     */
    @Test
    public void testChange_noService() throws Throwable {
        resetService();

        changeTest(false);
    }

    /**
     * This time the service is called, but it returns a {@code null} response so the UI behaves
     * as if autofill was disabled.
     */
    @Test
    public void testChange_serviceDoesNotAutofill() throws Throwable {
        MyAutofillService.newCannedResponse().reply();
        setService();

        changeTest(true);


        // Sanity check
        // Sanity check
        MyAutofillService.assertNoAsyncErrors();
        MyAutofillService.assertNoAsyncErrors();
    }
    }


    private void focusTest() throws Throwable {
    /**
     * Now the service returns autofill data, for both username and password.
     */
    @Test
    public void testChange_autofillBothFields() throws Throwable {
        MyAutofillService.newCannedResponse()
                .setUsername(mUsername.getAutofillId(), "user")
                .setPassword(mPassword.getAutofillId(), "pass")
                .reply();
        setService();

        changeTest(true);

        // Sanity check
        MyAutofillService.assertNoAsyncErrors();
    }

    /**
     * Now the service returns autofill data, but just for username.
     */
    @Test
    public void testChange_autofillUsernameOnly() throws Throwable {
        // Must set ignored ids so focus on password does not trigger new requests
        MyAutofillService.newCannedResponse()
                .setUsername(mUsername.getAutofillId(), "user")
                .setIgnored(mPassword.getAutofillId())
                .reply();
        setService();

        changeTest(true);

        // Sanity check
        MyAutofillService.assertNoAsyncErrors();
    }

    private void changeTest(boolean waitForService) throws Throwable {
        // Must first focus in a field to trigger autofill and wait for service response
        // outside the loop
        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
        if (waitForService) {
            MyAutofillService.getLastFillRequest();
        }
        mActivityRule.runOnUiThread(() -> {
        mActivityRule.runOnUiThread(() -> {

            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
            while (state.keepRunning()) {
            while (state.keepRunning()) {
                mUsername.requestFocus();
                mUsername.setText("");
                mPassword.requestFocus();
                mUsername.setText("a");
                mPassword.setText("");
                mPassword.setText("x");
            }
            }
        });
        });
    }
    }


    // TODO: add tests for changing value of the fields

    /**
    /**
     * Uses the {@code settings} binary to set the autofill service.
     * Uses the {@code settings} binary to set the autofill service.
     */
     */
+39 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.perftests.utils;

import android.content.Context;
import android.provider.Settings;

import androidx.annotation.NonNull;

/**
 * JUnit rule used to restore a {@link Settings} preference after the test is run.
 *
 * <p>It stores the current value before the test, and restores it after the test (if necessary).
 */
public class SettingsStateKeeperRule extends StateKeeperRule<String> {

    /**
     * Default constructor.
     *
     * @param context context used to retrieve the {@link Settings} provider.
     * @param key prefence key.
     */
    public SettingsStateKeeperRule(@NonNull Context context, @NonNull String key) {
        super(new SettingsStateManager(context, SettingsHelper.NAMESPACE_SECURE, key));
    }
}
+63 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.perftests.utils;

import android.content.Context;
import android.provider.Settings;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * Manages the state of a preference backed by {@link Settings}.
 */
public class SettingsStateManager implements StateManager<String> {

    private final Context mContext;
    private final String mNamespace;
    private final String mKey;

    /**
     * Default constructor.
     *
     * @param context context used to retrieve the {@link Settings} provider.
     * @param namespace settings namespace.
     * @param key prefence key.
     */
    public SettingsStateManager(@NonNull Context context, @NonNull String namespace,
            @NonNull String key) {
        mContext = context;
        mNamespace = namespace;
        mKey = key;
    }

    @Override
    public void set(@Nullable String value) {
        SettingsHelper.syncSet(mContext, mNamespace, mKey, value);
    }

    @Override
    @Nullable
    public String get() {
        return SettingsHelper.get(mNamespace, mKey);
    }

    @Override
    public String toString() {
        return "SettingsStateManager[namespace=" + mNamespace + ", key=" + mKey + "]";
    }
}
+63 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package android.perftests.utils;

import androidx.annotation.NonNull;

import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;

import java.util.Objects;

/**
 * JUnit rule used to restore a state after the test is run.
 *
 * <p>It stores the current state before the test, and restores it after the test (if necessary).
 */
public class StateKeeperRule<T> implements TestRule {

    private final StateManager<T> mStateManager;

    /**
     * Default constructor.
     *
     * @param stateManager abstraction used to manage the state.
     */
    public StateKeeperRule(StateManager<T> stateManager) {
        mStateManager = stateManager;
    }

    @Override
    public Statement apply(Statement base, Description description) {
        return new Statement() {

            @Override
            public void evaluate() throws Throwable {
                final T previousValue = mStateManager.get();
                try {
                    base.evaluate();
                } finally {
                    final T currentValue = mStateManager.get();
                    if (!Objects.equals(previousValue, currentValue)) {
                        mStateManager.set(previousValue);
                    }
                }
            }
        };
    }
}
+34 −0
Original line number Original line Diff line number Diff line
/*
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package android.perftests.utils;

import androidx.annotation.Nullable;

/**
 * Abstraction for a state that is managed somewhere, like Android Settings.
 */
public interface StateManager<T> {

    /**
     * Sets a new state.
     */
    void set(@Nullable T value);

    /**
     * Gets the current state.
     */
    @Nullable T get();
}