/* * The MIT License (MIT) * * Copyright (c) 2015 Curt Binder * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package info.curtbinder.reefangel.wizard; import android.content.Intent; import android.graphics.drawable.ColorDrawable; import android.os.Bundle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.ActionBar; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.Toolbar; import android.util.Log; import android.view.View; import android.widget.Button; import java.util.LinkedList; import info.curtbinder.reefangel.phone.MainActivity; import info.curtbinder.reefangel.phone.R; import info.curtbinder.reefangel.phone.RAApplication; import info.curtbinder.reefangel.service.MessageCommands; import info.curtbinder.reefangel.service.UpdateService; public class SetupWizardActivity extends ActionBarActivity implements View.OnClickListener { private static final String TAG = SetupWizardActivity.class.getSimpleName(); private static final int MAX_STEPS = 9; private static final int STEP_START = 0; private static final int STEP_DEVICE = 1; private static final int STEP_USERNAME = 2; private static final int STEP_RADDNS = 3; private static final int STEP_ALTDDNS = 4; private static final int STEP_IP = 5; private static final int STEP_AUTHUSER = 6; private static final int STEP_AUTHPASS = 7; // private static final int STEP_SUMMARY = 8; private NoSwipePager mWizardPager; private WizardAdapter mWizardAdapter; private Button btnNext; private Button btnPrev; private Fragment[] mSteps; private StepItem[] aStepItems; private LinkedList<Integer> stepsList; private RAApplication raApp; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); raApp = (RAApplication) getApplication(); setContentView(R.layout.activity_setup_wizard); final Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); toolbar.setTitle(R.string.titleSetupWizard); stepsList = new LinkedList<Integer>(); findViews(); createSteps(); updateNextButton(); } private void findViews() { btnNext = (Button) findViewById(R.id.btn_next); btnNext.setOnClickListener(this); btnPrev = (Button) findViewById(R.id.btn_prev); btnPrev.setOnClickListener(this); mWizardPager = (NoSwipePager) findViewById(R.id.pager); mWizardAdapter = new WizardAdapter(getSupportFragmentManager()); mWizardPager.setAdapter(mWizardAdapter); mWizardPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() { @Override public void onPageScrolled(int i, float v, int i2) { } @Override public void onPageSelected(int i) { if (i == (MAX_STEPS - 1)) { updateSummaryPageText(); } updateNextButton(); } @Override public void onPageScrollStateChanged(int i) { } }); } private void createSteps() { aStepItems = new StepItem[]{ new StepItem("", ""), new StepItem(getString(R.string.prefsCategoryDevice), getString(R.string.prefDeviceKey)), new StepItem(getString(R.string.labelPortalUsername), getString(R.string.prefUserIdKey)), new StepItem(getString(R.string.prefHostAwayTitle), getString(R.string.prefHostAwayKey)), new StepItem(getString(R.string.prefHostAwayTitle), getString(R.string.prefHostAwayKey)), new StepItem(getString(R.string.prefHostTitle), getString(R.string.prefHostKey)), new StepItem(getString(R.string.labelDeviceUsername), getString(R.string.prefWifiUserKey)), new StepItem(getString(R.string.labelDevicePassword), getString(R.string.prefWifiPasswordKey)), new StepItem(getString(R.string.labelSummary), ""), }; mSteps = new Fragment[]{ createMainStep(), createDeviceStep(), createUsernameStep(), createRADDNSStep(), createAltDDNSStep(), createDirectIpStep(), createDeviceAuthUsername(), createDeviceAuthPassword(), createSummaryStep(), }; } private Fragment createMainStep() { return StepTextFragment.newInstance(getString(R.string.descriptionWizardMainStep)); } private Fragment createDeviceStep() { StepTwoChoiceFragment f = StepTwoChoiceFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardDeviceStep)); f.setYesDescription(getString(R.string.prefsCategoryController)); f.setNoDescription(getString(R.string.prefsCategoryPortal)); f.setValueHidden(true); return f; } private Fragment createUsernameStep() { StepSingleInputFragment f = StepSingleInputFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardUsernameStep)); f.setHint(getString(R.string.prefUserIdDefault)); return f; } private Fragment createRADDNSStep() { StepTwoChoiceFragment f = StepTwoChoiceFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardRADNSStep)); f.setYesHint(getString(R.string.prefProfileHomeTitle)); return f; } private Fragment createAltDDNSStep() { StepTwoChoiceFragment f = StepTwoChoiceFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardDNSStep)); f.setYesHint(getString(R.string.labelExampleDNS)); return f; } private Fragment createDirectIpStep() { StepTwoChoiceFragment f = StepTwoChoiceFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardIPStep)); f.setYesHint(getString(R.string.prefHostHomeDefault)); f.setValueNumeric(); return f; } private Fragment createDeviceAuthUsername() { StepTwoChoiceFragment f = StepTwoChoiceFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardAuthUsernameStep)); f.setYesHint(getString(R.string.labelUsername)); return f; } private Fragment createDeviceAuthPassword() { StepSingleInputFragment f = StepSingleInputFragment.newInstance(); f.setStepDescription(getString(R.string.descriptionWizardAuthPasswordStep)); f.setHint(getString(R.string.labelPassword)); f.setValueRequired(true); return f; } private Fragment createSummaryStep() { return StepSummaryFragment.newInstance(); } public void updateNextButton() { StepBase step = (StepBase) mWizardAdapter.getItem(mWizardPager.getCurrentItem()); boolean fEnabled = step.isNextEnabled(); btnNext.setEnabled(fEnabled); } private void updateSummaryPageText() { // Final / Summary Step // update the description of the summary page based on the steps taken int size = stepsList.size() - 1; StepSummaryFragment step = (StepSummaryFragment) mWizardAdapter.getItem(8); // skip the first step when displaying the summary String summaryText, title; boolean fNoHostProvided = true; for (int i = size - 1; i >= 0; i--) { Integer v = stepsList.get(i); summaryText = aStepItems[v].getSummaryText(); if (summaryText.length() == 0) { summaryText = aStepItems[v].getValue(); } // skip displaying the step if the value is empty if (!(summaryText.length() == 0)) { title = aStepItems[v].getTitle(); if (title.compareTo(getString(R.string.prefHostTitle)) == 0) { // if we have a home_host, then we are good fNoHostProvided = false; } step.updateSummary(title, summaryText); } } // assume the host is not missing to accommodate for the portal boolean fHostMissing = false; if (fNoHostProvided && !isDevicePortal()) { // no host was provided, we need to display something in the summary // AND we are not communicating with the portal step.updateSummary(getString(R.string.prefHostTitle), getString(R.string.labelMissing)); fHostMissing = true; } step.setHostMissing(fHostMissing); step.updateDownloadButton(isUsernameGiven()); } @Override public void onClick(View v) { int id = v.getId(); switch (id) { case R.id.btn_next: navigate(true); break; case R.id.btn_prev: navigate(false); break; } } private void navigate(boolean fForward) { int position = mWizardPager.getCurrentItem(); updateValues(position); if (fForward) { if (isLastStep(position)) { saveValues(); finishAndLaunch(); } else { moveStep(getNextStep(position)); } } else { if (isFirstStep(position)) { // If the user is currently looking at the first step, allow the system to handle the // Back button. This calls finish() on this activity and pops the back stack. super.onBackPressed(); } else { // Otherwise, select the previous step. moveStep(getPreviousStep()); } } } private void updateValues(int position) { StepBase step = (StepBase) mWizardAdapter.getItem(position); aStepItems[position].setValue(step.getValue()); aStepItems[position].setOptionSelected(step.getOption()); } private void saveValues() { int size = stepsList.size() - 1; // skip the first step, which is the summary step // set the Device, since the value is empty / not set String sValue = "0"; // Controller if (isDevicePortal()) { sValue = "1"; // Portal } raApp.raprefs.set(aStepItems[1].getPreferenceKey(), sValue); for (int i = size - 1; i >= 0; i--) { Integer v = stepsList.get(i); // store it if we have a value if (!(aStepItems[v].getValue().length() == 0)) { String value = aStepItems[v].getValue(); // If we are on the RA DynDNS step, we need to compute the hostname // based on the given values if (v == STEP_RADDNS) { value = getRADynDNSHostname(); } // otherwise, if it's an Alternate DynDNS host, just use the value entered raApp.raprefs.set(aStepItems[v].getPreferenceKey(), value); } } if (isDownloadLabelsChecked()) { Intent i = new Intent(this, UpdateService.class); i.setAction(MessageCommands.LABEL_QUERY_INTENT); startService(i); } } private void finishAndLaunch() { raApp.raprefs.disableFirstRun(); Intent i = new Intent(this, MainActivity.class); i.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); startActivity(i); finish(); } private void moveStep(int newPosition) { // scroll to the new page mWizardPager.setCurrentItem(newPosition); // after the page is scrolled, see onPageSelected, the next button is updated // update the navigation buttons textual display updateButtons(newPosition); } private void updateButtons(int newPosition) { // update the buttons if (isLastStep(newPosition)) { btnNext.setText(R.string.buttonFinish); } else { btnNext.setText(R.string.buttonNext); } if (isFirstStep(newPosition)) { btnPrev.setText(R.string.buttonExit); } else { btnPrev.setText(R.string.buttonPrevious); } } private boolean isFirstStep(int position) { return (position == STEP_START); } private boolean isLastStep(int position) { return (position == (MAX_STEPS - 1)); } private int getNextStep(int currentPosition) { // determine the next position based on the current position // grab the previous page from the stack for use later Integer previous = stepsList.peek(); // push the current position onto the stack stepsList.addFirst(currentPosition); int newPosition = currentPosition + 1; switch (currentPosition) { default: break; // case 0: Start step case STEP_DEVICE: // Device Step // Update the Username step to be required if Portal is chosen // or not required if the Controller is chosen StepSingleInputFragment step = (StepSingleInputFragment) mWizardAdapter.getItem(STEP_USERNAME); step.setValueRequired(isDevicePortal()); break; case STEP_USERNAME: // Username step // if Portal was chosen, then we jump straight to the end // if Controller was chosen, we proceed based on the value given at this step // Controller value is 1, Portal value is 0 if (isDevicePortal()) { // Portal chosen, jump to the end newPosition = MAX_STEPS - 1; // set the summary text for the device to be Portal aStepItems[STEP_DEVICE].setSummaryText(getString(R.string.prefsCategoryPortal)); } else { // Controller chosen, check if the username was given // set the summary text for the device to be Controller aStepItems[STEP_DEVICE].setSummaryText(getString(R.string.prefsCategoryController)); if (isUsernameGiven()) { // Username was provided, so proceed to next step newPosition = STEP_RADDNS; } else { // No username given, so skip over the next step newPosition = STEP_ALTDDNS; } } break; case STEP_RADDNS: // RA Dynamic DNS step // if they are using the RA DDNS step, we can skip the next step which // asks if they are using an alternate DDNS if (aStepItems[STEP_RADDNS].getValue().length() == 0) { // Not using RA Dynamic DNS, so proceed to next step newPosition = STEP_ALTDDNS; } else { // Using RA Dynamic DNS, so skip the next step and goto the IP step // Update the summary text to contain the full hostname // host is: username-subdomain.myreefangel.com aStepItems[STEP_RADDNS].setSummaryText(getRADynDNSHostname()); newPosition = STEP_IP; } break; // case STEP_ALTDDNS: Alternate DDNS step case STEP_IP: // IP Address step if (aStepItems[STEP_IP].getValue().length() == 0) { // user did not provide an IP address for the controller // we need to assume that one of the Dynamic DNS hosts was provided // look at previous step and set that title and preference key to be Home aStepItems[previous].setTitle(getString(R.string.prefHostTitle)); aStepItems[previous].setPreferenceKey(getString(R.string.prefHostKey)); } else { // otherwise, the user provided an IP address and we need to set the // Dynamic DNS host as the Away host aStepItems[previous].setTitle(getString(R.string.prefHostAwayTitle)); aStepItems[previous].setPreferenceKey(getString(R.string.prefHostAwayKey)); } break; case STEP_AUTHUSER: // Wifi Authentication Username step // if a username was entered, then we proceed to the next step and ask for // the password // otherwise, if no username given, we skip the password step and jump to the end if (aStepItems[STEP_AUTHUSER].getValue().length() == 0) { newPosition = MAX_STEPS - 1; } else { newPosition = STEP_AUTHPASS; } break; // case STEP_AUTHPASS: Wifi Authentication Password step } Log.d(TAG, "next: " + newPosition); return newPosition; } private int getPreviousStep() { // The previous step is simply stored in the stack. // pop the previous pages off of the stack Integer newPos = stepsList.removeFirst(); Log.d(TAG, "prev: " + newPos.toString()); return newPos; } private String getRADynDNSHostname() { // Gets the full dynamic dns hostname based on the user's values entered // host is: username-subdomain.myreefangel.com return aStepItems[STEP_USERNAME].getValue() + "-" + aStepItems[STEP_RADDNS].getValue() + getString(R.string.labelMyReefangelDomain); } private boolean isUsernameGiven() { return !(aStepItems[STEP_USERNAME].getValue().length() == 0); } private boolean isDevicePortal() { return (aStepItems[STEP_DEVICE].getOptionSelected() == 0); } private boolean isDownloadLabelsChecked() { StepSummaryFragment step = (StepSummaryFragment) mWizardAdapter.getItem(MAX_STEPS - 1); return step.isDownloadLabelsChecked(); } @Override public void onBackPressed() { navigate(false); } private class WizardAdapter extends FragmentStatePagerAdapter { public WizardAdapter(FragmentManager fm) { super(fm); } @Override public Fragment getItem(int i) { return mSteps[i]; } @Override public int getCount() { return MAX_STEPS; } @Override public int getItemPosition(Object object) { return POSITION_NONE; } } }