Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
Expand Down Expand Up @@ -65,6 +66,39 @@ public static ChoiceSetInputRenderer getInstance()
return s_instance;
}

public static class FocusableChoiceListener<T extends CompoundButton> implements View.OnTouchListener
{
public FocusableChoiceListener(T firstView)
{
m_firstView = firstView;
}

@Override
public boolean onTouch(View view, MotionEvent motionEvent)
{
if (motionEvent.getAction() == MotionEvent.ACTION_UP)
{
m_firstView.setFocusableInTouchMode(false);
m_firstView.clearFocus();

T clickableElement = (T) view;
// Checkboxes must change their values to the opposite one, radio buttons must always turn on
if (clickableElement instanceof CheckBox)
{
clickableElement.setChecked(!clickableElement.isChecked());
}
else
{
clickableElement.setChecked(true);
}

}
return true;
}

private T m_firstView;
}

public View renderCheckBoxSet(
RenderedAdaptiveCard renderedCard,
Context context,
Expand All @@ -90,7 +124,7 @@ public View renderCheckBoxSet(
for (int i = 0; i < size; i++)
{
ChoiceInput choiceInput = choiceInputVector.get(i);
CheckBox checkBox = new CheckBox(context);
final CheckBox checkBox = new CheckBox(context);
checkBox.setText(choiceInput.GetTitle());

if (!choiceSetInput.GetWrap())
Expand All @@ -112,6 +146,13 @@ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked)
CardRendererRegistration.getInstance().notifyInputChange(checkBoxSetInputHandler.getId(), checkBoxSetInputHandler.getInput());
}
});

// Only for the first checkbox we'll add some extra behaviour as it's going to be the element to receive focus
// When validation fails we'll set the first checkbox with focusableInTouchMode = true, this makes the clicking
// inconsistent as it needs two clicks to check/uncheck, so once it's clicked, we'll remove the property to false
// and check/uncheck the box ourselves
checkBox.setOnTouchListener(new FocusableChoiceListener<CheckBox>(checkBoxList.get(0)));

layout.addView(checkBox);
}

Expand All @@ -135,6 +176,7 @@ public View renderRadioGroup(
ChoiceInputVector choiceInputVector = choiceSetInput.GetChoices();
long size = choiceInputVector.size();
String value = choiceSetInput.GetValue();

for (int i = 0; i < size; i++)
{
ChoiceInput choiceInput = choiceInputVector.get(i);
Expand All @@ -152,7 +194,10 @@ public View renderRadioGroup(
{
radioButton.setChecked(true);
}

radioGroup.addView(radioButton);

radioButton.setOnTouchListener(new FocusableChoiceListener<RadioButton>((RadioButton) radioGroup.getChildAt(0)));
}
renderedCard.registerInputHandler(radioGroupInputHandler, renderArgs.getContainerCardId());
radioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener()
Expand All @@ -163,6 +208,7 @@ public void onCheckedChanged(RadioGroup group, int checkedId)
CardRendererRegistration.getInstance().notifyInputChange(radioGroupInputHandler.getId(), radioGroupInputHandler.getInput());
}
});

return radioGroup;
}

Expand Down Expand Up @@ -280,6 +326,8 @@ public void onNothingSelected(AdapterView<?> parent)
CardRendererRegistration.getInstance().notifyInputChange(comboBoxInputHandler.getId(), comboBoxInputHandler.getInput());
}
});

spinner.setFocusable(true);
return spinner;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@ protected EditText renderInternal(
// editText.addTextChangedListener(new UnvalidatedTextWatcher(textInputHandler));
}

editText.setFocusable(true);
textInputHandler.setView(editText);
renderedCard.registerInputHandler(textInputHandler, renderArgs.getContainerCardId());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import android.nfc.Tag;
import android.support.v4.app.FragmentManager;
import android.text.TextUtils;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CheckBox;
Expand Down Expand Up @@ -73,6 +74,7 @@ public View render(
checkBox.setLines(1);
checkBox.setEllipsize(TextUtils.TruncateAt.END);
}

toggleInputHandler.setView(checkBox);

TagContent tagContent = new TagContent(toggleInput, toggleInputHandler);
Expand All @@ -94,6 +96,9 @@ public View render(
{
checkBox.setChecked(true);
}

checkBox.setOnTouchListener(new ChoiceSetInputRenderer.FocusableChoiceListener<CheckBox>(checkBox));

checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener()
{
@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ public void showValidationErrors(boolean isValid)
}
}

public void setFocusToView()
{
m_view.requestFocus();
}

protected BaseInputElement m_baseInputElement = null;
protected View m_view = null;
private StretchableInputLayout m_inputLayout = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// Licensed under the MIT License.
package io.adaptivecards.renderer.inputhandler;

import android.text.Layout;
import android.text.TextUtils;
import android.widget.CheckBox;
import android.widget.LinearLayout;

import io.adaptivecards.objectmodel.BaseInputElement;
import io.adaptivecards.objectmodel.ChoiceInputVector;
Expand Down Expand Up @@ -71,5 +73,15 @@ public void setInput(String values)
}
}

@Override
public void setFocusToView()
{
if (m_checkBoxList.size() > 0)
{
m_checkBoxList.get(0).setFocusableInTouchMode(true);
m_checkBoxList.get(0).requestFocus();
}
}

private List<CheckBox> m_checkBoxList;
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,11 @@ public void setInput(String value)

getSpinner().setSelection(selectedPosition);
}

@Override
public void setFocusToView()
{
m_view.requestFocus();
m_view.performClick();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,5 @@ public interface IInputHandler
void setInput(String input);

boolean isValid();
void setFocusToView();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Licensed under the MIT License.
package io.adaptivecards.renderer.inputhandler;

import android.widget.RadioButton;
import android.widget.RadioGroup;

import io.adaptivecards.objectmodel.BaseInputElement;
Expand Down Expand Up @@ -70,4 +71,18 @@ public void setInput(String choice)
}
}

@Override
public void setFocusToView()
{
RadioGroup radioGroup = (RadioGroup)m_view;

if (radioGroup.getChildCount() > 0)
{
RadioButton radioButton = (RadioButton)(radioGroup.getChildAt(0));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: additional newline creeped in

radioButton.setFocusableInTouchMode(true);
radioButton.requestFocus();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ public boolean isValidOnSpecifics(String textInputValue)
return isValid;
}

public void setFocusToView()
{
m_view.requestFocus();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,11 @@ public boolean isValid()

return isValid;
}

@Override
public void setFocusToView()
{
m_view.setFocusableInTouchMode(true);
m_view.requestFocus();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
package io.adaptivecards.adaptivecardssample.CustomObjects.CardElements;

import android.content.Context;
import android.graphics.Color;
import android.support.v4.app.FragmentManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;

import org.json.JSONException;
import org.json.JSONObject;

import io.adaptivecards.objectmodel.BaseCardElement;
import io.adaptivecards.objectmodel.BaseCardElementParser;
import io.adaptivecards.objectmodel.BaseInputElement;
import io.adaptivecards.objectmodel.CardElementType;
import io.adaptivecards.objectmodel.HostConfig;
import io.adaptivecards.objectmodel.JsonValue;
import io.adaptivecards.objectmodel.ParseContext;
import io.adaptivecards.renderer.BaseCardElementRenderer;
import io.adaptivecards.renderer.RenderArgs;
import io.adaptivecards.renderer.RenderedAdaptiveCard;
import io.adaptivecards.renderer.TagContent;
import io.adaptivecards.renderer.Util;
import io.adaptivecards.renderer.actionhandler.ICardActionHandler;
import io.adaptivecards.renderer.inputhandler.BaseInputHandler;
import io.adaptivecards.renderer.inputhandler.IInputHandler;

public class CustomInput extends BaseInputElement
{
public CustomInput(CardElementType cardElementType)
{
super(cardElementType);
}

public static class CustomInputHandler extends BaseInputHandler
{
public CustomInputHandler(BaseInputElement baseInputElement, EditText editText)
{
super(baseInputElement);
m_view = editText;
}

@Override
public String getInput()
{
return ((EditText)m_view).getText().toString();
}

@Override
public void setInput(String input)
{
((EditText)m_view).setText(input);
}

@Override
public void setFocusToView()
{
m_view.requestFocus();
}
}

public static class CustomInputRenderer extends BaseCardElementRenderer
{
@Override
public View render(RenderedAdaptiveCard renderedCard,
Context context,
FragmentManager fragmentManager,
ViewGroup viewGroup,
BaseCardElement baseCardElement,
ICardActionHandler cardActionHandler,
HostConfig hostConfig,
RenderArgs renderArgs) throws Exception
{
EditText renderedInput = new EditText(context);
renderedInput.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT));

renderedInput.setBackgroundColor(Color.GREEN);
renderedInput.setTag(new TagContent(baseCardElement));
viewGroup.addView(renderedInput);

BaseInputElement inputElement = Util.castTo(baseCardElement, BaseInputElement.class);
renderedCard.registerInputHandler(new CustomInputHandler(inputElement, renderedInput), renderArgs.getContainerCardId());
return renderedInput;
}
}


public static class CustomInputParser extends BaseCardElementParser
{
@Override
public BaseCardElement Deserialize(ParseContext context, JsonValue value)
{
CustomInput element = new CustomInput(CardElementType.Custom);
element.SetElementTypeString(customInputTypeString);
String val = value.getString();
try
{
JSONObject obj = new JSONObject(val);
element.SetId(obj.getString("id"));
element.SetLabel(obj.getString("label"));
}
catch (JSONException e)
{
e.printStackTrace();
}
return element;
}

@Override
public BaseCardElement DeserializeFromString(ParseContext context, String jsonString)
{
CustomInput element = new CustomInput(CardElementType.Custom);
element.SetElementTypeString(customInputTypeString);
try
{
JSONObject obj = new JSONObject(jsonString);
element.SetId(obj.getString("id"));
element.SetLabel(obj.getString("label"));
}
catch (JSONException e)
{
e.printStackTrace();
}
return element;
}
}

public final static String customInputTypeString = "customInput";
}
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ private ParseContext createParseContextForCustomElements()
{
elementParserRegistration = new ElementParserRegistration();
elementParserRegistration.AddParser("blah", new CustomBlahParser());
elementParserRegistration.AddParser(CustomInput.customInputTypeString, new CustomInput.CustomInputParser());

actionParserRegistration = new ActionParserRegistration();
actionParserRegistration.AddParser(CustomRedActionElement.CustomActionId, new CustomRedActionParser());
Expand Down Expand Up @@ -293,6 +294,7 @@ private void registerCustomElementRenderers()
if (m_customElements.isChecked())
{
CardRendererRegistration.getInstance().registerRenderer("blah", new CustomBlahRenderer());
CardRendererRegistration.getInstance().registerRenderer(CustomInput.customInputTypeString, new CustomInput.CustomInputRenderer());
}
}

Expand Down