private VoiceResultProcessor(Context context) {

    mContext = context;

    // Bin types, litter types and brands all pulled from cloud
    mBrands = new ArrayList<>();
    mLitterTypes = new ArrayList<>();
    mBinTypes = new ArrayList<>();
    populateBrandList();
    populateLitterTypes();
    populateBinTypes();

    ArrayList<LocalEntity> menuCommands = new ArrayList<>();
    LocalEntity brand = new LocalEntity("brand");
    brand.setName(context.getString(R.string.brand_command));
    brand.addSearchTerms(new String[] {"friends", "ground", "run", "front", "round"});
    menuCommands.add(brand);
    LocalEntity litterType = new LocalEntity("type");
    litterType.setName(mContext.getString(R.string.type_command));
    litterType.addSearchTerms(new String[] {"typ", "types", "tight", "tired"});
    menuCommands.add(litterType);
    LocalEntity bin = new LocalEntity("bin");
    bin.addSearchTerms(new String[] {"pin", "binh", "spin", "Ben", "friend", "pen", "fin"});
    menuCommands.add(bin);

    ArrayList<LocalEntity> confirmation = new ArrayList<>();
    LocalEntity confirmationTerms = new LocalEntity("yes");
    confirmationTerms.addSearchTerms(CONFIRMATION_TERMS);
    confirmation.add(confirmationTerms);

    // Populate Search objects for use in logic and UI
    menuSearch = new Search("menu", menuCommands, mContext.getString(R.string.menu_caption));
    binSearch =
        new Search(
            mContext.getString(R.string.bin_command),
            mBinTypes,
            mContext.getString(R.string.bin_caption));
    typeSearch =
        new Search(
            mContext.getString(R.string.type_command),
            mLitterTypes,
            mContext.getString(R.string.type_caption));
    brandSearch =
        new Search(
            mContext.getString(R.string.brand_command),
            mBrands,
            mContext.getString(R.string.brand_caption));
    yesNoSearch =
        new ConfirmationSearch("yesno", confirmation, mContext.getString(R.string.yes_no_caption));

    yesNoSearch.setYesTerms(YES_TERMS);
    yesNoSearch.setNoTerms(NO_TERMS);

    mActionHandler = new ActionHandler();
    mOutingManager = OutingManager.get(context);
  }
  // Deal with unexpected results
  private String processUnexpectedResult(String result) {

    String toastText = "";

    // Cancel item and start again if needed
    if (result.equals("cancel")
        || result.equals("council")
        || result.equals("Council")
        || result.equals("cancer")
        || result.equals("pencil")) {
      mOutingManager.speak("item cancelled");
      setCurrentSearch(brandSearch, result);
      mBin = null;
      mLitter = null;
      return null;
    }

    for (LocalEntity menuItem : menuSearch.getSearchObjects()) {
      if (menuItem.getSearchTerms().contains(result)) {
        setCurrentSearchByString(menuItem.getName());
        return null;
      }
    }

    if (!Search.getCurrentSearch().getName().equals("menu")) {
      toastText = "I haven't heard of " + result + ". Should I log it as other?";
      // log current item as 'other' and record the result
      yesNoSearch.setActive(true);
      yesNoSearch.setResponse(toastText);
      yesNoSearch.setPotentialOtherField(result);

      if (Search.getCurrentSearch().equals(brandSearch)) {
        mActionHandler.getCurrentAction().setActionType(Action.Type.LOG_OTHER_BRAND);
      }
      if (Search.getCurrentSearch().equals(typeSearch)) {
        mActionHandler.getCurrentAction().setActionType(Action.Type.LOG_OTHER_LITTER_TYPE);
      }
      if (Search.getCurrentSearch().equals(binSearch)) {
        mActionHandler.getCurrentAction().setActionType(Action.Type.LOG_OTHER_BIN_TYPE);
      }

      Log.d(TAG, "result at other: " + result);
      Log.d(TAG, "yesnosearch potentialotherfield set to " + yesNoSearch.getPotentialOtherField());
      Log.d(TAG, "currentSearch at unexpected result = " + Search.getCurrentSearch().getName());

      setCurrentSearch(yesNoSearch, "");
      return toastText;
    } else {
      setCurrentSearch(brandSearch, result);
      return null;
    }
  }
 public void checkForLitterBrand() {
   mActionHandler.getCurrentAction().setActionType(Action.Type.LITTER_BRAND_SEARCH);
   setCurrentSearch(yesNoSearch, "");
   yesNoSearch.setResponse(mContext.getString(R.string.confirm_log_litter_brand_caption));
   yesNoSearch.setYesAction(Action.Type.LITTER_BRAND_SEARCH);
   // If an 'other' item is being processed, then set no action to Log other type,
   // Otherwise log regular type
   if (yesNoSearch.getPotentialOtherField() != null) {
     yesNoSearch.setNoAction(Action.Type.LOG_OTHER_LITTER_TYPE);
   } else {
     yesNoSearch.setNoAction(Action.Type.LOG_LITTER_TYPE);
   }
 }
 public void logBin(Bin bin) {
   mOutingManager.logBin(bin);
   mOutingManager.speak("bin logged");
   mBin = null;
   yesNoSearch.setPotentialOtherField(null);
   setCurrentSearch(brandSearch, "");
 }
 public void logLitterItem(Litter litterItem) {
   mOutingManager.logLitter(mLitter);
   mOutingManager.speak("litter logged");
   mLitter = null;
   yesNoSearch.setPotentialOtherField(null);
   setCurrentSearch(brandSearch, "");
 }
  public void setCurrentSearch(Search newSearch, String result) {

    Action.Type actionType = null;
    yesNoSearch.setActive(true);
    yesNoSearch.setPotentialField(result);
    yesNoSearch.setResponse("Did you mean " + result + "?");
    // Set parent search for re-routing after user response
    if (Search.getCurrentSearch() != null && Search.getCurrentSearch() != yesNoSearch) {
      yesNoSearch.setParentSearch(Search.getCurrentSearch());
      Log.d(TAG, "parent search of yesNo search set to " + Search.getCurrentSearch().getName());
    }
    if (newSearch == binSearch) {
      actionType = Action.Type.LOG_BIN_ITEM;
    } else if (newSearch == typeSearch) {
      actionType = Action.Type.LOG_LITTER_TYPE;
    } else if (newSearch == brandSearch) {
      actionType = Action.Type.LOG_LITTER_BRAND;
    } else if (newSearch == yesNoSearch) {
      yesNoSearch.setYesAction(mActionHandler.getCurrentAction().getActionType());
      yesNoSearch.setNoAction(getActionFromSearch(yesNoSearch.getParentSearch()));
    }
    if (actionType != null) {
      mActionHandler.getCurrentAction().setActionType(actionType);
    }
    Search.setCurrentSearch(newSearch);
  }
  // process current active action
  public void performAction(Action.Type currentActionType, String result) {

    switch (currentActionType) {
      case LOG_LITTER_TYPE:
        populateLitterItem(yesNoSearch.getPotentialField(), null, "type");
        break;
      case LOG_OTHER_LITTER_TYPE:
        populateLitterItem("other", yesNoSearch.getPotentialOtherField(), "type");
        break;
      case LOG_LITTER_BRAND:
        populateLitterItem(yesNoSearch.getPotentialField(), null, "brand");
        break;
      case LOG_OTHER_BRAND:
        Log.d(TAG, "Logging other brand");
        populateLitterItem("other", yesNoSearch.getPotentialOtherField(), "brand");
        break;
      case LOG_BIN_ITEM:
        populateBinItem(yesNoSearch.getPotentialField(), null);
        logBin(mBin);
        setCurrentSearch(brandSearch, result);
        break;
      case LOG_OTHER_BIN_TYPE:
        populateBinItem("other", yesNoSearch.getPotentialOtherField());
        break;
      case LITTER_BRAND_SEARCH:
        setCurrentSearch(brandSearch, result);
        break;
      case LITTER_TYPE_SEARCH:
        setCurrentSearch(typeSearch, result);
        break;
      case BIN_SEARCH:
        setCurrentSearch(binSearch, result);
        break;
      case MENU_SEARCH:
        setCurrentSearch(menuSearch, result);
        break;
      default:
        Log.d(TAG, "invalid action type");
    }

    mActionHandler.setActionPerformed(true);
    Log.d(TAG, "action performed");
    Toast.makeText(mContext, "action performed", Toast.LENGTH_SHORT).show();
  }
  private void processExpectedResult(String result) {

    // If result is affirmative then assume it is in response to a confirmation question and
    // perform pending action associated with current search
    if (yesNoSearch.getYesTerms().getSearchTerms().contains(result)) {
      yesNoSearch.setActive(false);
      Log.d(TAG, "user answered yes");
      performAction(yesNoSearch.getYesAction(), result);
      return;
    }
    // If result is negative, assume it is in response to a confirmation as above
    if (yesNoSearch.getNoTerms().getSearchTerms().contains(result)) {
      yesNoSearch.setActive(false);
      Log.d(TAG, "user answered no");
      Log.d(TAG, "current no action = " + yesNoSearch.getNoAction());
      performAction(yesNoSearch.getNoAction(), result);
      return;
    }
    // Otherwise set next search, update UI and start listening for next input
    mActionHandler.setActionPerformed(false);
    setCurrentSearchByString(result);
    Log.d(TAG, "new current search before UI update = " + Search.getCurrentSearch().getName());
  }