public abstract class SecuredActivity extends ActionBarActivity { // class specific code here }
<activity android:name=".view.activity.NativeECSmartRegisterActivity" android:screenOrientation="landscape" android:theme="@style/AppThemeNoTitle" />
Where style/AppThemeNoTitle is defined under styles.xml file as:
<style name="AppThemeNoTitle" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- Customize your theme here. --> <item name="android:windowNoTitle">true</item> <item name="android:windowActionBar">false</item> <item name="android:windowFullscreen">false</item> <!-- this is useful to prevent the keyboard from covering up the input fields --> <item name="android:windowContentOverlay">@null</item> </style>
The logic that is contained in the initial activity that loads the form is then moved to a fragment, the base fragment, the fragment should be as self sufficient as possible i.e only the functions that are handled better by activity rather than fragment are left, the rest are moved to the fragment.
see org.ei.opensrp.mcare.fragment.HouseHoldSmartRegisterFragment; most of the the code moved over from the initial activity i.e org.ei.opensrp.mcare.household.HouseHoldSmartRegisterActivity.
The other modification required by the activity goes to manifest file i.e since we are switching the activity orientation during runtime depending on the fragment on display, we need to prevent the activity from starting a fresh each time (would otherwise cause an exception)
<activity android:name=".household.HouseHoldSmartRegisterActivity" android:configChanges="keyboardHidden|orientation|screenSize" android:theme="@style/AppThemeNoActionBarAndTitle" />
The default form launch functionality is also overridden such that we show the FormFragment instead of launching a new activity whenever a form is requested, the new form launch functionality accepts three parameters:
formName - the name of the form we want to launch
entityId - the id of the record we want to load to the form e.g if we are editing
meta data (fields overrides) - data structure that holds the fields we would like to override
@Override public void startFormActivity(String formName, String entityId, String metaData) { if (entityId != null){ String data = FormUtils.getInstance(getApplicationContext()).generateXMLInputForFormWithEntityId(entityId, formName, null); DisplayFormFragment displayFormFragment = getDisplayFormFragment(); if (displayFormFragment != null) { displayFormFragment.setFormData(data); displayFormFragment.loadFormData(); displayFormFragment.setRecordId(entityId); } } mPager.setCurrentItem(1, false); //Don't animate the view on orientation change the view disapears }
org.ei.opensrp.util.FormUtils class contains the logic needed while saving/retrieving the form, while saving the form the class converts the xml input obtained from the form into a form submission which can be handled by ziggy. When retrieving the form, e.g if the form needs to be preloaded with existing data, the class has utility method that uses the supplied id parameter to build an xml input string to be supplied to the form.
Navigation to and from the FormDisplay is achieved by simply switching the viewpager index to show the desired fragment, e.g initially the register activity shows the base fragment (the fragment with the records list), when new form flow is triggered the view pager index is moved to point to the FomFragment, 1 if its single form flow, or n if we can load multiple forms from the same base fragment.
Example in code is:
mPager.setCurrentItem(1, false); //Don't animate the view on orientation change the view disappears
Form display fragment
The form display fragment contains the logic required to load, edit and save a form. the important fields are:
private String formName; public String getFormName() { return formName; } public void setFormName(String formName) { this.formName = formName; }
String formData; public void setFormData(String data){ this.formData = data; } public void loadFormData(){ formData = formData != null ? formData.replaceAll("\"","\\\"") : ""; webView.post(new Runnable() { @Override public void run() { webView.loadUrl("javascript:loadDraft('"+ formData + "')"); } }); }
The fragment also contains javascript interface for communicating to and fro between the fragment/activity and the enketo form, currently there are only two functions:
- showFormErrorToast - get called if user attempts to save a form that has errors.
- processFormSubmission - gets called whenever save operation is triggered.
public class MyJavaScriptInterface { Context mContext; MyJavaScriptInterface(Context c) { mContext = c; } @JavascriptInterface public void showFormErrorToast(){ Toast.makeText(mContext, formInputErrorMessage, Toast.LENGTH_LONG).show(); } @JavascriptInterface public void processFormSubmission(String formSubmission){ ((SecuredNativeSmartRegisterActivity)getActivity()).saveFormSubmission(formSubmission, recordId, formName, getFormFieldsOverrides()); } }
Add Comment