diff --git a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java index bee9fa2b19..ede3b6f8cf 100644 --- a/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java +++ b/OsmAnd-java/src/main/java/net/osmand/GPXUtilities.java @@ -1822,6 +1822,25 @@ public class GPXUtilities { } serializer.endTag(null, "metadata"); + for (WptPt l : file.points) { + serializer.startTag(null, "wpt"); //$NON-NLS-1$ + writeWpt(format, serializer, l); + serializer.endTag(null, "wpt"); //$NON-NLS-1$ + } + + for (Route track : file.routes) { + serializer.startTag(null, "rte"); //$NON-NLS-1$ + writeNotNullText(serializer, "name", track.name); + writeNotNullText(serializer, "desc", track.desc); + + for (WptPt p : track.points) { + serializer.startTag(null, "rtept"); //$NON-NLS-1$ + writeWpt(format, serializer, p); + serializer.endTag(null, "rtept"); //$NON-NLS-1$ + } + writeExtensions(serializer, track); + serializer.endTag(null, "rte"); //$NON-NLS-1$ + } for (Track track : file.tracks) { if (!track.generalTrack) { @@ -1844,26 +1863,6 @@ public class GPXUtilities { } } - for (Route track : file.routes) { - serializer.startTag(null, "rte"); //$NON-NLS-1$ - writeNotNullText(serializer, "name", track.name); - writeNotNullText(serializer, "desc", track.desc); - - for (WptPt p : track.points) { - serializer.startTag(null, "rtept"); //$NON-NLS-1$ - writeWpt(format, serializer, p); - serializer.endTag(null, "rtept"); //$NON-NLS-1$ - } - writeExtensions(serializer, track); - serializer.endTag(null, "rte"); //$NON-NLS-1$ - } - - for (WptPt l : file.points) { - serializer.startTag(null, "wpt"); //$NON-NLS-1$ - writeWpt(format, serializer, l); - serializer.endTag(null, "wpt"); //$NON-NLS-1$ - } - writeExtensions(serializer, file); serializer.endTag(null, "gpx"); //$NON-NLS-1$ diff --git a/OsmAnd-java/src/main/java/net/osmand/binary/StringBundleWriter.java b/OsmAnd-java/src/main/java/net/osmand/binary/StringBundleWriter.java index 2f607aef3a..d3c151c12a 100644 --- a/OsmAnd-java/src/main/java/net/osmand/binary/StringBundleWriter.java +++ b/OsmAnd-java/src/main/java/net/osmand/binary/StringBundleWriter.java @@ -20,7 +20,7 @@ public abstract class StringBundleWriter { public void writeBundle() { for (Entry> entry : bundle.getMap().entrySet()) { - writeItem(entry.getKey(), entry.getValue()); + writeItem("osmand:" + entry.getKey(), entry.getValue()); } } } diff --git a/OsmAnd/build.gradle.lib b/OsmAnd/build.gradle.lib index 6b0f4da990..f4f9c019ed 100644 --- a/OsmAnd/build.gradle.lib +++ b/OsmAnd/build.gradle.lib @@ -38,7 +38,7 @@ android { jni.srcDirs = [] jniLibs.srcDirs = ["libs"] aidl.srcDirs = ["src"] - java.srcDirs = ["src", "src-google"] + java.srcDirs = ["src", "src-gms", "src-google"] resources.srcDirs = ["src"] renderscript.srcDirs = ["src"] res.srcDirs = ["res"] @@ -409,6 +409,7 @@ dependencies { exclude group: "com.fasterxml.jackson.core" } implementation 'com.jaredrummler:colorpicker:1.1.0' - implementation 'org.bouncycastle:bcpkix-jdk15on:1.56' + + implementation 'com.google.android.gms:play-services-location:17.1.0' } diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java index 1b9e7f3b29..888216abb3 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingCard.java @@ -5,10 +5,12 @@ import android.text.TextWatcher; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnFocusChangeListener; +import android.view.ViewGroup; import android.widget.EditText; import android.widget.TextView; import androidx.annotation.NonNull; +import androidx.core.content.ContextCompat; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -23,6 +25,7 @@ import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener; import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionItem; import net.osmand.plus.routepreparationmenu.cards.BaseCard; +import net.osmand.plus.settings.backend.ApplicationMode; import net.osmand.plus.widgets.OsmandTextFieldBoxes; import java.util.List; @@ -42,10 +45,12 @@ public class OnlineRoutingCard extends BaseCard { private View bottomDivider; private View button; private OnTextChangedListener onTextChangedListener; + private ApplicationMode appMode; - public OnlineRoutingCard(@NonNull MapActivity mapActivity, boolean nightMode) { + public OnlineRoutingCard(@NonNull MapActivity mapActivity, boolean nightMode, ApplicationMode appMode) { super(mapActivity); this.nightMode = nightMode; + this.appMode = appMode; } @Override @@ -67,6 +72,9 @@ public class OnlineRoutingCard extends BaseCard { bottomDivider = view.findViewById(R.id.bottom_divider); button = view.findViewById(R.id.button); + int activeColor = ContextCompat.getColor(app, appMode.getIconColorInfo().getColor(nightMode)); + textFieldBoxes.setPrimaryColor(activeColor); + editText.addTextChangedListener(new TextWatcher() { @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { @@ -127,6 +135,11 @@ public class OnlineRoutingCard extends BaseCard { rvSelectionMenu.setAdapter(adapter); } + public void updateBottomMarginSelectionMenu(int bottomMargin) { + ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) rvSelectionMenu.getLayoutParams(); + params.bottomMargin = bottomMargin; + } + public void setDescription(@NonNull String description) { showElements(tvDescription); tvDescription.setText(description); diff --git a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java index 59df4ef698..997b7fb34c 100644 --- a/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java +++ b/OsmAnd/src/net/osmand/plus/onlinerouting/OnlineRoutingEngineFragment.java @@ -1,18 +1,28 @@ package net.osmand.plus.onlinerouting; +import android.annotation.SuppressLint; +import android.app.Activity; import android.content.Context; +import android.content.DialogInterface; +import android.graphics.Rect; import android.os.Build; import android.os.Bundle; import android.view.LayoutInflater; +import android.view.MotionEvent; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.ScrollView; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.appcompat.app.AlertDialog; import androidx.appcompat.widget.Toolbar; import androidx.fragment.app.FragmentActivity; import androidx.fragment.app.FragmentManager; @@ -51,6 +61,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { private static final String ENGINE_VEHICLE_TYPE_KEY = "engine_vehicle_type"; private static final String ENGINE_CUSTOM_VEHICLE_KEY = "engine_custom_vehicle"; private static final String ENGINE_API_KEY_KEY = "engine_api_key"; + private static final String INIT_ENGINE_NAME_KEY = "init_engine_name"; + private static final String INIT_ENGINE_SERVER_KEY = "init_engine_server"; + private static final String INIT_ENGINE_SERVER_URL_KEY = "init_engine_server_url"; + private static final String INIT_ENGINE_VEHICLE_TYPE_KEY = "init_engine_vehicle_type"; + private static final String INIT_ENGINE_CUSTOM_VEHICLE_KEY = "init_engine_custom_vehicle"; + private static final String INIT_ENGINE_API_KEY_KEY = "init_engine_api_key"; private static final String EXAMPLE_LOCATION_KEY = "example_location"; private static final String APP_MODE_KEY = "app_mode"; private static final String EDITED_ENGINE_KEY = "edited_engine_key"; @@ -67,10 +83,14 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { private OnlineRoutingCard apiKeyCard; private OnlineRoutingCard exampleCard; private View testResultsContainer; + private ScrollView scrollView; + private OnGlobalLayoutListener onGlobalLayout; + private boolean isKeyboardShown = false; private ApplicationMode appMode; private OnlineRoutingEngineObject engine; + private OnlineRoutingEngineObject initEngine; private ExampleLocation selectedLocation; private String editedEngineKey; @@ -122,21 +142,32 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { mapActivity = getMapActivity(); helper = app.getOnlineRoutingHelper(); engine = new OnlineRoutingEngineObject(); + initEngine = new OnlineRoutingEngineObject(); if (savedInstanceState != null) { restoreState(savedInstanceState); } else { initState(); } + requireMyActivity().getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) { + public void handleOnBackPressed() { + MapActivity mapActivity = getMapActivity(); + if (mapActivity != null) { + showExitDialog(); + } + } + }); } + @SuppressLint("ClickableViewAccessibility") @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, - @Nullable ViewGroup container, - @Nullable Bundle savedInstanceState) { + @Nullable ViewGroup container, + @Nullable Bundle savedInstanceState) { view = getInflater().inflate( R.layout.online_routing_engine_fragment, container, false); segmentsContainer = (ViewGroup) view.findViewById(R.id.segments_container); + scrollView = (ScrollView) segmentsContainer.getParent(); if (Build.VERSION.SDK_INT >= 21) { AndroidUtils.addStatusBarPadding21v(getContext(), view); } @@ -153,11 +184,84 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { setupButtons(); updateCardViews(nameCard, typeCard, vehicleCard, exampleCard); + + scrollView.setOnTouchListener(new View.OnTouchListener() { + int scrollViewY = 0; + + @Override + public boolean onTouch(View v, MotionEvent event) { + int y = scrollView.getScrollY(); + if (isKeyboardShown && scrollViewY != y) { + scrollViewY = y; + View focus = mapActivity.getCurrentFocus(); + if (focus != null) { + AndroidUtils.hideSoftKeyboard(mapActivity, focus); + focus.clearFocus(); + } + } + return false; + } + }); + + onGlobalLayout = new ViewTreeObserver.OnGlobalLayoutListener() { + private int layoutHeightPrevious; + private int layoutHeightMin; + + @Override + public void onGlobalLayout() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + view.getViewTreeObserver().removeOnGlobalLayoutListener(this); + } else { + view.getViewTreeObserver().removeGlobalOnLayoutListener(this); + } + + Rect visibleDisplayFrame = new Rect(); + view.getWindowVisibleDisplayFrame(visibleDisplayFrame); + int layoutHeight = visibleDisplayFrame.bottom; + + if (layoutHeight < layoutHeightPrevious) { + isKeyboardShown = true; + layoutHeightMin = layoutHeight; + } else { + isKeyboardShown = layoutHeight == layoutHeightMin; + } + + if (layoutHeight != layoutHeightPrevious) { + FrameLayout.LayoutParams rootViewLayout = (FrameLayout.LayoutParams) view.getLayoutParams(); + rootViewLayout.height = layoutHeight; + view.requestLayout(); + layoutHeightPrevious = layoutHeight; + } + + view.post(new Runnable() { + @Override + public void run() { + view.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayout); + } + }); + + } + }; + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + view.getViewTreeObserver().addOnGlobalLayoutListener(onGlobalLayout); + } + return view; } + @Override + public void onDestroyView() { + super.onDestroyView(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + view.getViewTreeObserver().removeOnGlobalLayoutListener(onGlobalLayout); + } else { + view.getViewTreeObserver().removeGlobalOnLayoutListener(onGlobalLayout); + } + } + private void setupNameCard() { - nameCard = new OnlineRoutingCard(mapActivity, isNightMode()); + nameCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); nameCard.build(mapActivity); nameCard.setDescription(getString(R.string.select_nav_profile_dialog_message)); nameCard.setEditedText(engine.getName(app)); @@ -175,7 +279,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } private void setupTypeCard() { - typeCard = new OnlineRoutingCard(mapActivity, isNightMode()); + typeCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); typeCard.build(mapActivity); typeCard.setHeaderTitle(getString(R.string.shared_string_type)); List serverItems = new ArrayList<>(); @@ -210,7 +314,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } private void setupVehicleCard() { - vehicleCard = new OnlineRoutingCard(mapActivity, isNightMode()); + vehicleCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); vehicleCard.build(mapActivity); vehicleCard.setHeaderTitle(getString(R.string.shared_string_vehicle)); List vehicleItems = new ArrayList<>(); @@ -247,7 +351,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } private void setupApiKeyCard() { - apiKeyCard = new OnlineRoutingCard(mapActivity, isNightMode()); + apiKeyCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); apiKeyCard.build(mapActivity); apiKeyCard.setHeaderTitle(getString(R.string.shared_string_api_key)); apiKeyCard.setFieldBoxLabelText(getString(R.string.keep_it_empty_if_not)); @@ -264,7 +368,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } private void setupExampleCard() { - exampleCard = new OnlineRoutingCard(mapActivity, isNightMode()); + exampleCard = new OnlineRoutingCard(mapActivity, isNightMode(), appMode); exampleCard.build(mapActivity); exampleCard.setHeaderTitle(getString(R.string.shared_string_example)); List locationItems = new ArrayList<>(); @@ -284,7 +388,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { return false; } }); - exampleCard.setFieldBoxHelperText(getString(R.string.online_routing_example_hint)); + exampleCard.setDescription(getString(R.string.online_routing_example_hint)); + exampleCard.showFieldBox(); exampleCard.setButton(getString(R.string.test_route_calculation), new View.OnClickListener() { @Override public void onClick(View v) { @@ -315,7 +420,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { navigationIcon.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { - dismiss(); + showExitDialog(); } }); TextView title = toolbar.findViewById(R.id.toolbar_title); @@ -370,7 +475,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } else { vehicleCard.hideFieldBox(); } - + int contentPadding = getResources().getDimensionPixelSize(R.dimen.content_padding); + vehicleCard.updateBottomMarginSelectionMenu(engine.vehicleType != VehicleType.CUSTOM ? 0 : contentPadding); } else if (exampleCard.equals(card)) { exampleCard.setEditedText(getTestUrl()); } @@ -385,7 +491,7 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { cancelButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { - dismiss(); + showExitDialog(); } }); @@ -496,6 +602,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { outState.putString(ENGINE_VEHICLE_TYPE_KEY, engine.vehicleType.name()); outState.putString(ENGINE_CUSTOM_VEHICLE_KEY, engine.customVehicleKey); outState.putString(ENGINE_API_KEY_KEY, engine.apiKey); + outState.putString(INIT_ENGINE_NAME_KEY, initEngine.customName); + outState.putString(INIT_ENGINE_SERVER_KEY, initEngine.type.name()); + outState.putString(INIT_ENGINE_SERVER_URL_KEY, initEngine.customServerUrl); + outState.putString(INIT_ENGINE_VEHICLE_TYPE_KEY, initEngine.vehicleType.name()); + outState.putString(INIT_ENGINE_CUSTOM_VEHICLE_KEY, initEngine.customVehicleKey); + outState.putString(INIT_ENGINE_API_KEY_KEY, initEngine.apiKey); outState.putString(EXAMPLE_LOCATION_KEY, selectedLocation.name()); if (appMode != null) { outState.putString(APP_MODE_KEY, appMode.getStringKey()); @@ -510,6 +622,12 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { engine.vehicleType = VehicleType.valueOf(savedState.getString(ENGINE_VEHICLE_TYPE_KEY)); engine.customVehicleKey = savedState.getString(ENGINE_CUSTOM_VEHICLE_KEY); engine.apiKey = savedState.getString(ENGINE_API_KEY_KEY); + initEngine.customName = savedState.getString(INIT_ENGINE_NAME_KEY); + initEngine.type = EngineType.valueOf(savedState.getString(INIT_ENGINE_SERVER_KEY)); + initEngine.customServerUrl = savedState.getString(INIT_ENGINE_SERVER_URL_KEY); + initEngine.vehicleType = VehicleType.valueOf(savedState.getString(INIT_ENGINE_VEHICLE_TYPE_KEY)); + initEngine.customVehicleKey = savedState.getString(INIT_ENGINE_CUSTOM_VEHICLE_KEY); + initEngine.apiKey = savedState.getString(INIT_ENGINE_API_KEY_KEY); selectedLocation = ExampleLocation.valueOf(savedState.getString(EXAMPLE_LOCATION_KEY)); appMode = ApplicationMode.valueOfStringKey(savedState.getString(APP_MODE_KEY), null); editedEngineKey = savedState.getString(EDITED_ENGINE_KEY); @@ -536,15 +654,49 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { engine.apiKey = editedEngine.getParameter(EngineParameter.API_KEY); } } + engine.cloneIn(initEngine); } private void dismiss() { FragmentActivity activity = getActivity(); if (activity != null) { - activity.onBackPressed(); + FragmentManager fragmentManager = activity.getSupportFragmentManager(); + if (!fragmentManager.isStateSaved()) { + fragmentManager.popBackStack(); + } } } + public void showExitDialog() { + View focus = view.findFocus(); + AndroidUtils.hideSoftKeyboard(mapActivity, focus); + if (engine.customName != null && initEngine.customName == null) { + initEngine.customName = initEngine.getName(app); + } + if (!engine.equals(initEngine)) { + AlertDialog.Builder dismissDialog = createWarningDialog(mapActivity, + R.string.shared_string_dismiss, R.string.exit_without_saving, R.string.shared_string_cancel); + dismissDialog.setPositiveButton(R.string.shared_string_exit, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dismiss(); + } + }); + dismissDialog.show(); + } else { + dismiss(); + } + } + + private AlertDialog.Builder createWarningDialog(Activity activity, int title, int message, int negButton) { + Context themedContext = UiUtilities.getThemedContext(activity, isNightMode()); + AlertDialog.Builder warningDialog = new AlertDialog.Builder(themedContext); + warningDialog.setTitle(getString(title)); + warningDialog.setMessage(getString(message)); + warningDialog.setNegativeButton(negButton, null); + return warningDialog; + } + private boolean isNightMode() { return !app.getSettings().isLightContentForMode(appMode); } @@ -564,8 +716,8 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } public static void showInstance(@NonNull FragmentActivity activity, - @NonNull ApplicationMode appMode, - String editedEngineKey) { + @NonNull ApplicationMode appMode, + String editedEngineKey) { FragmentManager fm = activity.getSupportFragmentManager(); if (!fm.isStateSaved() && fm.findFragmentByTag(OnlineRoutingEngineFragment.TAG) == null) { OnlineRoutingEngineFragment fragment = new OnlineRoutingEngineFragment(); @@ -605,5 +757,28 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment { } return customServerUrl; } + + public void cloneIn(OnlineRoutingEngineObject clone) { + clone.customName = customName; + clone.type = type; + clone.customServerUrl = customServerUrl; + clone.vehicleType = vehicleType; + clone.customVehicleKey = customVehicleKey; + clone.apiKey = apiKey; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) return true; + if (obj == null || getClass() != obj.getClass()) return false; + + OnlineRoutingEngineObject engine = (OnlineRoutingEngineObject) obj; + if (!Algorithms.stringsEqual(customName, engine.customName)) return false; + if (type != engine.type) return false; + if (!Algorithms.stringsEqual(getBaseUrl(), engine.getBaseUrl())) return false; + if (vehicleType != engine.vehicleType) return false; + if (!Algorithms.stringsEqual(getVehicleKey(), engine.getVehicleKey())) return false; + return Algorithms.isEmpty(apiKey) ? Algorithms.isEmpty(engine.apiKey) : Algorithms.stringsEqual(apiKey, engine.apiKey); + } } }