From 6d0111b43413746ba2a1cc6f17a1f00215614967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9verin=20Lemaignan?= Date: Tue, 25 Nov 2025 22:44:34 +0100 Subject: [PATCH] [android] add support for schuko/type-E charge sockets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The commit is slightly more complicated that expected because: - it adds supports for both schuko and type-E, using the same icon (but maintaining the underlying type annotated in OSM) - it adds logic to *not* display the power of schuko socket as 'unknown' when not provided in OSM, as it is 'implicit' (3.7kW in most countries) Signed-off-by: Séverin Lemaignan --- .../organicmaps/editor/EditorFragment.java | 34 ++++++++------- .../PlacePageChargeSocketsFragment.java | 9 +++- .../app/src/main/res/values-es/strings.xml | 1 + android/app/src/main/res/values/arrays.xml | 1 + android/app/src/main/res/values/strings.xml | 1 + .../data/ChargeSocketDescriptor.java | 28 ++++++++++++- .../res/drawable/ic_charge_socket_schuko.xml | 10 +++++ .../ic_charge_socket_schuko.svg | 42 +++++++++++++++++++ 8 files changed, 108 insertions(+), 18 deletions(-) create mode 100644 android/sdk/src/main/res/drawable/ic_charge_socket_schuko.xml create mode 100644 data/symbols-svg/charging_sockets/ic_charge_socket_schuko.svg diff --git a/android/app/src/main/java/app/organicmaps/editor/EditorFragment.java b/android/app/src/main/java/app/organicmaps/editor/EditorFragment.java index 0a728c985..a329aa05a 100644 --- a/android/app/src/main/java/app/organicmaps/editor/EditorFragment.java +++ b/android/app/src/main/java/app/organicmaps/editor/EditorFragment.java @@ -1,5 +1,7 @@ package app.organicmaps.editor; +import static android.view.View.INVISIBLE; + import android.annotation.SuppressLint; import android.content.Context; import android.os.Bundle; @@ -396,16 +398,18 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe typeBtns.removeAllViews(); List SOCKET_TYPES = Arrays.stream(getResources().getStringArray(R.array.charge_socket_types)).toList(); - for (String socket : SOCKET_TYPES) + for (String socketType : SOCKET_TYPES) { + ChargeSocketDescriptor socket = new ChargeSocketDescriptor(socketType,0,0); + MaterialButton btn = (MaterialButton) inflater.inflate(R.layout.button_socket_type, typeBtns, false); - btn.setTag(R.id.socket_type, socket); + btn.setTag(R.id.socket_type, socket.type()); // load SVG icon converted into VectorDrawable in res/drawable @SuppressLint("DiscouragedApi") int resIconId = - getResources().getIdentifier("ic_charge_socket_" + socket, "drawable", requireContext().getPackageName()); + getResources().getIdentifier("ic_charge_socket_" + socket.visualType(), "drawable", requireContext().getPackageName()); if (resIconId != 0) { btn.setIcon(getResources().getDrawable(resIconId)); @@ -413,7 +417,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe @SuppressLint("DiscouragedApi") int resTypeId = - getResources().getIdentifier("charge_socket_" + socket, "string", requireContext().getPackageName()); + getResources().getIdentifier("charge_socket_" + socket.visualType(), "string", requireContext().getPackageName()); if (resTypeId != 0) { btn.setText(getResources().getString(resTypeId)); @@ -601,8 +605,7 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe GridLayout socketsGrid = mChargeSockets.findViewById(R.id.socket_grid_editor); socketsGrid.removeAllViews(); - for (int i = 0; i < sockets.length; i++) - { + for (int i = 0; i < sockets.length; i++) { final int currentIndex = i; ChargeSocketDescriptor socket = sockets[i]; @@ -613,28 +616,29 @@ public class EditorFragment extends BaseMwmFragment implements View.OnClickListe MaterialTextView power = itemView.findViewById(R.id.socket_power); MaterialTextView count = itemView.findViewById(R.id.socket_count); + // load SVG icon converted into VectorDrawable in res/drawable @SuppressLint("DiscouragedApi") - int resIconId = getResources().getIdentifier("ic_charge_socket_" + socket.type(), "drawable", - requireContext().getPackageName()); - if (resIconId != 0) - { + int resIconId = getResources().getIdentifier("ic_charge_socket_" + socket.visualType(), "drawable", + requireContext().getPackageName()); + if (resIconId != 0) { icon.setImageResource(resIconId); } @SuppressLint("DiscouragedApi") int resTypeId = - getResources().getIdentifier("charge_socket_" + socket.type(), "string", requireContext().getPackageName()); - if (resTypeId != 0) - { + getResources().getIdentifier("charge_socket_" + socket.visualType(), "string", requireContext().getPackageName()); + if (resTypeId != 0) { type.setText(resTypeId); } - if (socket.power() != 0) - { + if (socket.power() != 0) { DecimalFormat df = new DecimalFormat("#.##"); power.setText(getString(R.string.kw_label, df.format(socket.power()))); } + else if (socket.ignorePower()) { + power.setVisibility(INVISIBLE); + } if (socket.count() != 0) { diff --git a/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java b/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java index 152614d2e..8233cb6e3 100644 --- a/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java +++ b/android/app/src/main/java/app/organicmaps/widget/placepage/sections/PlacePageChargeSocketsFragment.java @@ -1,5 +1,7 @@ package app.organicmaps.widget.placepage.sections; +import static android.view.View.INVISIBLE; + import android.annotation.SuppressLint; import android.os.Bundle; import android.view.LayoutInflater; @@ -89,7 +91,7 @@ public class PlacePageChargeSocketsFragment extends Fragment implements Observer // load SVG icon converted into VectorDrawable in res/drawable @SuppressLint("DiscouragedApi") - int resIconId = getResources().getIdentifier("ic_charge_socket_" + socket.type(), "drawable", + int resIconId = getResources().getIdentifier("ic_charge_socket_" + socket.visualType(), "drawable", requireContext().getPackageName()); if (resIconId != 0) { @@ -98,7 +100,7 @@ public class PlacePageChargeSocketsFragment extends Fragment implements Observer @SuppressLint("DiscouragedApi") int resTypeId = - getResources().getIdentifier("charge_socket_" + socket.type(), "string", requireContext().getPackageName()); + getResources().getIdentifier("charge_socket_" + socket.visualType(), "string", requireContext().getPackageName()); if (resTypeId != 0) { type.setText(resTypeId); @@ -109,6 +111,9 @@ public class PlacePageChargeSocketsFragment extends Fragment implements Observer DecimalFormat df = new DecimalFormat("#.##"); power.setText(getString(R.string.kw_label, df.format(socket.power()))); } + else if (socket.ignorePower()) { + power.setVisibility(INVISIBLE); + } if (socket.count() != 0) { diff --git a/android/app/src/main/res/values-es/strings.xml b/android/app/src/main/res/values-es/strings.xml index 7d59ad3f0..115bd8ea0 100644 --- a/android/app/src/main/res/values-es/strings.xml +++ b/android/app/src/main/res/values-es/strings.xml @@ -887,6 +887,7 @@ Potencia (kW) desconocido Evitar escaleras + Doméstico UE enchufe desconocido Crear nuevo enchufe o editar existentes. Enchufes disponibles diff --git a/android/app/src/main/res/values/arrays.xml b/android/app/src/main/res/values/arrays.xml index de2c651d7..f2f0a85eb 100644 --- a/android/app/src/main/res/values/arrays.xml +++ b/android/app/src/main/res/values/arrays.xml @@ -30,6 +30,7 @@ type1 type2_cable type2 + schuko unknown diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index 861f6dfc1..2273c8658 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -939,6 +939,7 @@ Type 1 NACS CHAdeMO + Domestic EU unknown socket Create new sockets or edit existing ones. Available sockets diff --git a/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java b/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java index 955464bc6..743c39afc 100644 --- a/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java +++ b/android/sdk/src/main/java/app/organicmaps/sdk/bookmarks/data/ChargeSocketDescriptor.java @@ -1,7 +1,33 @@ package app.organicmaps.sdk.bookmarks.data; +import java.text.DecimalFormat; + /** * represents the details of the socket available on a particular charging station * */ -public record ChargeSocketDescriptor(String type, int count, double power) {} +public record ChargeSocketDescriptor(String type, int count, double power) { + + /** + * Some charge sockets have the same visuals as other sockets, even though they are different and are tagged + * differently in OSM. This method returns the 'visual' type that should be used for the socket. + * + * @return the 'equivalent' visual style that should be used for this socket + */ + public String visualType() { + if (type.equals("typee")) { + return "schuko"; + } + return type; + } + + /** + * For some sockets (eg, domestic sockets), the power is usually not provided, as it is 'implicit' + * + * @return true if this socket type does not require displaying the power + */ + public Boolean ignorePower() { + return type.equals("typee") || type.equals("schuko"); + } + +} diff --git a/android/sdk/src/main/res/drawable/ic_charge_socket_schuko.xml b/android/sdk/src/main/res/drawable/ic_charge_socket_schuko.xml new file mode 100644 index 000000000..85e92e6ba --- /dev/null +++ b/android/sdk/src/main/res/drawable/ic_charge_socket_schuko.xml @@ -0,0 +1,10 @@ + + + diff --git a/data/symbols-svg/charging_sockets/ic_charge_socket_schuko.svg b/data/symbols-svg/charging_sockets/ic_charge_socket_schuko.svg new file mode 100644 index 000000000..89edae0b7 --- /dev/null +++ b/data/symbols-svg/charging_sockets/ic_charge_socket_schuko.svg @@ -0,0 +1,42 @@ + +image/svg+xml