Skip to content

Commit

Permalink
Merge pull request #766 from PhenoApps/issue/458-tep46
Browse files Browse the repository at this point in the history
Implementing functionality to scan a QR code with BrAPI config settings
  • Loading branch information
trife authored Nov 30, 2023
2 parents fb76bdd + c474e87 commit 353ccf3
Show file tree
Hide file tree
Showing 4 changed files with 255 additions and 11 deletions.
114 changes: 114 additions & 0 deletions app/src/main/java/com/fieldbook/tracker/objects/BrAPIConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package com.fieldbook.tracker.objects;

import com.google.gson.annotations.SerializedName;

import java.util.Objects;

public class BrAPIConfig {
private String url;
private String name;
@SerializedName("v")
private String version;
@SerializedName("ps")
private String pageSize;
@SerializedName("cs")
private String chunkSize;
@SerializedName("st")
private String serverTimeoutMilli;
@SerializedName("flow")
private String authFlow;
@SerializedName("oidc")
private String oidcUrl;
@SerializedName("cat")
private String catDisplay;

public String getUrl() {
return url;
}

public void setUrl(String url) {
this.url = url;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getVersion() {
return version;
}

public void setVersion(String version) {
this.version = version;
}

public String getPageSize() {
return pageSize;
}

public void setPageSize(String pageSize) {
this.pageSize = pageSize;
}

public String getChunkSize() {
return chunkSize;
}

public void setChunkSize(String chunkSize) {
this.chunkSize = chunkSize;
}

public String getServerTimeoutMilli() {
return serverTimeoutMilli;
}

public void setServerTimeoutMilli(String serverTimeoutMilli) {
this.serverTimeoutMilli = serverTimeoutMilli;
}

public String getAuthFlow() {
return authFlow;
}

public void setAuthFlow(String authFlow) {
this.authFlow = authFlow;
}

public String getOidcUrl() {
return oidcUrl;
}

public void setOidcUrl(String oidcUrl) {
this.oidcUrl = oidcUrl;
}

public String getCatDisplay() {
return catDisplay;
}

public void setCatDisplay(String catDisplay) {
this.catDisplay = catDisplay;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
BrAPIConfig that = (BrAPIConfig) o;
return pageSize.equals(that.pageSize) && chunkSize.equals(that.chunkSize) && serverTimeoutMilli.equals(that.serverTimeoutMilli) && url.equals(that.url) && name.equals(that.name) && version.equals(that.version) && authFlow.equals(that.authFlow) && oidcUrl.equals(
that.oidcUrl) && catDisplay.equals(that.catDisplay);
}

@Override
public int hashCode() {
return Objects.hash(url, name, version, pageSize, chunkSize, serverTimeoutMilli, authFlow, oidcUrl, catDisplay);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,16 @@
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.ActionBar;
Expand All @@ -27,6 +32,13 @@
import com.fieldbook.tracker.R;
import com.fieldbook.tracker.activities.PreferencesActivity;
import com.fieldbook.tracker.activities.brapi.BrapiAuthActivity;
import com.fieldbook.tracker.objects.BrAPIConfig;
import com.google.gson.Gson;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.WriterException;
import com.google.zxing.BarcodeFormat;

import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;

Expand All @@ -50,6 +62,7 @@ public class BrapiPreferencesFragment extends PreferenceFragmentCompat implement
private static final String TAG = BrapiPreferencesFragment.class.getSimpleName();
private static final int REQUEST_BARCODE_SCAN_BASE_URL = 99;
private static final int REQUEST_BARCODE_SCAN_OIDC_URL = 98;
private static final int REQUEST_BARCODE_SCAN_BRAPI_CONFIG = 97;
private static final int AUTH_REQUEST_CODE = 123;
private static final String DIALOG_FRAGMENT_TAG = "com.tracker.fieldbook.preferences.BRAPI_DIALOG_FRAGMENT";

Expand Down Expand Up @@ -188,6 +201,32 @@ public boolean onPreferenceChange(Preference preference, Object newValue) {
});
}

//set barcode click listener to start zxing intent
Preference brapiConfigBarcode = findPreference("brapi_config_barcode");
if (brapiConfigBarcode != null) {
brapiConfigBarcode.setOnPreferenceClickListener(preference -> {
String title = getString(R.string.qr_code_share_choose_action_title);
new AlertDialog.Builder(getContext())
.setTitle(title)
.setItems(new String[]{getString(R.string.preferences_brapi_barcode_config_scan), getString(R.string.preferences_brapi_barcode_config_share)}, (dialog, which) -> {
switch (which) {
case 0: // Scan QR Code to import settings
new IntentIntegrator(getActivity())
.setPrompt(getString(R.string.barcode_scanner_text))
.setBeepEnabled(true)
.setRequestCode(REQUEST_BARCODE_SCAN_BRAPI_CONFIG)
.initiateScan();
break;
case 1: // Generate QR Code for sharing settings
generateQRCodeFromPreferences();
break;
}
})
.show();
return true;
});
}

setOidcFlowUi();
}

Expand All @@ -210,6 +249,58 @@ private void updatePreferencesVisibility(boolean isChecked) {
}
}

private void generateQRCodeFromPreferences() {
try {
BrAPIConfig config = new BrAPIConfig();
SharedPreferences ep = prefMgr.getSharedPreferences();
config.setUrl(ep.getString(GeneralKeys.BRAPI_BASE_URL, getString(R.string.brapi_base_url_default)));
config.setName(ep.getString(GeneralKeys.BRAPI_DISPLAY_NAME, getString(R.string.preferences_brapi_server_test)));
config.setVersion(ep.getString(GeneralKeys.BRAPI_VERSION, "V2"));
config.setPageSize(ep.getString(GeneralKeys.BRAPI_PAGE_SIZE, "50"));
config.setChunkSize(ep.getString(GeneralKeys.BRAPI_CHUNK_SIZE, "500"));
config.setServerTimeoutMilli(ep.getString(GeneralKeys.BRAPI_TIMEOUT, "120"));
config.setAuthFlow(ep.getString(GeneralKeys.BRAPI_OIDC_FLOW, getString(R.string.preferences_brapi_oidc_flow_oauth_implicit)));
config.setOidcUrl(ep.getString(GeneralKeys.BRAPI_OIDC_URL, getString(R.string.brapi_oidc_url_default)));
config.setCatDisplay(ep.getString(GeneralKeys.LABELVAL_CUSTOMIZE, "value"));

Gson gson = new Gson();
String jsonConfig = gson.toJson(config);

DisplayMetrics displayMetrics = new DisplayMetrics();
((Activity) getContext()).getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int screenWidth = displayMetrics.widthPixels;

// Set the QR Code size to be 80% of the screen width
int qrCodeSize = (int) (screenWidth * 0.8);

BitMatrix bitMatrix = new MultiFormatWriter().encode(jsonConfig, BarcodeFormat.QR_CODE, qrCodeSize, qrCodeSize);

int width = bitMatrix.getWidth();
int height = bitMatrix.getHeight();
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
for (int x = 0; x < width; x++) {
for (int y = 0; y < height; y++) {
bmp.setPixel(x, y, bitMatrix.get(x, y) ? Color.BLACK : Color.WHITE);
}
}

ImageView imageView = new ImageView(getContext());
imageView.setImageBitmap(bmp);
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
imageView.setAdjustViewBounds(true);

new AlertDialog.Builder(getContext())
.setTitle(getString(R.string.preferences_brapi_barcode_config_dialog_title))
.setView(imageView)
.setPositiveButton(getString(R.string.dialog_close), null)
.show();

} catch (WriterException e) {
Toast.makeText(getContext(), "Error generating QR code", Toast.LENGTH_SHORT).show();
}
}


@Override
public void onCreateOptionsMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {
menu.clear();
Expand Down Expand Up @@ -484,7 +575,6 @@ private void setServer(String url, String displayName, String oidcUrl, String oi
if(oidcFlow != null)
brapiOIDCFlow.setValue(oidcFlow);

setBaseURLSummary();
setOidcFlowUi();
brapiAuth();
}
Expand Down Expand Up @@ -515,8 +605,6 @@ private void updateUrls(String newValue) {
}

oldBaseUrl = newValue;

setBaseURLSummary();
}

/**
Expand Down Expand Up @@ -597,6 +685,33 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) {
updateUrls(scannedBarcode);
}
break;
case REQUEST_BARCODE_SCAN_BRAPI_CONFIG: //barcode scan result for brapi config
if(resultCode == RESULT_OK) {
Log.d(TAG, "onActivityResult: processing config code scan!");
IntentResult plotDataResult = IntentIntegrator.parseActivityResult(resultCode, data);
String scannedConfigJson = plotDataResult.getContents();
Log.d(TAG, "onActivityResult: config data received: " + scannedConfigJson);
BrAPIConfig brAPIConfig = new Gson().fromJson(scannedConfigJson, BrAPIConfig.class);

String brapiVersion = getString(R.string.preferences_brapi_version_v2);
if("v1".equalsIgnoreCase(brAPIConfig.getVersion())) {
brapiVersion = getString(R.string.preferences_brapi_version_v1);
}
((ListPreference)findPreference(GeneralKeys.BRAPI_VERSION)).setValue(brapiVersion);
((BetterEditTextPreference)findPreference(GeneralKeys.BRAPI_PAGE_SIZE)).setText(brAPIConfig.getPageSize());
((BetterEditTextPreference)findPreference(GeneralKeys.BRAPI_CHUNK_SIZE)).setText(brAPIConfig.getChunkSize());
((BetterEditTextPreference)findPreference(GeneralKeys.BRAPI_TIMEOUT)).setText(brAPIConfig.getServerTimeoutMilli());
((ListPreference)findPreference(GeneralKeys.LABELVAL_CUSTOMIZE)).setValue(brAPIConfig.getCatDisplay());

String oidcFlow = getString(R.string.preferences_brapi_oidc_flow_oauth_implicit);
String codeFlow = getString(R.string.preferences_brapi_oidc_flow_oauth_code);
if(codeFlow.equalsIgnoreCase(brAPIConfig.getAuthFlow())) {
oidcFlow = getString(R.string.preferences_brapi_oidc_flow_oauth_code);
}

setServer(brAPIConfig.getUrl(), brAPIConfig.getName(), brAPIConfig.getOidcUrl(), oidcFlow);
}
break;
case AUTH_REQUEST_CODE: // Add your new request code here
if (resultCode == RESULT_OK) {
displaySuccessDialog();
Expand Down
25 changes: 17 additions & 8 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -702,7 +702,8 @@
<string name="database_reset_warning1">All data will be deleted. Are you sure you want to reset the database?</string>
<string name="database_reset_warning2">A database reset cannot be reversed. The app will quit after clearing the database. Are you really sure you want to continue?</string>
<string name="database_reset_message">Database has been deleted</string>

<string name="share_file_title">Sending file…</string>

<!-- Experimental -->
<string name="preferences_experimental_title">Experimental</string>
<string name="preferences_experimental_stable_title">Stable</string>
Expand Down Expand Up @@ -769,7 +770,13 @@
<string name="preferences_brapi_enable_title">Enable BrAPI</string>
<string name="preferences_brapi_enable_summary">The Breeding API allows simple data transfer to compatible databases.</string>
<string name="preferences_brapi_core_title">Configuration</string>

<string name="preferences_brapi_barcode_config_title">Auto-configure</string>
<string name="preferences_brapi_barcode_config_summary">Manage settings with QR codes</string>
<string name="preferences_brapi_barcode_config_scan">Import new settings</string>
<string name="preferences_brapi_barcode_config_share">Share current settings</string>
<string name="preferences_brapi_barcode_config_dialog_title">Scannable BrAPI Configuration</string>
<string name="qr_code_share_choose_action_title">Choose Action</string>

<string name="menu_action_brapi_pref_title">Authorize BrAPI</string>
<string name="act_brapi_auth_http_warning_title">HTTP Warning</string>
<string name="act_brapi_auth_http_warning_message">You have entered an http url. There is no guarantee that this connection is secure.</string>
Expand Down Expand Up @@ -952,7 +959,10 @@
<string name="tutorial_main_delete_description">Data is deleted using this button.</string>
<string name="tutorial_main_search_title">Search</string>
<string name="tutorial_main_search_description">The search icon allows database queries.</string>
<string name="tutorial_main_resources_title">Resources</string>
<string name="tutorial_main_resou exported in two formats: database or table.</string>
<string name="tutorial_fields_add_title">Add Field</string>
<string name="tutorial_fields_add_description">Import a field file.</strrces_title">Resources</string>
<string name="tutorial_main_resources_description">This displays a list of files in the Resources folder.</string>
<string name="tutorial_main_summary_title">Summary</string>
<string name="tutorial_main_summary_description">This displays a summary of all data for the current entry.</string>
Expand All @@ -969,10 +979,7 @@
<string name="tutorial_settings_settings_title">Settings</string>
<string name="tutorial_settings_settings_description">allows additional configuration for data collection.</string>
<string name="tutorial_settings_export_title">Export</string>
<string name="tutorial_settings_export_description">Data can be exported in two formats: database or table.</string>

<string name="tutorial_fields_add_title">Add Field</string>
<string name="tutorial_fields_add_description">Import a field file.</string>
<string name="tutorial_settings_export_description">Data can being>
<string name="tutorial_fields_file_description">Files must contain three columns: a unique identifier, a primary order, and a secondary order. The primary/secondary order are used for navigation in the field.</string>
<string name="tutorial_fields_select_title">Active Field</string>
<string name="tutorial_fields_select_description">A field is selected for data collection after being imported.</string>
Expand All @@ -985,6 +992,8 @@
<string name="tutorial_traits_format_description">Different trait formats are indicated with different icons.</string>
<string name="tutorial_traits_visibility_title">Trait Visibility</string>
<string name="tutorial_traits_visibility_description">Traits can be disabled from collection by toggling the checkbox.</string>
<string name="share_file_title">Sending file…</string>




</resources>
6 changes: 6 additions & 0 deletions app/src/main/res/xml/preferences_brapi.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
android:title="@string/preferences_brapi_core_title"
app:iconSpaceReserved="false">

<Preference
android:icon="@drawable/ic_trait_barcode"
android:key="brapi_config_barcode"
android:title="@string/preferences_brapi_barcode_config_title"
android:summary="@string/preferences_brapi_barcode_config_summary" />

<org.phenoapps.sharedpreferences.dialogs.NeutralButtonEditTextDialog
android:defaultValue="@string/brapi_base_url_default"
android:dialogMessage="@string/brapi_base_url_desc"
Expand Down

0 comments on commit 353ccf3

Please sign in to comment.