blob: 65deff568fa78e082557103ba4a43f5fc8e0004a [file] [log] [blame]
/*
* Copyright (C) 2017 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;
import android.os.Bundle;
import android.util.Log;
import android.view.autofill.AutofillManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.GridLayout;
import java.util.ArrayList;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
/**
* Activity that contains a 4x4 grid of cells (named {@code l1c1} to {@code l4c2}) plus
* {@code save} and {@code clear} buttons.
*/
public class GridActivity extends AbstractAutoFillActivity {
private static final String TAG = "GridActivity";
private static final int N_ROWS = 4;
private static final int N_COLS = 2;
public static final String ID_L1C1 = getResourceId(1, 1);
public static final String ID_L1C2 = getResourceId(1, 2);
public static final String ID_L2C1 = getResourceId(2, 1);
public static final String ID_L2C2 = getResourceId(2, 2);
public static final String ID_L3C1 = getResourceId(3, 1);
public static final String ID_L3C2 = getResourceId(3, 2);
public static final String ID_L4C1 = getResourceId(4, 1);
public static final String ID_L4C2 = getResourceId(4, 2);
private GridLayout mGrid;
private final EditText[][] mCells = new EditText[4][2];
private Button mSaveButton;
private Button mClearButton;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.grid_activity);
mGrid = findViewById(R.id.grid);
mCells[0][0] = findViewById(R.id.l1c1);
mCells[0][1] = findViewById(R.id.l1c2);
mCells[1][0] = findViewById(R.id.l2c1);
mCells[1][1] = findViewById(R.id.l2c2);
mCells[2][0] = findViewById(R.id.l3c1);
mCells[2][1] = findViewById(R.id.l3c2);
mCells[3][0] = findViewById(R.id.l4c1);
mCells[3][1] = findViewById(R.id.l4c2);
mSaveButton = findViewById(R.id.save);
mClearButton = findViewById(R.id.clear);
mSaveButton.setOnClickListener((v) -> save());
mClearButton.setOnClickListener((v) -> resetFields());
}
void save() {
getSystemService(AutofillManager.class).commit();
}
void resetFields() {
for (int i = 0; i < N_ROWS; i++) {
for (int j = 0; j < N_COLS; j++) {
mCells[i][j].setText("");
}
}
getSystemService(AutofillManager.class).cancel();
}
EditText getCell(int row, int column) {
return mCells[row - 1][column - 1];
}
public static String getResourceId(int line, int col) {
return "l" + line + "c" + col;
}
public void onCell(int row, int column, Visitor<EditText> v) {
final EditText cell = getCell(row, column);
syncRunOnUiThread(() -> v.visit(cell));
}
public void focusCell(int row, int column) {
onCell(row, column, EditText::requestFocus);
}
public void clearCell(int row, int column) {
onCell(row, column, (c) -> c.setText(""));
}
public void setText(int row, int column, String text) {
onCell(row, column, (c) -> c.setText(text));
}
public void forceAutofill(int row, int column) {
onCell(row, column, (c) -> getAutofillManager().requestAutofill(c));
}
public void removeCell(int row, int column) {
onCell(row, column, (c) -> mGrid.removeView(c));
}
public void addCell(int row, int column, EditText cell) {
mCells[row - 1][column - 1] = cell;
// TODO: ideally it should be added in the right place...
syncRunOnUiThread(() -> mGrid.addView(cell));
}
public void triggerAutofill(boolean manually, int row, int column) {
if (manually) {
forceAutofill(row, column);
} else {
focusCell(row, column);
}
}
public String getText(int row, int column) throws InterruptedException {
final BlockingQueue<String> queue = new LinkedBlockingQueue<>(1);
onCell(row, column, (c) -> queue.offer(c.getText().toString()));
final String text = queue.poll(100, TimeUnit.MILLISECONDS);
if (text == null) {
throw new RetryableException("text not set in 100ms");
}
return text;
}
public FillExpectation expectAutofill() {
return new FillExpectation();
}
public void dumpCells() {
final StringBuilder output = new StringBuilder("dumpCells():\n");
for (int i = 0; i < N_ROWS; i++) {
for (int j = 0; j < N_COLS; j++) {
final String id = getResourceId(i + 1, j + 1);
final String value = mCells[i][j].getText().toString();
output.append('\t').append(id).append("='").append(value).append("'\n");
}
}
Log.d(TAG, output.toString());
}
final class FillExpectation {
private final ArrayList<OneTimeTextWatcher> mWatchers = new ArrayList<>();
public FillExpectation onCell(int line, int col, String value) {
final String resourceId = getResourceId(line, col);
final EditText cell = getCell(line, col);
final OneTimeTextWatcher watcher = new OneTimeTextWatcher(resourceId, cell, value);
mWatchers.add(watcher);
cell.addTextChangedListener(watcher);
return this;
}
public void assertAutoFilled() throws Exception {
try {
for (int i = 0; i < mWatchers.size(); i++) {
final OneTimeTextWatcher watcher = mWatchers.get(i);
watcher.assertAutoFilled();
}
} catch (AssertionError | Exception e) {
dumpCells();
throw e;
}
}
}
}