blob: 2d764bc8219c9a47ab0d46697a0e7678bae132ce [file] [log] [blame]
/*
* 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.autofillservice.cts.saveui;
import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_INPUT;
import static android.autofillservice.cts.activities.SimpleSaveActivity.ID_PASSWORD;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_HIDE;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_PASSWORD_MASKED;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_PASSWORD_PLAIN;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_SHOW;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_USERNAME_MASKED;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.ID_USERNAME_PLAIN;
import static android.autofillservice.cts.testcore.CustomDescriptionHelper.newCustomDescriptionWithHiddenFields;
import static android.autofillservice.cts.testcore.Helper.ID_PASSWORD_LABEL;
import static android.autofillservice.cts.testcore.Helper.ID_USERNAME_LABEL;
import static android.autofillservice.cts.testcore.Helper.assertTextAndValue;
import static android.autofillservice.cts.testcore.Helper.findAutofillIdByResourceId;
import static android.autofillservice.cts.testcore.Helper.findNodeByResourceId;
import static android.service.autofill.SaveInfo.SAVE_DATA_TYPE_GENERIC;
import android.autofillservice.cts.R;
import android.autofillservice.cts.activities.SimpleSaveActivity;
import android.autofillservice.cts.commontests.AutoFillServiceTestCase;
import android.autofillservice.cts.testcore.AutofillActivityTestRule;
import android.autofillservice.cts.testcore.CannedFillResponse;
import android.autofillservice.cts.testcore.InstrumentedAutoFillService.SaveRequest;
import android.autofillservice.cts.testcore.Timeouts;
import android.platform.test.annotations.AppModeFull;
import android.service.autofill.CharSequenceTransformation;
import android.service.autofill.FillContext;
import android.service.autofill.OnClickAction;
import android.service.autofill.VisibilitySetterAction;
import android.support.test.uiautomator.UiObject2;
import android.view.View;
import android.view.autofill.AutofillId;
import org.junit.Test;
import java.util.regex.Pattern;
/**
* Integration tests for the {@link OnClickAction} implementations.
*/
@AppModeFull(reason = "Service-specific test")
public class OnClickActionTest
extends AutoFillServiceTestCase.AutoActivityLaunch<SimpleSaveActivity> {
private static final Pattern MATCH_ALL = Pattern.compile("^(.*)$");
private SimpleSaveActivity mActivity;
@Override
protected AutofillActivityTestRule<SimpleSaveActivity> getActivityRule() {
return new AutofillActivityTestRule<SimpleSaveActivity>(SimpleSaveActivity.class) {
@Override
protected void afterActivityLaunched() {
mActivity = getActivity();
}
};
}
@Test
public void testHideAndShow() throws Exception {
// Set service.
enableService();
// Set expectations.
sReplier.addResponse(new CannedFillResponse.Builder()
.setRequiredSavableIds(SAVE_DATA_TYPE_GENERIC, ID_INPUT, ID_PASSWORD)
.setSaveInfoVisitor((contexts, builder) -> {
final FillContext context = contexts.get(0);
final AutofillId usernameId = findAutofillIdByResourceId(context, ID_INPUT);
final AutofillId passwordId = findAutofillIdByResourceId(context, ID_PASSWORD);
final CharSequenceTransformation usernameTrans = new CharSequenceTransformation
.Builder(usernameId, MATCH_ALL, "$1").build();
final CharSequenceTransformation passwordTrans = new CharSequenceTransformation
.Builder(passwordId, MATCH_ALL, "$1").build();
builder.setCustomDescription(newCustomDescriptionWithHiddenFields()
.addChild(R.id.username_plain, usernameTrans)
.addChild(R.id.password_plain, passwordTrans)
.addOnClickAction(R.id.show, new VisibilitySetterAction
.Builder(R.id.hide, View.VISIBLE)
.setVisibility(R.id.show, View.GONE)
.setVisibility(R.id.username_plain, View.VISIBLE)
.setVisibility(R.id.password_plain, View.VISIBLE)
.setVisibility(R.id.username_masked, View.GONE)
.setVisibility(R.id.password_masked, View.GONE)
.build())
.addOnClickAction(R.id.hide, new VisibilitySetterAction
.Builder(R.id.show, View.VISIBLE)
.setVisibility(R.id.hide, View.GONE)
.setVisibility(R.id.username_masked, View.VISIBLE)
.setVisibility(R.id.password_masked, View.VISIBLE)
.setVisibility(R.id.username_plain, View.GONE)
.setVisibility(R.id.password_plain, View.GONE)
.build())
.build());
})
.build());
// Trigger autofill.
mActivity.syncRunOnUiThread(() -> mActivity.mInput.requestFocus());
sReplier.getNextFillRequest();
// Trigger save.
mActivity.setTextAndWaitTextChange(/* input= */ "42", /* password= */ "108");
mActivity.syncRunOnUiThread(() -> {
mActivity.mCommit.performClick();
});
final UiObject2 saveUi = mUiBot.assertSaveShowing(SAVE_DATA_TYPE_GENERIC);
// Assert initial UI is hidden the password.
final UiObject2 showButton = assertHidden(saveUi);
// Then tap SHOW and assert it's showing how
showButton.click();
final UiObject2 hideButton = assertShown(saveUi);
// Hide again
hideButton.click();
assertHidden(saveUi);
// Rinse-and repeat a couple times
showButton.click(); assertShown(saveUi);
hideButton.click(); assertHidden(saveUi);
showButton.click(); assertShown(saveUi);
hideButton.click(); assertHidden(saveUi);
// Then save it...
mUiBot.saveForAutofill(saveUi, true);
// ... and assert results
final SaveRequest saveRequest = sReplier.getNextSaveRequest();
assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_INPUT), "42");
assertTextAndValue(findNodeByResourceId(saveRequest.structure, ID_PASSWORD), "108");
}
/**
* Asserts that the Save UI is in the hiding the password field, returning the {@code SHOW}
* button.
*/
private UiObject2 assertHidden(UiObject2 saveUi) throws Exception {
// Username
mUiBot.assertChildText(saveUi, ID_USERNAME_LABEL, "User:");
mUiBot.assertChildText(saveUi, ID_USERNAME_MASKED, "****");
assertInvisible(saveUi, ID_USERNAME_PLAIN);
// Password
mUiBot.assertChildText(saveUi, ID_PASSWORD_LABEL, "Pass:");
mUiBot.assertChildText(saveUi, ID_PASSWORD_MASKED, "....");
assertInvisible(saveUi, ID_PASSWORD_PLAIN);
// Buttons
assertInvisible(saveUi, ID_HIDE);
return mUiBot.assertChildText(saveUi, ID_SHOW, "SHOW");
}
/**
* Asserts that the Save UI is in the showing the password field, returning the {@code HIDE}
* button.
*/
private UiObject2 assertShown(UiObject2 saveUi) throws Exception {
// Username
mUiBot.assertChildText(saveUi, ID_USERNAME_LABEL, "User:");
mUiBot.assertChildText(saveUi, ID_USERNAME_PLAIN, "42");
assertInvisible(saveUi, ID_USERNAME_MASKED);
// Password
mUiBot.assertChildText(saveUi, ID_PASSWORD_LABEL, "Pass:");
mUiBot.assertChildText(saveUi, ID_PASSWORD_PLAIN, "108");
assertInvisible(saveUi, ID_PASSWORD_MASKED);
// Buttons
assertInvisible(saveUi, ID_SHOW);
return mUiBot.assertChildText(saveUi, ID_HIDE, "HIDE");
}
private void assertInvisible(UiObject2 saveUi, String resourceId) {
mUiBot.assertGoneByRelativeId(saveUi, resourceId, Timeouts.UI_TIMEOUT);
}
}