Merge "Merge "Use NORMAL synchronous mode for WAL journal mode" into pi-dev am: 4ca34d7bd7 am: eb44a1a85f"
diff --git a/apct-tests/perftests/core/src/android/view/autofill/AutofillPerfTest.java b/apct-tests/perftests/core/src/android/view/autofill/AutofillPerfTest.java
index bc92aab..8acd6eb 100644
--- a/apct-tests/perftests/core/src/android/view/autofill/AutofillPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/autofill/AutofillPerfTest.java
@@ -21,6 +21,7 @@
 import android.os.Bundle;
 import android.perftests.utils.PerfStatusReporter;
 import android.perftests.utils.SettingsHelper;
+import android.perftests.utils.SettingsStateKeeperRule;
 import android.perftests.utils.ShellHelper;
 import android.util.Log;
 import android.view.View;
@@ -42,6 +43,7 @@
 import org.junit.Test;
 import org.junit.After;
 import org.junit.Before;
+import org.junit.ClassRule;
 import org.junit.Rule;
 import org.junit.runners.Parameterized;
 import org.junit.runners.Parameterized.Parameters;
@@ -67,6 +69,10 @@
         mLayoutId = layoutId;
     }
 
+    @ClassRule
+    public static final SettingsStateKeeperRule mServiceSettingsKeeper = new SettingsStateKeeperRule(
+            InstrumentationRegistry.getTargetContext(), Settings.Secure.AUTOFILL_SERVICE);
+
     @Rule
     public ActivityTestRule<StubActivity> mActivityRule =
             new ActivityTestRule<StubActivity>(StubActivity.class);
@@ -97,11 +103,6 @@
         MyAutofillService.resetStaticState();
     }
 
-    @After
-    public void cleanup() {
-        resetService();
-    }
-
     /**
      * This is the baseline test for focusing the 2 views when autofill is disabled.
      */
@@ -109,7 +110,7 @@
     public void testFocus_noService() throws Throwable {
         resetService();
 
-        focusTest();
+        focusTest(false);
     }
 
     /**
@@ -121,13 +122,7 @@
         MyAutofillService.newCannedResponse().reply();
         setService();
 
-        // Must first focus in a field to trigger autofill and wait for service response
-        // outside the loop
-        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
-        MyAutofillService.getLastFillRequest();
-
-        // Test properly speaking
-        focusTest();
+        focusTest(true);
 
         // Sanity check
         MyAutofillService.assertNoAsyncErrors();
@@ -144,13 +139,7 @@
                 .reply();
         setService();
 
-        // Must first focus in a field to trigger autofill and wait for service response
-        // outside the loop
-        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
-        MyAutofillService.getLastFillRequest();
-
-        // Test properly speaking
-        focusTest();
+        focusTest(true);
 
         // Sanity check
         MyAutofillService.assertNoAsyncErrors();
@@ -168,18 +157,19 @@
                 .reply();
         setService();
 
-        // Must first focus in a field to trigger autofill and wait for service response
-        // outside the loop
-        mActivityRule.runOnUiThread(() -> mUsername.requestFocus());
-        MyAutofillService.getLastFillRequest();
-
-        focusTest();
+        focusTest(true);
 
         // Sanity check
         MyAutofillService.assertNoAsyncErrors();
     }
 
-    private void focusTest() throws Throwable {
+    private void focusTest(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(() -> {
             BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
             while (state.keepRunning()) {
@@ -189,7 +179,84 @@
         });
     }
 
-    // TODO: add tests for changing value of the fields
+    /**
+     * 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
+        MyAutofillService.assertNoAsyncErrors();
+    }
+
+    /**
+     * 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(() -> {
+
+            BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+            while (state.keepRunning()) {
+                mUsername.setText("");
+                mUsername.setText("a");
+                mPassword.setText("");
+                mPassword.setText("x");
+            }
+        });
+    }
 
     /**
      * Uses the {@code settings} binary to set the autofill service.
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/SettingsStateKeeperRule.java b/apct-tests/perftests/utils/src/android/perftests/utils/SettingsStateKeeperRule.java
new file mode 100644
index 0000000..a8e2fdf
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/SettingsStateKeeperRule.java
@@ -0,0 +1,39 @@
+/*
+ * 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));
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/SettingsStateManager.java b/apct-tests/perftests/utils/src/android/perftests/utils/SettingsStateManager.java
new file mode 100644
index 0000000..13ad66a
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/SettingsStateManager.java
@@ -0,0 +1,63 @@
+/*
+ * 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 + "]";
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/StateKeeperRule.java b/apct-tests/perftests/utils/src/android/perftests/utils/StateKeeperRule.java
new file mode 100644
index 0000000..1bb09b2
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/StateKeeperRule.java
@@ -0,0 +1,63 @@
+/*
+ * 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);
+                    }
+                }
+            }
+        };
+    }
+}
diff --git a/apct-tests/perftests/utils/src/android/perftests/utils/StateManager.java b/apct-tests/perftests/utils/src/android/perftests/utils/StateManager.java
new file mode 100644
index 0000000..5fc499a
--- /dev/null
+++ b/apct-tests/perftests/utils/src/android/perftests/utils/StateManager.java
@@ -0,0 +1,34 @@
+/*
+ * 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();
+}