*
Its's useful to verify how an autofill service handles account creation that takes multiple * steps. */ /* * TODO list * - use ConstraintLayout * - use Fragments instead of replacing views directly * - use custom view and/or layout xml for mSteps */ abstract class AbstractMultipleStepsActivity extends AppCompatActivity { private TextView mStatus; private ViewGroup mContainer; private Button mPrev; private Button mNext; private Button mFinish; private int mCurrentStep; private boolean mFinished; private LinearLayout[] mSteps; /** * Gets the mapping from resource id to autofill hints. */ protected abstract Map getStepsMap(); @Override protected final void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.multiple_steps_activity); mStatus = findViewById(R.id.status); mContainer = findViewById(R.id.container); mPrev = findViewById(R.id.prev); mNext = findViewById(R.id.next); mFinish = findViewById(R.id.finish); View.OnClickListener onClickListener = (v) -> { if (v == mPrev) { showStep(mCurrentStep - 1); } else if (v == mNext) { showStep(mCurrentStep + 1); } else { finishIt(); } }; mPrev.setOnClickListener(onClickListener); mNext.setOnClickListener(onClickListener); mFinish.setOnClickListener(onClickListener); Map stepsMap = getStepsMap(); if (DEBUG) debug("onCreate(): steps=%s", stepsMap); initializeSteps(stepsMap); showStep(0); } private void showStep(int i) { if (mFinished || i < 0 || i >= mSteps.length) { warn("Invalid step: %d (finished=%s, range=[%d,%d])", mFinished, i, 0, mSteps.length - 1); return; } View step = mSteps[i]; mStatus.setText(getString(R.string.message_showing_step, i)); if (DEBUG) debug("Showing step %d", i); if (mContainer.getChildCount() > 0) { mContainer.removeViewAt(0); } mContainer.addView(step); mCurrentStep = i; mPrev.setEnabled(mCurrentStep != 0); mNext.setEnabled(mCurrentStep != mSteps.length - 1); } private void updateButtons() { mPrev.setEnabled(!mFinished && mCurrentStep != 0); mNext.setEnabled(!mFinished && mCurrentStep != mSteps.length - 1); mFinish.setEnabled(!mFinished); } private void finishIt() { StringBuilder message = new StringBuilder(getString(R.string.message_finished)) .append("\n\n"); for (int i = 0; i < mSteps.length; i++) { TextView label = (TextView) mSteps[i].getChildAt(0); EditText input = (EditText) mSteps[i].getChildAt(1); message.append(getString(R.string.message_step_description, label.getText(), input.getText())) .append('\n'); } mStatus.setText(message.toString()); mContainer.removeAllViews(); mFinished = true; updateButtons(); } private void initializeSteps(Map stepsMap) { mSteps = new LinearLayout[stepsMap.size()]; int i = 0; for (Map.Entry entry : stepsMap.entrySet()) { int labelId = entry.getKey(); String autofillHints = entry.getValue(); if (DEBUG) debug("step %d: %s->%s", i, getString(labelId), autofillHints); mSteps[i++] = newStep(labelId, autofillHints); } } private LinearLayout newStep(int labelId, String autofillHints) { LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.HORIZONTAL); TextView label = new TextView(this); label.setText(labelId); layout.addView(label); EditText input = new EditText(this); input.setAutofillHints(autofillHints); input.setWidth(500); // TODO: proper size layout.addView(input); return layout; } protected void debug(String fmt, Object... args) { Log.d(TAG, getLocalClassName() + "." + String.format(fmt, args)); } protected void warn(String fmt, Object... args) { Log.w(TAG, getLocalClassName() + "." + String.format(fmt, args)); } }