private String getCustomValuesText(PDroidAppSetting setting) {
    if (setting.getCustomValues() != null && setting.getCustomValues().size() > 0) {
      List<String> customValueStrings = new LinkedList<String>();
      for (SimpleImmutableEntry<String, String> customValue : setting.getCustomValues()) {
        SpannableStringBuilder builder = new SpannableStringBuilder();
        if (customValue.getKey() != null && !(customValue.getKey().isEmpty())) {
          builder.append(customValue.getKey()).append(":");
        }
        if (customValue.getValue() != null && !(customValue.getValue().isEmpty())) {
          builder.append(customValue.getValue());
          builder.setSpan(
              new StyleSpan(Typeface.ITALIC),
              builder.length() - customValue.getValue().length(),
              builder.length(),
              0);
        }

        if (!builder.toString().isEmpty()) {
          customValueStrings.add(builder.toString());
        }
      }

      if (customValueStrings.size() > 0) {
        return TextUtils.join(
            context.getString(R.string.detail_custom_value_spacer), customValueStrings);
      }
    }
    return null;
  }
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
    View row = convertView;
    SettingHolder holder;

    if (row == null) {
      LayoutInflater inflater = ((Activity) this.context).getLayoutInflater();
      row = inflater.inflate(this.standardResourceId, parent, false);

      holder = new SettingHolder();
      holder.settingName = (TextView) row.findViewById(R.id.option_title);

      // there may or may not be a help button - try to get it, and if
      // it fails, assuming it isn't present
      holder.helpButton = null;
      holder.helpButton = (ImageButton) row.findViewById(R.id.help_button);
      if (holder.helpButton != null) {
        holder.helpButton.setOnClickListener(this.helpButtonClickListener);
      } else {
        row.setOnClickListener(this.helpButtonClickListener);
      }

      holder.customValuePretext = (TextView) row.findViewById(R.id.option_custom_value_pretext);
      holder.customValue = (TextView) row.findViewById(R.id.option_custom_value);
      holder.radioGroup = (RadioGroup) row.findViewById(R.id.setting_choice);

      holder.noChangeOption = row.findViewById(R.id.option_nochange);

      holder.allowOption = row.findViewById(R.id.option_allow);
      holder.allowOption.setOnClickListener(radioButtonClickListener);
      holder.yesOption = row.findViewById(R.id.option_yes);
      holder.yesOption.setOnClickListener(radioButtonClickListener);
      holder.customOption = row.findViewById(R.id.option_custom);
      holder.customOption.setOnClickListener(radioButtonClickListener);
      holder.customLocationOption = row.findViewById(R.id.option_customlocation);
      holder.customLocationOption.setOnClickListener(radioButtonClickListener);
      holder.randomOption = row.findViewById(R.id.option_random);
      holder.randomOption.setOnClickListener(radioButtonClickListener);
      holder.denyOption = row.findViewById(R.id.option_deny);
      holder.denyOption.setOnClickListener(radioButtonClickListener);
      holder.noOption = row.findViewById(R.id.option_no);
      holder.noOption.setOnClickListener(radioButtonClickListener);
      row.setTag(holder);
    } else {
      holder = (SettingHolder) row.getTag();
    }

    // This approach to identified the clicked 'position' is based on
    // http://stackoverflow.com/questions/9392511/how-to-handle-oncheckedchangelistener-for-a-radiogroup-in-a-custom-listview-adap
    // I am not entirely comfortable with always resetting this tag, but I'm not sure creating a
    // class
    // to hold stuff in there and updating it would be better
    holder.radioGroup.setTag(Integer.valueOf(position));
    if (holder.helpButton == null) {
      holder.position = position;
    } else {
      holder.helpButton.setTag(Integer.valueOf(position));
    }

    holder.radioGroup.setOnCheckedChangeListener(
        null); // temporarily disable on-click listener in the hope that it will not trigger
               // unnecessarily
    PDroidAppSetting setting = settingList.get(position);

    holder.settingName.setText(setting.getTitle());

    String customValueText = null;
    switch (setting.getSelectedOptionBit()) {
      case PDroidSetting.OPTION_FLAG_NO_CHANGE:
        holder.radioGroup.check(R.id.option_nochange);
        break;
      case PDroidSetting.OPTION_FLAG_ALLOW:
        holder.radioGroup.check(R.id.option_allow);
        break;
      case PDroidSetting.OPTION_FLAG_YES:
        holder.radioGroup.check(R.id.option_yes);
        break;
      case PDroidSetting.OPTION_FLAG_CUSTOM:
        holder.radioGroup.check(R.id.option_custom);
        customValueText = getCustomValuesText(setting);
        break;
      case PDroidSetting.OPTION_FLAG_CUSTOMLOCATION:
        holder.radioGroup.check(R.id.option_customlocation);
        customValueText = getCustomValuesText(setting);
        break;
      case PDroidSetting.OPTION_FLAG_RANDOM:
        holder.radioGroup.check(R.id.option_random);
        break;
      case PDroidSetting.OPTION_FLAG_DENY:
        holder.radioGroup.check(R.id.option_deny);
        break;
      case PDroidSetting.OPTION_FLAG_NO:
        holder.radioGroup.check(R.id.option_no);
        break;
      default:
        holder.radioGroup.check(R.id.option_allow);
        break;
    }

    if (customValueText == null) {
      holder.customValue.setVisibility(View.GONE);
      holder.customValuePretext.setVisibility(View.GONE);
    } else {
      holder.customValue.setText(customValueText);
      holder.customValue.setVisibility(View.VISIBLE);
      holder.customValuePretext.setVisibility(View.VISIBLE);
    }

    int optionsBits = setting.getOptionsBits();
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_ALLOW)) {
      holder.allowOption.setVisibility(View.GONE);
    } else {
      holder.allowOption.setVisibility(View.VISIBLE);
    }
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_YES)) {
      holder.yesOption.setVisibility(View.GONE);
    } else {
      holder.yesOption.setVisibility(View.VISIBLE);
    }
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_CUSTOM)) {
      holder.customOption.setVisibility(View.GONE);
    } else {
      holder.customOption.setVisibility(View.VISIBLE);
    }
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_CUSTOMLOCATION)) {
      holder.customLocationOption.setVisibility(View.GONE);
    } else {
      holder.customLocationOption.setVisibility(View.VISIBLE);
    }
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_RANDOM)) {
      holder.randomOption.setVisibility(View.GONE);
    } else {
      holder.randomOption.setVisibility(View.VISIBLE);
    }
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_DENY)) {
      holder.denyOption.setVisibility(View.GONE);
    } else {
      holder.denyOption.setVisibility(View.VISIBLE);
    }
    if (0 == (optionsBits & PDroidSetting.OPTION_FLAG_NO)) {
      holder.noOption.setVisibility(View.GONE);
    } else {
      holder.noOption.setVisibility(View.VISIBLE);
    }

    holder.radioGroup.setOnCheckedChangeListener(this.checkbuttonChangeListener);
    return row;
  }