165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/*
265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Copyright (C) 2014 The Android Open Source Project
365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *
465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Licensed under the Apache License, Version 2.0 (the "License");
565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * you may not use this file except in compliance with the License.
665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * You may obtain a copy of the License at
765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *
865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *      http://www.apache.org/licenses/LICENSE-2.0
965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane *
1065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Unless required by applicable law or agreed to in writing, software
1165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * distributed under the License is distributed on an "AS IS" BASIS,
1265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * See the License for the specific language governing permissions and
1465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * limitations under the License.
1565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */
1665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
1765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepackage com.android.tv.settings.form;
1865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
1965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.Action;
2065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.ActionAdapter;
2165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.ActionFragment;
2265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.ContentFragment;
2365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.DialogActivity;
2465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport com.android.tv.settings.dialog.old.EditTextFragment;
2565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
2665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.app.Fragment;
2765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.content.Intent;
2865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.os.Bundle;
2965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.util.Log;
3065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.view.KeyEvent;
3165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport android.widget.TextView;
3265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
3365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.ArrayList;
3465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Laneimport java.util.Stack;
3565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
3665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane/**
3765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * Implements a MultiPagedForm.
3865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * <p>
3965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * This is a multi-paged form that can be used for fragment transitions used in
4065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane * such as setup, add network, and add credit cards
4165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane */
4265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lanepublic abstract class MultiPagedForm extends DialogActivity implements ActionAdapter.Listener,
4365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    FormPageResultListener, FormResultListener {
4465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
4565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final int INTENT_FORM_PAGE_DATA_REQUEST = 1;
4665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private static final String TAG = "MultiPagedForm";
4765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
4865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private enum Key {
4965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        DONE, CANCEL
5065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
5165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
5265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected final ArrayList<FormPage> mFormPages = new ArrayList<FormPage>();
5365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private final Stack<Object> mFlowStack = new Stack<Object>();
5465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private ActionAdapter.Listener mListener = null;
5565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
5665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
5765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onActionClicked(Action action) {
5865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (mListener != null) {
5965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            mListener.onActionClicked(action);
6065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
6165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
6265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
6365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
6465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onBackPressed() {
6565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
6665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // If we don't have a page to go back to, finish as cancelled.
6765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (mFlowStack.size() < 1) {
6865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            setResult(RESULT_CANCELED);
6965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            finish();
7065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return;
7165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
7265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Pop the current location off the stack.
7465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mFlowStack.pop();
7565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Peek at the previous location on the stack.
7765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Object lastLocation = mFlowStack.isEmpty() ? null : mFlowStack.peek();
7865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
7965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (lastLocation instanceof FormPage && !mFormPages.contains(lastLocation)) {
8065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            onBackPressed();
8165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } else {
8265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            displayCurrentStep(false);
8365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (mFlowStack.isEmpty()) {
8465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                setResult(RESULT_CANCELED);
8565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                finish();
8665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
8765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
8865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
8965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
9065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
9165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onBundlePageResult(FormPage page, Bundle bundleResults) {
9265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Complete the form with the results.
9365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        page.complete(bundleResults);
9465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
9565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Indicate that we've completed a page. If we get back false it means
9665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // the data was invalid and the page must be filled out again.
9765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // Otherwise, we move on to the next page.
9865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (!onPageComplete(page)) {
9965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            displayCurrentStep(false);
10065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } else {
10165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            performNextStep();
10265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
10365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
10465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
10565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
10665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onFormComplete() {
10765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        onComplete(mFormPages);
10865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
10965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
11065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
11165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    public void onFormCancelled() {
11265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        onCancel(mFormPages);
11365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
11465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
11565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
11665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void onCreate(Bundle savedInstanceState) {
11765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        performNextStep();
11865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        super.onCreate(savedInstanceState);
11965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
12065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
12165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    @Override
12265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
12365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (requestCode == INTENT_FORM_PAGE_DATA_REQUEST) {
12465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (resultCode == RESULT_OK) {
12565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                Object currentLocation = mFlowStack.peek();
12665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (currentLocation instanceof FormPage) {
12765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    FormPage page = (FormPage) currentLocation;
12865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    Bundle results = data == null ? null : data.getExtras();
12965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    if (data == null) {
13065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        Log.w(TAG, "Intent result was null!");
13165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    } else if (results == null) {
13265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        Log.w(TAG, "Intent result extras were null!");
13365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    } else if (!results.containsKey(FormPage.DATA_KEY_SUMMARY_STRING)) {
13465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        Log.w(TAG, "Intent result extras didn't have the result summary key!");
13565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    }
13665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    onBundlePageResult(page, results);
13765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                } else {
13865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    Log.e(TAG, "Our current location wasn't on the top of the stack!");
13965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
14065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            } else {
14165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                onBackPressed();
14265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
14365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
14465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
14565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
14665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
14765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Called when a form page completes. If necessary, add or remove any pages
14865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * from the form before this call completes. If all pages are complete when
14965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * onPageComplete returns, the form will be considered finished and the form
15065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * results will be displayed for confirmation.
15165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
15265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage the page that was completed.
15365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return true if the form can continue to the next incomplete page, or
15465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *         false if the data input is invalid and the form page must be
15565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *         completed again.
15665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
15765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected abstract boolean onPageComplete(FormPage formPage);
15865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
15965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
16065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Called when all form pages have been completed and the user has accepted
16165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * them.
16265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
16365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPages the pages that were completed. Any pages removed during
16465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *            the completion of the form are not included.
16565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
16665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected abstract void onComplete(ArrayList<FormPage> formPages);
16765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
16865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
16965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Called when all form pages have been completed but the user wants to
17065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * cancel the form and discard the results.
17165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
17265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPages the pages that were completed. Any pages removed during
17365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *            the completion of the form are not included.
17465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
17565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected abstract void onCancel(ArrayList<FormPage> formPages);
17665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
17765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
17865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to fully customize the display of the page.
17965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
18065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage the page that should be displayed.
18165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param listener the listener to notify when the page is complete.
18265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
18365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void displayPage(FormPage formPage, FormPageResultListener listener,
18465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            boolean forward) {
18565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        switch (formPage.getType()) {
18665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case PASSWORD_INPUT:
18765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                setContentAndActionFragments(getContentFragment(formPage),
18865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        createPasswordEditTextFragment(formPage));
18965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
19065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case TEXT_INPUT:
19165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                setContentAndActionFragments(getContentFragment(formPage),
19265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        createEditTextFragment(formPage));
19365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
19465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case MULTIPLE_CHOICE:
19565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                setContentAndActionFragments(getContentFragment(formPage),
19665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        createActionFragment(formPage));
19765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
19865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            case INTENT:
19965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            default:
20065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
20165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
20265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
20365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
20465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
20565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to fully customize the display of the form results.
20665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
20765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPages the pages that were whose results should be displayed.
20865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param listener the listener to notify when the form is complete or has been cancelled.
20965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
21065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void displayFormResults(ArrayList<FormPage> formPages, FormResultListener listener) {
21165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        setContentAndActionFragments(createResultContentFragment(),
21265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                createResultActionFragment(formPages, listener));
21365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
21465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
21565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
21665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return the main title for this multipage form.
21765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
21865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected String getMainTitle() {
21965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return "";
22065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
22165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
22265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
22365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return the action title to indicate the form is correct.
22465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
22565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected String getFormIsCorrectActionTitle() {
22665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return "";
22765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
22865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
22965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
23065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return the action title to indicate the form should be canceled and its
23165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *         results discarded.
23265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
23365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected String getFormCancelActionTitle() {
23465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return "";
23565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
23665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
23765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
23865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to provide a custom Fragment for displaying the content
23965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * portion of the page.
24065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
24165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage the page the Fragment should display.
24265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return a Fragment for identifying the current step.
24365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
24465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected Fragment getContentFragment(FormPage formPage) {
24565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return ContentFragment.newInstance(formPage.getTitle());
24665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
24765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
24865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
24965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to provide a custom Fragment for displaying the content
25065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * portion of the form results.
25165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
25265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return a Fragment for giving context to the result page.
25365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
25465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected Fragment getResultContentFragment() {
25565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return ContentFragment.newInstance(getMainTitle());
25665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
25765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
25865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
25965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to provide a custom EditTextFragment for displaying a form
26065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * page for password input. Warning: the OnEditorActionListener of this
26165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * fragment will be overridden.
26265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
26365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param initialText initial text that should be displayed in the edit
26465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *            field.
26565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return an EditTextFragment for password input.
26665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
26765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected EditTextFragment getPasswordEditTextFragment(String initialText) {
26865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return EditTextFragment.newInstance(null, initialText, true /* password */);
26965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
27065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
27165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
27265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to provide a custom EditTextFragment for displaying a form
27365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * page for text input. Warning: the OnEditorActionListener of this fragment
27465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * will be overridden.
27565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
27665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param initialText initial text that should be displayed in the edit
27765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *            field.
27865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return an EditTextFragment for custom input.
27965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
28065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected EditTextFragment getEditTextFragment(String initialText) {
28165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return EditTextFragment.newInstance(null, initialText);
28265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
28365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
28465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
28565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to provide a custom ActionFragment for displaying a form
28665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * page for a list of choices.
28765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
28865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage the page the ActionFragment is for.
28965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param actions the actions the ActionFragment should display.
29065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param selectedAction the action in actions that is currently selected,
29165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *            or null if none are selected.
29265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return an ActionFragment displaying the given actions.
29365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
29465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected ActionFragment getActionFragment(FormPage formPage, ArrayList<Action> actions,
29565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            Action selectedAction) {
29665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ActionFragment actionFragment = ActionFragment.newInstance(actions);
29765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (selectedAction != null) {
29865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            int indexOfSelection = actions.indexOf(selectedAction);
29965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (indexOfSelection >= 0) {
30065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                // TODO: Set initial focus action:
30165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                // actionFragment.setSelection(indexOfSelection);
30265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
30365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
30465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return actionFragment;
30565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
30665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
30765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
30865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Override this to provide a custom ActionFragment for displaying the list
30965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * of page results.
31065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
31165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param actions the actions the ActionFragment should display.
31265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @return an ActionFragment displaying the given form results.
31365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
31465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected ActionFragment getResultActionFragment(ArrayList<Action> actions) {
31565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return ActionFragment.newInstance(actions);
31665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
31765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
31865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
31965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Adds the page to the end of the form. Only call this before onCreate or
32065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * during onPageComplete.
32165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
32265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage the page to add to the end of the form.
32365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
32465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void addPage(FormPage formPage) {
32565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mFormPages.add(formPage);
32665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
32765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
32865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
32965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Removes the page from the form. Only call this before onCreate or during
33065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * onPageComplete.
33165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
33265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage the page to remove from the form.
33365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
33465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void removePage(FormPage formPage) {
33565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mFormPages.remove(formPage);
33665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
33765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
33865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
33965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Clears all pages from the form. Only call this before onCreate or during
34065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * onPageComplete.
34165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
34265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void clear() {
34365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mFormPages.clear();
34465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
34565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
34665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
34765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Clears all pages after the given page from the form. Only call this
34865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * before onCreate or during onPageComplete.
34965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *
35065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * @param formPage all pages after this page in the form will be removed
35165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     *            from the form.
35265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
35365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void clearAfter(FormPage formPage) {
35465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        int indexOfPage = mFormPages.indexOf(formPage);
35565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (indexOfPage >= 0) {
35665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            for (int i = mFormPages.size() - 1; i > indexOfPage; i--) {
35765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                mFormPages.remove(i);
35865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
35965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
36065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
36165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
36265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    /**
36365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * Stop display the currently displayed page. Note that this does <b>not</b>
36465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * remove the form page from the set of form pages for this form, it is just
36565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * no longer displayed and no replacement is provided, the screen should be
36665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     * empty after this method.
36765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane     */
36865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    protected void undisplayCurrentPage() {
36965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
37065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
37165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void performNextStep() {
37265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
37365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // First see if there are any incomplete form pages.
37465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        FormPage nextIncompleteStep = findNextIncompleteStep();
37565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
37665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        // If all the pages we have are complete, display the results.
37765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (nextIncompleteStep == null) {
37865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            mFlowStack.push(this);
37965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } else {
38065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            mFlowStack.push(nextIncompleteStep);
38165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
38265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        displayCurrentStep(true);
38365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
38465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
38565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private FormPage findNextIncompleteStep() {
38665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        for (int i = 0, size = mFormPages.size(); i < size; i++) {
38765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            FormPage formPage = mFormPages.get(i);
38865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (!formPage.isComplete()) {
38965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                return formPage;
39065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
39165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
39265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return null;
39365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
39465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
39565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void displayCurrentStep(boolean forward) {
39665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
39765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        if (!mFlowStack.isEmpty()) {
39865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            Object currentLocation = mFlowStack.peek();
39965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
40065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (currentLocation instanceof MultiPagedForm) {
40165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                displayFormResults(mFormPages, this);
40265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            } else if (currentLocation instanceof FormPage) {
40365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                FormPage page = (FormPage) currentLocation;
40465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (page.getType() == FormPage.Type.INTENT) {
40565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    startActivityForResult(page.getIntent(), INTENT_FORM_PAGE_DATA_REQUEST);
40665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
40765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                displayPage(page, this, forward);
40865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            } else {
40965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                Log.d("JMATT", "Finishing from here!");
41065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                // If this is an unexpected type, something went wrong, finish as
41165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                // cancelled.
41265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                setResult(RESULT_CANCELED);
41365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                finish();
41465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
41565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } else {
41665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            undisplayCurrentPage();
41765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
41865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
41965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
42065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
42165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Fragment createResultContentFragment() {
42265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return getResultContentFragment();
42365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
42465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
42565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Fragment createResultActionFragment(final ArrayList<FormPage> formPages,
42665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            final FormResultListener listener) {
42765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
42865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mListener = new ActionAdapter.Listener() {
42965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
43065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            @Override
43165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            public void onActionClicked(Action action) {
43265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                Key key = getKeyFromKey(action.getKey());
43365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                if (key != null) {
43465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    switch (key) {
43565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        case DONE:
43665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            listener.onFormComplete();
43765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            break;
43865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        case CANCEL:
43965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            listener.onFormCancelled();
44065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            break;
44165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        default:
44265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            break;
44365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    }
44465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                } else {
44565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    String formPageKey = action.getKey();
44665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    for (int i = 0, size = formPages.size(); i < size; i++) {
44765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        FormPage formPage = formPages.get(i);
44865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        if (formPageKey.equals(formPage.getTitle())) {
44965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            mFlowStack.push(formPage);
45065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            displayCurrentStep(true);
45165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                            break;
45265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                        }
45365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    }
45465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                }
45565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
45665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        };
45765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
45865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return getResultActionFragment(getResultActions());
45965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
46065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
46165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Key getKeyFromKey(String key) {
46265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        try {
46365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return Key.valueOf(key);
46465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        } catch (IllegalArgumentException iae) {
46565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            return null;
46665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
46765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
46865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
46965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private ArrayList<Action> getActions(FormPage formPage) {
47065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ArrayList<Action> actions = new ArrayList<Action>();
47165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        for (String choice : formPage.getChoices()) {
47265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            actions.add(new Action.Builder().key(choice).title(choice).build());
47365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
47465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return actions;
47565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
47665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
47765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private ArrayList<Action> getResultActions() {
47865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ArrayList<Action> actions = new ArrayList<Action>();
47965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        for (int i = 0, size = mFormPages.size(); i < size; i++) {
48065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            FormPage formPage = mFormPages.get(i);
48165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            actions.add(new Action.Builder().key(formPage.getTitle())
48265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                    .title(formPage.getDataSummary()).description(formPage.getTitle()).build());
48365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
48465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        actions.add(new Action.Builder().key(Key.CANCEL.name())
48565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                .title(getFormCancelActionTitle()).build());
48665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        actions.add(new Action.Builder().key(Key.DONE.name())
48765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                .title(getFormIsCorrectActionTitle()).build());
48865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return actions;
48965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
49065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
49165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Fragment createActionFragment(final FormPage formPage) {
49265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        mListener = new ActionAdapter.Listener() {
49365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
49465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            @Override
49565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            public void onActionClicked(Action action) {
49665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                handleStringPageResult(formPage, action.getKey());
49765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
49865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        };
49965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
50065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        ArrayList<Action> actions = getActions(formPage);
50165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
50265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Action selectedAction = null;
50365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        String choice = formPage.getDataSummary();
50465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        for (int i = 0, size = actions.size(); i < size; i++) {
50565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            Action action = actions.get(i);
50665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            if (action.getKey().equals(choice)) {
50765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                selectedAction = action;
50865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                break;
50965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
51065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        }
51165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
51265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return getActionFragment(formPage, actions, selectedAction);
51365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
51465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
51565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Fragment createPasswordEditTextFragment(final FormPage formPage) {
51665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        EditTextFragment editTextFragment = getPasswordEditTextFragment(formPage.getDataSummary());
51765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        attachListeners(editTextFragment, formPage);
51865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return editTextFragment;
51965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
52065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
52165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private Fragment createEditTextFragment(final FormPage formPage) {
52265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        EditTextFragment editTextFragment = getEditTextFragment(formPage.getDataSummary());
52365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        attachListeners(editTextFragment, formPage);
52465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        return editTextFragment;
52565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
52665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
52765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void attachListeners(EditTextFragment editTextFragment, final FormPage formPage) {
52865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
52965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        editTextFragment.setOnEditorActionListener(new TextView.OnEditorActionListener() {
53065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
53165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            @Override
53265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
53365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                handleStringPageResult(formPage, v.getText().toString());
53465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane                return true;
53565a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane            }
53665a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        });
53765a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
53865a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane
53965a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    private void handleStringPageResult(FormPage page, String stringResults) {
54065a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        Bundle bundleResults = new Bundle();
54165a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        bundleResults.putString(FormPage.DATA_KEY_SUMMARY_STRING, stringResults);
54265a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane        onBundlePageResult(page, bundleResults);
54365a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane    }
54465a5a7d84ad9b5324ae53eda526e39e513473af7Christopher Lane}
545