package btools.routingapp; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; import android.os.Build; import android.os.Bundle; import android.window.OnBackInvokedCallback; import android.window.OnBackInvokedDispatcher; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.app.AppCompatActivity; import androidx.preference.CheckBoxPreference; import androidx.preference.EditTextPreference; import androidx.preference.ListPreference; import androidx.preference.Preference; import androidx.preference.PreferenceCategory; import androidx.preference.PreferenceFragmentCompat; import androidx.preference.PreferenceScreen; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * This activity is used to define the parameter for the six BRouter routing modes. * But it could also used from other apps to get parameters for an extern profile * So the app can send a remote profile and add some parameters for the handling *

* How to use from extern app *

* - copy the class btools.routingapp.RoutingParam to your app java folder without any changes * - copy the routine 'getParamsFromProfile' below to your favorite setting class * inside BRouter the getParamsFromProfile is called to handle the internal parameters *

* Call the Parameter Setting Dialog from your app like this: *

* // read the variable parameters into array * List listParams = new ArrayList<>(); * String file = "xyz.brf"; * InputStream fis = new FileInputStream(file); // could be also a stream from DocumentFile * listParams = getParamsFromProfile(fis); * fis.close(); *

* // call the BRouter param dialog * ComponentName cn = new ComponentName("btools.routingapp", "btools.routingapp.RoutingParameterDialog"); * Intent i = new Intent(); * i.setComponent(cn); *

* // fill some parameter for the dialog * String profile_hash = String.format("X%X", file.hashCode()); // some identify code * i.putExtra("PROFILE_HASH", profile_hash); * i.putExtra("PROFILE", profile_name); // the profile name, only used for display * i.putExtra("PARAMS", listParams); // the settings list * i.putExtra("PARAMS_VALUES", saved_params); // your stored profile parameter or nothing *

* startActivityForResult(i, ROUTE_SETTING_REQUEST); *

* onActivityResult: * if (requestCode == ROUTE_SETTING_REQUEST) { * String profile = null; * String profile_hash = null; * String sparams = null; * // get back the selected parameter (only PARAMS_VALUES is needed) * if (data != null && data.hasExtra("PARAMS_VALUES")) { * sparams = data.getExtras().getString("PARAMS_VALUES", ""); * Log.d(TAG, "result sparams " + sparams); * } * if (data != null && data.hasExtra("PROFILE")) { * profile = data.getExtras().getString("PROFILE", ""); * Log.d(TAG, "result profile " + profile); * } * if (data != null && data.hasExtra("PROFILE_HASH")) { * profile_hash = data.getExtras().getString("PROFILE_HASH", ""); * Log.d(TAG, "result profile_hash " + profile_hash); * } * } */ public class RoutingParameterDialog extends AppCompatActivity { static String TAG = "RoutingParameterDialog"; static SharedPreferences sharedValues; static ArrayList listParams; static String profile; static String profile_hash; /** * collect a list of parameter in a profile * * @param fis - inputstream from profile * @return - list of variable params in this profile * @throws IOException if not readable */ static public List getParamsFromProfile(final InputStream fis) throws IOException { List list = null; if (fis != null) { list = new ArrayList<>(); // prepare the file for reading InputStreamReader chapterReader = new InputStreamReader(fis); BufferedReader buffreader = new BufferedReader(chapterReader); String line; // read every line of the file into the line-variable, on line at the time do { line = buffreader.readLine(); // do something with the line if (line != null && line.contains("#") && line.contains("%") && line.lastIndexOf("%") != line.indexOf("%") ) { String s = line.substring(line.indexOf("#") + 1); String v = line.substring(0, line.indexOf("#")); try { String[] sa = s.split("\\|"); RoutingParam p = new RoutingParam(); p.name = sa[0].trim(); p.name = p.name.substring(1, p.name.length() - 1); // turnInstructionMode may transfered from client direct, use only in web client if (p.name.equals("turnInstructionMode")) continue; p.description = sa[1].trim(); p.type = sa[2].trim(); String[] sav = v.trim().split(" +"); if (sav[1].equals(p.name)) { if (sav[0].equals("assign")) { if (sav[2].equals("=")) { p.value = sav[3]; } else { p.value = sav[2]; } } list.add(p); } } catch (Exception e) { e.printStackTrace(); } } } while (line != null); } return list; } @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit(); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { getOnBackInvokedDispatcher().registerOnBackInvokedCallback( OnBackInvokedDispatcher.PRIORITY_DEFAULT, new OnBackInvokedCallback() { @Override public void onBackInvoked() { StringBuilder sb = null; if (sharedValues != null) { // fill preference with used params // for direct use in the BRouter interface "extraParams" sb = new StringBuilder(); for (Map.Entry entry : sharedValues.getAll().entrySet()) { if (!entry.getKey().equals("params")) { sb.append(sb.length() > 0 ? "&" : "") .append(entry.getKey()) .append("="); String s = entry.getValue().toString(); if (s.equals("true")) s = "1"; else if (s.equals("false")) s = "0"; sb.append(s); } } } // and return the array // one should be enough Intent i = new Intent(); // i.putExtra("PARAMS", listParams); i.putExtra("PROFILE", profile); i.putExtra("PROFILE_HASH", profile_hash); if (sb != null) i.putExtra("PARAMS_VALUES", sb.toString()); setResult(Activity.RESULT_OK, i); finish(); } } ); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } public static class MyPreferenceFragment extends PreferenceFragmentCompat { private Activity mActivity; @Override public void onAttach(@NonNull Context context) { super.onAttach(context); if (context instanceof Activity) { mActivity = (Activity) context; } } @Override public void onDetach() { super.onDetach(); mActivity = null; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mActivity.setTitle("Profile Settings"); listParams = new ArrayList<>(); String sparams = ""; try { Intent i = mActivity.getIntent(); if (i == null) { mActivity.finish(); return; } if (i.hasExtra("PROFILE")) { profile = i.getStringExtra("PROFILE"); } if (i.hasExtra("PROFILE_HASH")) { profile_hash = i.getStringExtra("PROFILE_HASH"); } if (i.hasExtra("PARAMS")) { List result; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { result = (List) i.getExtras().getSerializable("PARAMS", ArrayList.class); } else { result = (List) i.getExtras().getSerializable("PARAMS"); } if (result instanceof ArrayList) { for (Object o : result) { if (o instanceof RoutingParam) listParams.add((RoutingParam) o); } } } if (i.hasExtra("PARAMS_VALUES")) { sparams = i.getExtras().getString("PARAMS_VALUES", ""); } } catch (Exception e) { e.printStackTrace(); } getPreferenceManager().setSharedPreferencesName("prefs_profile_" + profile_hash); sharedValues = getPreferenceManager().getSharedPreferences(); // clear all // sharedValues.edit().clear().commit(); setPreferenceScreen(createPreferenceHierarchy(sparams)); } @Override public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) { } private PreferenceScreen createPreferenceHierarchy(String sparams) { // Root Activity a = this.getActivity(); if (a == null) return null; // fill incoming params Map params = new HashMap<>(); if (sparams != null && sparams.length() > 0) { String[] sa = sparams.split("&"); for (String sar : sa) { String[] sa2 = sar.split("="); if (sa2.length == 2) params.put(sa2[0], sa2[1]); } } PreferenceScreen root = getPreferenceManager().createPreferenceScreen(a); PreferenceCategory gpsPrefCat = new PreferenceCategory(this.getActivity()); if (profile.length() > 0) { gpsPrefCat.setTitle(profile); } else { gpsPrefCat.setTitle("Profile Settings"); } root.addPreference(gpsPrefCat); if (listParams != null) { for (RoutingParam p : listParams) { if (p.type.equals("number")) { EditTextPreference numberTextPref = new EditTextPreference(this.getActivity()); numberTextPref.setDialogTitle(p.name); numberTextPref.setKey(p.name); numberTextPref.setSummary(p.description); String s = (params.get(p.name) != null ? params.get(p.name) : p.value); if (p.value.equals(s)) sharedValues.edit().remove(p.name).apply(); numberTextPref.setTitle(p.name + ": " + s); numberTextPref.setText(s); //EditText speedEditText = (EditText) speedTextPref.getText(); //speedEditText.setKeyListener(DigitsKeyListener.getInstance(false, true)); numberTextPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> { p.value = (String) newValue; numberTextPref.setTitle(p.name + ": " + p.value); return true; }); gpsPrefCat.addPreference(numberTextPref); } else if (p.type.equals("boolean")) { CheckBoxPreference boolPref = new CheckBoxPreference(this.getActivity()); boolPref.setKey(p.name); boolPref.setTitle(p.name); boolPref.setSummary(p.description); boolean checked = false; boolean vchecked = p.value != null && (p.value.equals("1") || p.value.equals("true")); if (params.get(p.name) != null) { checked = params.get(p.name).equals("1") || params.get(p.name).equals("true"); } else { checked = vchecked; } if (vchecked == checked) sharedValues.edit().remove(p.name).apply(); boolPref.setChecked(checked); //historyPref.setDefaultValue(sharedValues.getBoolean(p.name, p.value != null ? p.value.equals("1") || p.value.equals("true") : false)); boolPref.setDefaultValue(p.value != null && (p.value.equals("1") || p.value.equals("true"))); boolPref.setOnPreferenceClickListener((Preference preference) -> { p.value = (((CheckBoxPreference) preference).isChecked() ? "1" : "0"); return true; }); gpsPrefCat.addPreference(boolPref); } else if (p.type.contains("[") && p.type.contains("]")) { String[] sa = p.type.substring(p.type.indexOf("[") + 1, p.type.indexOf("]")).split(","); String[] entryValues = new String[sa.length]; String[] entries = new String[sa.length]; int i = 0, ii = 0; String s = (params.get(p.name) != null ? params.get(p.name) : p.value); //sharedValues.getString(p.name, p.value); for (String tmp : sa) { // Add the name and address to the ListPreference enties and entyValues //L.v("AFTrack", "device: "+device.getName() + " -- " + device.getAddress()); entryValues[i] = "" + i; entries[i] = tmp.trim(); if (entryValues[i].equals(s)) ii = i; i++; } if (p.value.equals(s)) sharedValues.edit().remove(p.name).apply(); ListPreference listPref = new ListPreference(this.getActivity()); listPref.setEntries(entries); listPref.setEntryValues(entryValues); listPref.setDialogTitle(p.name); listPref.setKey(p.name); listPref.setValueIndex(ii); listPref.setTitle(p.name + ": " + entries[ii]); listPref.setSummary(p.description); listPref.setOnPreferenceChangeListener((Preference preference, Object newValue) -> { p.value = (String) newValue; int iii = Integer.decode(p.value); listPref.setTitle(p.name + ": " + entries[iii]); return true; }); gpsPrefCat.addPreference(listPref); } } } return root; } } }