brouter/brouter-routing-app/src/main/java/btools/routingapp/RoutingParameterDialog.java
2023-07-31 10:30:40 +02:00

400 lines
14 KiB
Java

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
* <p>
* How to use from extern app
* <p>
* - 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
* <p>
* Call the Parameter Setting Dialog from your app like this:
* <p>
* // read the variable parameters into array
* List<RoutingParam> listParams = new ArrayList<>();
* String file = "xyz.brf";
* InputStream fis = new FileInputStream(file); // could be also a stream from DocumentFile
* listParams = getParamsFromProfile(fis);
* fis.close();
* <p>
* // call the BRouter param dialog
* ComponentName cn = new ComponentName("btools.routingapp", "btools.routingapp.RoutingParameterDialog");
* Intent i = new Intent();
* i.setComponent(cn);
* <p>
* // 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
* <p>
* startActivityForResult(i, ROUTE_SETTING_REQUEST);
* <p>
* 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<RoutingParam> 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<RoutingParam> getParamsFromProfile(final InputStream fis) throws IOException {
List<RoutingParam> 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<String, ?> 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<String, String> 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;
}
}
}