Skip to content

OptiBP Widget

Sebastian edited this page May 23, 2023 · 3 revisions

OptiBP Widget

This widget will launch the OptiBP app to read systolic and diastolic BP readings and then populate the results in the specified fields.

Field attributes

Field Attribute Usage Required
key Unique of the field yes
type Type of the field yes
label OptiBP widget label yes
optibp_button_bg_color Background color of the OptiBP launch button no
optibp_button_text_color Text-color of the OptiBP launch button no
optibp_data JSON object containing clientid and clientOpenSRPId yes
fields_to_use_value Contains the keys of fields on which BP reading will be populated yes
relevance Holds the rules to show/hide the specific field. This can use rules engine/ the line relevance no
calculations Holds the link to the rules files that has a calculation that affects the field in question no
openmrs_entity_parent Holds the concept id of the parent concept in OpenMRS yes
openmrs_entity Holds the entity type on OpenMRS e.g Person, Address, Concept yes
openmrs_entity_id Holds the concept id from OpenMRS no

How to use it optibp widget classes and methods

The main class of optibpWidget is called OptiBPWidgetFactory class in native-form library. If you are using the latest version of native form, this will come as a class in your module.

  1. JSON configuration. Below shows JSON configs you will need to get it working
      {
        "key": "record_bp_using_optibp_button",
        "openmrs_entity_parent": "",
        "openmrs_entity": "concept",
        "openmrs_entity_id": "",
        "type": "optibp",
        "label": "{{anc_physical_exam.step2.record_bp_using_optibp_button.label}}",
        "optibp_button_bg_color": "#EB5281",
        "optibp_button_text_color": "#FFFFFF",
        "read_only": false,
        "optibp_data": {
          "clientId": "",
          "clientOpenSRPId": "",
          "calibration": ""
        },
        "fields_to_use_value": [
          "bp_systolic",
          "bp_diastolic"
        ],
        "relevance": {
          "rules-engine": {
            "ex-rules": {
              "rules-file": "physical-exam-relevance-rules.yml"
            }
          }
        }
      },

Required Status

optibp_data --- This field should be populated programmatically before starting the form. It should contain the clientId and clientOpenSRPId JSON Object. FormUtils.createOptiBPDataObject(clientId, clientOpenSRPId) utils method can be used which will return the required object.

fields_to_use_value --- This field should contain a JSON Array of keys of the fields on which BP readings will be populated. The index 0 should have the key of systolic BP reading field and index 1 should have the diastolic BP reading field key.

Rules

Calculations

  "calculation": {
    "rules-engine": {
      "ex-rules": {
        "rules-file": "sample-calculation-rules.yml"
      }
    }
  }

The block above shows the rules engine relevance block.

Relevance

"relevance": {
    "rules-engine": {
      "ex-rules": {
        "rules-file": "sample-relevance-rules.yml"
      }
    }
  }

The block above shows the rules engine relevance block.

  1. Class implementation and method. Since native form is form based, you will need to populate data to the key fields above in your application. For example in anc, below is a sample code that populates data to the key mentioned above
  if (fieldObject.getString(JsonFormConstants.KEY).equals(ANCJsonFormConstants.KeyConstants.OPTIBP_BUTTON)
                || fieldObject.getString(JsonFormConstants.KEY).equals(ANCJsonFormConstants.KeyConstants.OPTIBP_BUTTON_SECOND)) {
            if (fieldObject.has(JsonFormConstants.OptibpConstants.OPTIBP_KEY_DATA)) {
                fieldObject.remove(JsonFormConstants.OptibpConstants.OPTIBP_KEY_DATA);
            }
            String optibpButtonKey = fieldObject.getString(JsonFormConstants.KEY).equals(ANCJsonFormConstants.KeyConstants.OPTIBP_BUTTON) ? ANCJsonFormConstants.KeyConstants.OPTIBP_BUTTON : ANCJsonFormConstants.KeyConstants.OPTIBP_BUTTON_SECOND;
            String previousContactBpValue = getMapValue(optibpButtonKey) == null ? "" : getMapValue(optibpButtonKey);
            JSONObject optiBPData = FormUtils.createOptiBPDataObject(baseEntityId, womanOpenSRPId, previousContactBpValue);
            fieldObject.put(JsonFormConstants.OptibpConstants.OPTIBP_KEY_DATA, optiBPData);
        }
  1. Dependencies The optibp widget depends on a third party application called Biospectal Optibp App. The two communication use intent communication to share data. Below is the sample code that communicates with Biospectal App. The app is launched with a click on a button shown below

Function launched

  private Button initLaunchButton(LinearLayout rootLayout, final WidgetArgs widgetArgs, boolean readOnly, final int requestCode) throws JSONException {
        final Context context = widgetArgs.getContext();
        final JSONObject jsonObject = widgetArgs.getJsonObject();
        Button launchButton = rootLayout.findViewById(R.id.optibp_launch_button);
        formatButtonWidget(launchButton, widgetArgs.getJsonObject());
        launchButton.setOnClickListener(view -> {
            try {
                Timber.w(" ONCLICK WITH JSON %s", jsonObject);
                Intent intent = new Intent(OptibpConstants.OPTIBP_LAUNCH_INTENT);
                intent.setType("text/json");
                intent.putExtra(Intent.EXTRA_TEXT, getInputJsonString(context, jsonObject, widgetArgs));
                ((Activity) context).startActivityForResult(Intent.createChooser(intent, ""), requestCode);
            } catch (Exception e) {
                Timber.e(e);
            }
        });

        if (readOnly) {
            launchButton.setBackgroundDrawable(new ColorDrawable(widgetArgs.getContext().getResources()
                    .getColor(android.R.color.darker_gray)));
            launchButton.setClickable(false);
            launchButton.setEnabled(false);
            launchButton.setFocusable(false);
        }

        return launchButton;
    }

Results are read by the function below

 public void setUpOptiBpActivityResultListener(final WidgetArgs widgetArgs, int requestCode, final LinearLayout rootLayout, EditText systolicEditText, final EditText diastolicEditText) {
        final Context context = widgetArgs.getContext();
        if (context instanceof JsonApi) {
            final JsonApi jsonApi = (JsonApi) context;
            jsonApi.addOnActivityResultListener(requestCode, (finalRequestCode, resultCode, data) -> {
                if (resultCode == Activity.RESULT_OK) {
                    if (finalRequestCode == OptibpConstants.OPTIBP_REQUEST_CODE ||
                            finalRequestCode == OptibpConstants.OPTIBP_REPEAT_REQUEST_CODE) {
                        try {
                            if (data != null) {
                                String resultJson = data.getStringExtra(Intent.EXTRA_TEXT);
                                Timber.d("Resultant OptiBP JSON: %s ", resultJson);
                                populateBPEditTextValues(resultJson, systolicEditText, diastolicEditText, widgetArgs);
                                String resultString = getValueString(resultJson);
                                if (StringUtils.isNotBlank(resultString)) {
                                    writeResult(jsonApi, rootLayout, resultString, widgetArgs);
                                } else {
                                    Timber.e("JSON Result  %s , Result String  %s", resultJson, resultString);
                                    Toast.makeText(context, context.getString(R.string.invalid_optibp_data), Toast.LENGTH_SHORT).show();
                                }
                            } else
                                Timber.e("NO RESULT FROM OPTIBP APP finalRequestCode %s, resultCode %s", finalRequestCode, resultCode);
                        } catch (Exception e) {
                            Timber.e(e);
                        }
                    }
                } else {
                    Timber.e("final Request code: %s,  ResultCode : %s , Data from OptiBP: %s ", finalRequestCode, resultCode, data);
                    Toast.makeText(context, context.getString(R.string.optibp_unable_to_receive), Toast.LENGTH_SHORT).show();
                }
            });
        }
    }