diff --git a/android/app/src/main/java/app/organicmaps/sdk/search/SearchResult.java b/android/app/src/main/java/app/organicmaps/sdk/search/SearchResult.java index 2fdcf6861a..4c5ad8501d 100644 --- a/android/app/src/main/java/app/organicmaps/sdk/search/SearchResult.java +++ b/android/app/src/main/java/app/organicmaps/sdk/search/SearchResult.java @@ -2,6 +2,8 @@ package app.organicmaps.sdk.search; import android.content.Context; import android.graphics.Typeface; +import android.os.Parcel; +import android.os.Parcelable; import android.text.Spannable; import android.text.SpannableStringBuilder; import android.text.Spanned; @@ -20,7 +22,7 @@ import app.organicmaps.util.Distance; // Used by JNI. @Keep @SuppressWarnings("unused") -public class SearchResult +public class SearchResult implements Parcelable { public static final int TYPE_PURE_SUGGEST = 0; public static final int TYPE_SUGGEST = 1; @@ -37,7 +39,7 @@ public class SearchResult // Used by JNI. @Keep @SuppressWarnings("unused") - public static class Description + public static class Description implements Parcelable { public final FeatureId featureId; public final String localizedFeatureType; @@ -65,6 +67,54 @@ public class SearchResult this.minutesUntilClosed = minutesUntilClosed; this.hasPopularityHigherPriority = hasPopularityHigherPriority; } + + public static final Creator CREATOR = new Creator() + { + @Override + public Description createFromParcel(Parcel in) + { + return new Description(in); + } + + @Override + public Description[] newArray(int size) + { + return new Description[size]; + } + }; + + protected Description(Parcel in) + { + featureId = in.readParcelable(FeatureId.class.getClassLoader()); + localizedFeatureType = in.readString(); + region = in.readString(); + distance = in.readParcelable(Distance.class.getClassLoader()); + description = in.readString(); + openNow = in.readInt(); + minutesUntilOpen = in.readInt(); + minutesUntilClosed = in.readInt(); + hasPopularityHigherPriority = in.readByte() != 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeParcelable(featureId, flags); + dest.writeString(localizedFeatureType); + dest.writeString(region); + dest.writeParcelable(distance, flags); + dest.writeString(description); + dest.writeInt(openNow); + dest.writeInt(minutesUntilOpen); + dest.writeInt(minutesUntilClosed); + dest.writeByte((byte) (hasPopularityHigherPriority ? 1 : 0)); + } + + @Override + public int describeContents() + { + return 0; + } } public final String name; @@ -113,6 +163,19 @@ public class SearchResult this.descHighlightRanges = descHighlightRanges; } + protected SearchResult(Parcel in) + { + name = in.readString(); + suggestion = in.readString(); + lat = in.readDouble(); + lon = in.readDouble(); + type = in.readInt(); + description = in.readParcelable(Description.class.getClassLoader()); + highlightRanges = in.createIntArray(); + descHighlightRanges = in.createIntArray(); + mPopularity = in.readParcelable(Popularity.class.getClassLoader()); + } + @NonNull public String getTitle(@NonNull Context context) { @@ -157,4 +220,38 @@ public class SearchResult return builder; } -} + public static final Creator CREATOR = new Creator<>() + { + @Override + public SearchResult createFromParcel(Parcel in) + { + return new SearchResult(in); + } + + @Override + public SearchResult[] newArray(int size) + { + return new SearchResult[size]; + } + }; + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeString(name); + dest.writeString(suggestion); + dest.writeDouble(lat); + dest.writeDouble(lon); + dest.writeInt(type); + dest.writeParcelable(description, flags); + dest.writeIntArray(highlightRanges); + dest.writeIntArray(descHighlightRanges); + dest.writeParcelable(mPopularity, flags); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/search/SearchAdapter.java b/android/app/src/main/java/app/organicmaps/search/SearchAdapter.java index 261d86c44e..0728822627 100644 --- a/android/app/src/main/java/app/organicmaps/search/SearchAdapter.java +++ b/android/app/src/main/java/app/organicmaps/search/SearchAdapter.java @@ -256,6 +256,11 @@ class SearchAdapter extends RecyclerView.Adapter mHiddenCommands = new ArrayList<>(); @@ -123,7 +126,11 @@ public class SearchFragment extends BaseMwmFragment } mViewModel.setIsQueryEmpty(false); - runSearch(); + + if (wereResultsRestored) + wereResultsRestored = false; + else + runSearch(); } @Override @@ -254,7 +261,7 @@ public class SearchFragment extends BaseMwmFragment | AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL : 0); toolbar.setLayoutParams(lp); - UiUtils.showIf(hasQuery, mResultsFrame); + UiUtils.showIf(wereResultsRestored || hasQuery, mResultsFrame); UiUtils.showIf(!mIsModal && hasQuery, mShowOnMapFab); if (hasQuery) hideDownloadSuggest(); @@ -268,7 +275,7 @@ public class SearchFragment extends BaseMwmFragment { final boolean show = !mSearchRunning && mSearchAdapter.getItemCount() == 0 - && mToolbarController.hasQuery(); + && (wereResultsRestored || mToolbarController.hasQuery()); UiUtils.showIf(show, mResultsPlaceholder); } @@ -325,6 +332,16 @@ public class SearchFragment extends BaseMwmFragment mResults.setLayoutManager(new LinearLayoutManager(view.getContext())); mResults.setAdapter(mSearchAdapter); + if (savedInstanceState != null) + { + SearchResult[] savedSearchResults = (SearchResult[]) savedInstanceState.getParcelableArray(STATE_KEY_RESULTS); + if (savedSearchResults != null) + { + wereResultsRestored = true; + mSearchAdapter.refreshData(savedSearchResults); + } + } + updateFrames(); updateResultsPlaceholder(); ViewCompat.setOnApplyWindowInsetsListener( @@ -382,6 +399,14 @@ public class SearchFragment extends BaseMwmFragment mToolbarController.detach(); } + @Override + public void onSaveInstanceState(@NonNull Bundle outState) + { + super.onSaveInstanceState(outState); + if (!mSearchRunning) + outState.putParcelableArray(STATE_KEY_RESULTS, mSearchAdapter.getResults()); + } + @Override public void onDestroy() { diff --git a/android/app/src/main/java/app/organicmaps/util/Distance.java b/android/app/src/main/java/app/organicmaps/util/Distance.java index 0848fb9bf1..9dad3814ae 100644 --- a/android/app/src/main/java/app/organicmaps/util/Distance.java +++ b/android/app/src/main/java/app/organicmaps/util/Distance.java @@ -1,6 +1,8 @@ package app.organicmaps.util; import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; import androidx.annotation.Keep; import androidx.annotation.NonNull; @@ -11,7 +13,7 @@ import app.organicmaps.R; // Used by JNI. @Keep @SuppressWarnings("unused") -public final class Distance +public final class Distance implements Parcelable { public static final Distance EMPTY = new Distance(0.0, "", (byte) 0); @@ -50,6 +52,13 @@ public final class Distance mUnits = Units.values()[unitsIndex]; } + protected Distance(Parcel in) + { + mDistance = in.readDouble(); + mDistanceStr = in.readString(); + mUnits = Units.values()[in.readByte()]; + } + public boolean isValid() { return mDistance >= 0.0; @@ -70,6 +79,21 @@ public final class Distance return mDistanceStr + NON_BREAKING_SPACE + getUnitsStr(context); } + public static final Creator CREATOR = new Creator() + { + @Override + public Distance createFromParcel(Parcel in) + { + return new Distance(in); + } + + @Override + public Distance[] newArray(int size) + { + return new Distance[size]; + } + }; + @NonNull @Override public String toString() @@ -79,4 +103,18 @@ public final class Distance return mDistanceStr + NON_BREAKING_SPACE + mUnits.toString(); } -} + + @Override + public int describeContents() + { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) + { + dest.writeDouble(mDistance); + dest.writeString(mDistanceStr); + dest.writeByte((byte) mUnits.ordinal()); + } +} \ No newline at end of file diff --git a/android/app/src/main/java/app/organicmaps/widget/modalsearch/ModalSearchController.java b/android/app/src/main/java/app/organicmaps/widget/modalsearch/ModalSearchController.java index 7c73d279f5..d72427aeb3 100644 --- a/android/app/src/main/java/app/organicmaps/widget/modalsearch/ModalSearchController.java +++ b/android/app/src/main/java/app/organicmaps/widget/modalsearch/ModalSearchController.java @@ -33,10 +33,12 @@ import app.organicmaps.util.InputUtils; public class ModalSearchController extends Fragment { private static final String SEARCH_FRAGMENT_TAG = SearchFragment.class.getSimpleName(); + private static final int FALLBACK_COLLAPSED_HEIGHT = 200; private SearchBottomSheetBehavior mSearchBehavior; private NestedScrollView mModalSearch; private ViewGroup mCoordinator; private int mViewportMinHeight; + private int mCollapsedHeight = FALLBACK_COLLAPSED_HEIGHT; private ModalSearchViewModel mViewModel; private final Observer mModalSearchSuspendedObserver = suspended -> { if (Boolean.FALSE.equals(mViewModel.getModalSearchActive().getValue())) @@ -235,12 +237,13 @@ public class ModalSearchController extends Fragment { try { - return mDragIndicator.getMeasuredHeight() + + int calculatedHeight = mDragIndicator.getMeasuredHeight() + mModalSearch.findViewById(R.id.app_bar).getMeasuredHeight(); // TODO(savsch) get feedback on whether to change this height - } catch (NullPointerException npe) - { - return 0; - } + if (calculatedHeight > 0) + mCollapsedHeight = calculatedHeight; + } catch (NullPointerException ignored) + {} + return mCollapsedHeight; } private void removeModalSearchFragments()