diff --git a/app/build.gradle b/app/build.gradle index 9f3f88c8..1c89b235 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -76,14 +76,15 @@ dependencies { androidTestImplementation 'androidx.test.ext:junit:1.1.5' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test:rules:1.5.0' + implementation "androidx.fragment:fragment:1.6.2" implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.recyclerview:recyclerview:1.3.2' implementation "androidx.preference:preference:1.2.1" implementation "androidx.work:work-runtime:2.9.0" implementation 'androidx.core:core-splashscreen:1.0.1' implementation 'com.google.code.findbugs:jsr305:3.0.2' - implementation 'androidx.annotation:annotation:1.7.0' - implementation 'com.google.android.material:material:1.10.0' + implementation 'androidx.annotation:annotation:1.7.1' + implementation 'com.google.android.material:material:1.11.0' implementation 'com.github.andreynovikov:androidcolorpicker:v0.0.3' implementation 'com.github.andreynovikov:Geo-Coordinate-Conversion-Java:v1.0.0' implementation 'com.caverock:androidsvg:1.4' diff --git a/app/src/main/java/mobi/maptrek/MainActivity.java b/app/src/main/java/mobi/maptrek/MainActivity.java index 73578575..ada0f22c 100644 --- a/app/src/main/java/mobi/maptrek/MainActivity.java +++ b/app/src/main/java/mobi/maptrek/MainActivity.java @@ -52,7 +52,7 @@ import android.os.Message; import android.os.SystemClock; -import androidx.activity.result.ActivityResultCallback; +import androidx.activity.OnBackPressedCallback; import androidx.activity.result.ActivityResultLauncher; import androidx.activity.result.contract.ActivityResultContracts; import androidx.annotation.DrawableRes; @@ -194,7 +194,6 @@ import mobi.maptrek.fragments.MapList; import mobi.maptrek.fragments.MapSelection; import mobi.maptrek.fragments.MarkerInformation; -import mobi.maptrek.fragments.OnBackPressedListener; import mobi.maptrek.fragments.OnFeatureActionListener; import mobi.maptrek.fragments.OnLocationListener; import mobi.maptrek.fragments.OnMapActionListener; @@ -279,7 +278,6 @@ public class MainActivity extends AppCompatActivity implements ILocationListener MapTrekTileLayer.OnAmenityGestureListener, PopupMenu.OnMenuItemClickListener, LoaderManager.LoaderCallbacks>, - FragmentManager.OnBackStackChangedListener, AmenitySetupDialog.AmenitySetupDialogCallback, SafeResultReceiver.Callback { private static final Logger logger = LoggerFactory.getLogger(MainActivity.class); @@ -472,7 +470,7 @@ protected void onCreate(Bundle savedInstanceState) { // find the retained fragment on activity restarts mFragmentManager = getSupportFragmentManager(); - mFragmentManager.addOnBackStackChangedListener(this); + mFragmentManager.registerFragmentLifecycleCallbacks(mFragmentLifecycleCallback, true); mNativeMapIndex = application.getMapIndex(); mMapIndex = application.getExtraMapIndex(); @@ -907,6 +905,8 @@ protected void onStart() { resultReceiver.setCallback(this); mResultReceiver = new WeakReference<>(resultReceiver); + getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); + mBackPressedCallback.setEnabled(mFragmentManager.getBackStackEntryCount() == 0); MapTrek.isMainActivityRunning = true; } @@ -1037,6 +1037,7 @@ protected void onStop() { logger.debug("onStop()"); MapTrek.isMainActivityRunning = false; + mBackPressedCallback.remove(); mResultReceiver.get().setCallback(null); @@ -1134,6 +1135,7 @@ public void onSaveInstanceState(@NonNull Bundle savedInstanceState) { savedInstanceState.putInt("progressBar", mViews.progressBar.getMax()); savedInstanceState.putSerializable("panelState", mPanelState); savedInstanceState.putBoolean("autoTiltShouldSet", mAutoTiltShouldSet); + savedInstanceState.putBoolean("baseMapWarningShown", mBaseMapWarningShown); super.onSaveInstanceState(savedInstanceState); } @@ -1153,6 +1155,7 @@ public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) { mViews.progressBar.setMax(savedInstanceState.getInt("progressBar")); } mAutoTiltShouldSet = savedInstanceState.getBoolean("autoTiltShouldSet"); + mBaseMapWarningShown = savedInstanceState.getBoolean("baseMapWarningShown"); setPanelState((PANEL_STATE) savedInstanceState.getSerializable("panelState")); } @@ -1347,7 +1350,6 @@ public boolean onMenuItemClick(MenuItem item) { ft.replace(R.id.contentPanel, fragment, "ruler"); ft.addToBackStack("ruler"); ft.commit(); - mCrosshairLayer.lock(Color.RED); return true; } else if (action == R.id.actionAddGauge) { mViews.gaugePanel.onLongClick(mViews.gaugePanel); @@ -3460,10 +3462,8 @@ private void showExtendPanel(PANEL_STATE panel, String name, Fragment fragment) FragmentManager.BackStackEntry bse = mFragmentManager.getBackStackEntryAt(0); //TODO Make it properly work without "immediate" - that is why exit transitions do not work mFragmentManager.popBackStackImmediate(bse.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE); - if (name.equals(bse.getName())) { - setPanelState(PANEL_STATE.NONE); + if (name.equals(bse.getName())) return; - } } mViews.extendPanel.setForeground(null); @@ -3589,8 +3589,6 @@ private void setPanelState(PANEL_STATE state) { mPanelState = state; } - private final Set> mBackListeners = new HashSet<>(); - @Override public FloatingActionButton enableActionButton() { if (mViews.listActionButton.getVisibility() == View.VISIBLE) @@ -3619,37 +3617,9 @@ public void disableListActionButton() { mViews.listActionButton.setVisibility(View.GONE); } - @Override - public void addBackClickListener(OnBackPressedListener listener) { - mBackListeners.add(new WeakReference<>(listener)); - } - - @Override - public void removeBackClickListener(OnBackPressedListener listener) { - for (Iterator> iterator = mBackListeners.iterator(); - iterator.hasNext(); ) { - WeakReference weakRef = iterator.next(); - if (weakRef.get() == listener) { - iterator.remove(); - } - } - } - @Override public void popCurrent() { logger.debug("popCurrent()"); - int count = mFragmentManager.getBackStackEntryCount(); - if (count > 0) { - FragmentManager.BackStackEntry bse = mFragmentManager.getBackStackEntryAt(count - 1); - String fragmentName = bse.getName(); - if ("baseMapDownload".equals(fragmentName)) { - if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - HelperUtils.showTargetedAdvice(MainActivity.this, Configuration.ADVICE_ENABLE_LOCATIONS, R.string.advice_enable_locations, mViews.locationButton, false); - } - } else if ("trackProperties".equals(fragmentName)) { - HelperUtils.showTargetedAdvice(this, Configuration.ADVICE_RECORDED_TRACKS, R.string.advice_recorded_tracks, mViews.recordButton, false); - } - } mFragmentManager.popBackStack(); } @@ -3665,73 +3635,98 @@ public CoordinatorLayout getCoordinatorLayout() { return mViews.coordinatorLayout; } - private boolean backKeyIntercepted() { - boolean intercepted = false; - for (WeakReference weakRef : mBackListeners) { - OnBackPressedListener onBackClickListener = weakRef.get(); - if (onBackClickListener != null) { - boolean isFragIntercept = onBackClickListener.onBackClick(); - if (!intercepted) - intercepted = isFragIntercept; - } - } - return intercepted; - } + private final OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(false) { + final Handler mBackHandler = new Handler(); - final Handler mBackHandler = new Handler(); - - @Override - public void onBackPressed() { - logger.debug("onBackPressed()"); - if (backKeyIntercepted()) - return; - - int count = mFragmentManager.getBackStackEntryCount(); - if (count > 0) { - FragmentManager.BackStackEntry bse = mFragmentManager.getBackStackEntryAt(count - 1); - String name = bse.getName(); - if ("ruler".equals(name)) - mCrosshairLayer.unlock(); - else if ("settings".equals(name)) - HelperUtils.showTargetedAdvice(this, Configuration.ADVICE_MAP_SETTINGS, R.string.advice_map_settings, mViews.mapsButton, false); - else if ("trackProperties".equals(name)) - HelperUtils.showTargetedAdvice(this, Configuration.ADVICE_RECORDED_TRACKS, R.string.advice_recorded_tracks, mViews.recordButton, false); - super.onBackPressed(); - if (count == 1 && mPanelState != PANEL_STATE.NONE) - setPanelState(PANEL_STATE.NONE); - } else { + @Override + public void handleOnBackPressed() { if (secondBack) { mBackToast.cancel(); - finish(); + this.setEnabled(false); + getOnBackPressedDispatcher().onBackPressed(); } else { secondBack = true; mBackToast.show(); mBackHandler.postDelayed(() -> secondBack = false, 2000); } } - } + }; - @SuppressLint("UseCompatLoadingForDrawables") - @Override - public void onBackStackChanged() { - logger.debug("onBackStackChanged()"); - int count = mFragmentManager.getBackStackEntryCount(); - if (count == 0) { - if (mPanelState != PANEL_STATE.NONE) + private final FragmentManager.FragmentLifecycleCallbacks mFragmentLifecycleCallback = new FragmentManager.FragmentLifecycleCallbacks() { + @Override + public void onFragmentPreAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) { + logger.error("onFragmentPreAttached({})", f.getClass().getName()); + } + + @Override + public void onFragmentAttached(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Context context) { + logger.error("onFragmentAttached({})", f.getClass().getName()); + mBackPressedCallback.setEnabled(false); + } + + @Override + public void onFragmentPreCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @Nullable Bundle savedInstanceState) { + logger.error("onFragmentPreCreated({})", f.getClass().getName()); + } + + @Override + public void onFragmentCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @Nullable Bundle savedInstanceState) { + logger.error("onFragmentCreated({})", f.getClass().getName()); + } + + @Override + public void onFragmentViewCreated(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull View v, @Nullable Bundle savedInstanceState) { + logger.error("onFragmentViewCreated({})", f.getClass().getName()); + } + + @Override + public void onFragmentStarted(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentStarted({})", f.getClass().getName()); + } + + @Override + public void onFragmentResumed(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentResumed({})", f.getClass().getName()); + if (f.getClass() == Ruler.class) + mCrosshairLayer.lock(Color.RED); + } + + @Override + public void onFragmentPaused(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentPaused({})", f.getClass().getName()); + if (f.getClass() == Ruler.class) + mCrosshairLayer.unlock(); + } + + @Override + public void onFragmentStopped(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentStopped({})", f.getClass().getName()); + if (mFragmentManager.getBackStackEntryCount() == 0 && mPanelState != PANEL_STATE.NONE) setPanelState(PANEL_STATE.NONE); - return; } - FragmentManager.BackStackEntry bse = mFragmentManager.getBackStackEntryAt(count - 1); - Fragment f = mFragmentManager.findFragmentByTag(bse.getName()); - if (f == null) - return; - View v = f.getView(); - if (v == null) - return; - final ViewGroup p = (ViewGroup) v.getParent(); - if (p.getForeground() != null) { - p.setForeground(getDrawable(R.drawable.dim)); - p.getForeground().setAlpha(0); + + @Override + public void onFragmentSaveInstanceState(@NonNull FragmentManager fm, @NonNull Fragment f, @NonNull Bundle outState) { + logger.error("onFragmentSaveInstanceState({})", f.getClass().getName()); + } + + @Override + public void onFragmentViewDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentViewDestroyed({})", f.getClass().getName()); + + int count = mFragmentManager.getBackStackEntryCount(); + if (count == 0) + return; + FragmentManager.BackStackEntry bse = mFragmentManager.getBackStackEntryAt(count - 1); + Fragment fr = mFragmentManager.findFragmentByTag(bse.getName()); + if (fr == null) + return; + View fv = fr.getView(); + if (fv == null) + return; + final ViewGroup p = (ViewGroup) fv.getParent(); + if (p == null || p.getForeground() == null) + return; ObjectAnimator anim = ObjectAnimator.ofInt(p.getForeground(), "alpha", 255, 0); anim.addListener(new Animator.AnimatorListener() { @Override @@ -3755,7 +3750,45 @@ public void onAnimationRepeat(@NonNull Animator animation) { anim.setDuration(500); anim.start(); } - } + + @Override + public void onFragmentDestroyed(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentDestroyed({})", f.getClass().getName()); + } + + @Override + public void onFragmentDetached(@NonNull FragmentManager fm, @NonNull Fragment f) { + logger.error("onFragmentDetached({})", f.getClass().getName()); + mBackPressedCallback.setEnabled(mFragmentManager.getBackStackEntryCount() == 0); + + Class cls = f.getClass(); + if (cls == BaseMapDownload.class) { + if (checkSelfPermission(Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) + HelperUtils.showTargetedAdvice( + MainActivity.this, + Configuration.ADVICE_ENABLE_LOCATIONS, + R.string.advice_enable_locations, + mViews.locationButton, + false + ); + } else if (cls == Settings.class) + HelperUtils.showTargetedAdvice( + MainActivity.this, + Configuration.ADVICE_MAP_SETTINGS, + R.string.advice_map_settings, + mViews.mapsButton, + false + ); + else if (cls == TrackProperties.class) + HelperUtils.showTargetedAdvice( + MainActivity.this, + Configuration.ADVICE_RECORDED_TRACKS, + R.string.advice_recorded_tracks, + mViews.recordButton, + false + ); + } + }; private void hideDownloadButton() { if (mViews.mapDownloadButton.getVisibility() == View.VISIBLE) { diff --git a/app/src/main/java/mobi/maptrek/fragments/AmenityInformation.java b/app/src/main/java/mobi/maptrek/fragments/AmenityInformation.java index 45f0bcde..b89b700b 100644 --- a/app/src/main/java/mobi/maptrek/fragments/AmenityInformation.java +++ b/app/src/main/java/mobi/maptrek/fragments/AmenityInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -25,6 +25,7 @@ import android.net.Uri; import android.os.Bundle; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; @@ -64,7 +65,7 @@ import mobi.maptrek.util.ResUtils; import mobi.maptrek.util.StringFormatter; -public class AmenityInformation extends Fragment implements OnBackPressedListener, LocationChangeListener { +public class AmenityInformation extends Fragment implements LocationChangeListener { public static final String ARG_LATITUDE = "lat"; public static final String ARG_LONGITUDE = "lon"; public static final String ARG_LANG = "lang"; @@ -174,17 +175,17 @@ public void onAttach(@NonNull Context context) { } try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); + mBackPressedCallback.remove(); mMapHolder.removeMarker(); - mFragmentHolder.removeBackClickListener(this); mFragmentHolder = null; mMapHolder = null; } @@ -391,12 +392,6 @@ private void updatePeekHeight(ViewGroup rootView, boolean setState) { mBottomSheetBehavior.setState(mBottomSheetBehavior.getState()); } - @Override - public boolean onBackClick() { - mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - return true; - } - @Override public void onLocationChanged(Location location) { updateAmenityInformation(location.getLatitude(), location.getLongitude()); @@ -406,6 +401,13 @@ public void setPreferredLanguage(String lang) { mLang = MapTrekDatabaseHelper.getLanguageId(lang); } + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + } + }; + private class AmenityBottomSheetCallback extends BottomSheetBehavior.BottomSheetCallback { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { diff --git a/app/src/main/java/mobi/maptrek/fragments/BaseMapDownload.java b/app/src/main/java/mobi/maptrek/fragments/BaseMapDownload.java index 8e4421a0..36ffdfd5 100644 --- a/app/src/main/java/mobi/maptrek/fragments/BaseMapDownload.java +++ b/app/src/main/java/mobi/maptrek/fragments/BaseMapDownload.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -25,6 +25,7 @@ import android.view.ViewGroup; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; @@ -33,7 +34,7 @@ import mobi.maptrek.R; import mobi.maptrek.maps.maptrek.Index; -public class BaseMapDownload extends Fragment implements OnBackPressedListener { +public class BaseMapDownload extends Fragment { private FragmentHolder mFragmentHolder; private Index mMapIndex; private TextView mMessageView; @@ -69,27 +70,29 @@ public void onAttach(@NonNull Context context) { super.onAttach(context); try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); - mFragmentHolder.removeBackClickListener(this); + mBackPressedCallback.remove(); mFragmentHolder = null; } - @Override - public boolean onBackClick() { - mFragmentHolder.disableActionButton(); - return false; - } - public void setMapIndex(Index mapIndex) { mMapIndex = mapIndex; } + private final OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + mFragmentHolder.disableActionButton(); + this.remove(); + requireActivity().getOnBackPressedDispatcher().onBackPressed(); + } + }; } diff --git a/app/src/main/java/mobi/maptrek/fragments/CrashReport.java b/app/src/main/java/mobi/maptrek/fragments/CrashReport.java index a118eb82..3b86f73a 100644 --- a/app/src/main/java/mobi/maptrek/fragments/CrashReport.java +++ b/app/src/main/java/mobi/maptrek/fragments/CrashReport.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -27,6 +27,7 @@ import android.view.View; import android.view.ViewGroup; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; @@ -39,7 +40,7 @@ import mobi.maptrek.R; import mobi.maptrek.provider.ExportProvider; -public class CrashReport extends Fragment implements OnBackPressedListener { +public class CrashReport extends Fragment { private FragmentHolder mFragmentHolder; public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -87,22 +88,25 @@ public void onAttach(@NonNull Context context) { super.onAttach(context); try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); - mFragmentHolder.removeBackClickListener(this); + mBackPressedCallback.remove(); mFragmentHolder = null; } - @Override - public boolean onBackClick() { - mFragmentHolder.disableActionButton(); - return false; - } + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + mFragmentHolder.disableActionButton(); + this.remove(); + requireActivity().getOnBackPressedDispatcher().onBackPressed(); + } + }; } diff --git a/app/src/main/java/mobi/maptrek/fragments/FragmentHolder.java b/app/src/main/java/mobi/maptrek/fragments/FragmentHolder.java index f76cf3ff..085cf549 100644 --- a/app/src/main/java/mobi/maptrek/fragments/FragmentHolder.java +++ b/app/src/main/java/mobi/maptrek/fragments/FragmentHolder.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -28,10 +28,6 @@ public interface FragmentHolder { void disableListActionButton(); - void addBackClickListener(OnBackPressedListener listener); - - void removeBackClickListener(OnBackPressedListener listener); - void popCurrent(); void popAll(); diff --git a/app/src/main/java/mobi/maptrek/fragments/MapSelection.java b/app/src/main/java/mobi/maptrek/fragments/MapSelection.java index 05825ee0..52e4f7df 100644 --- a/app/src/main/java/mobi/maptrek/fragments/MapSelection.java +++ b/app/src/main/java/mobi/maptrek/fragments/MapSelection.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -33,6 +33,7 @@ import android.widget.ImageButton; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -58,7 +59,7 @@ import mobi.maptrek.maps.maptrek.Index; import mobi.maptrek.util.HelperUtils; -public class MapSelection extends Fragment implements OnBackPressedListener, Index.MapStateListener { +public class MapSelection extends Fragment implements Index.MapStateListener { private static final Logger logger = LoggerFactory.getLogger(MapSelection.class); private static final long INDEX_CACHE_TIMEOUT = 24 * 3600 * 1000L; // One day @@ -176,7 +177,6 @@ public void onAttach(@NonNull Context context) { } try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } @@ -187,13 +187,14 @@ public void onAttach(@NonNull Context context) { mHillshadeCacheFile = new File(cacheDir, "hillshadeIndex"); mMapIndex.addMapStateListener(this); + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); + mBackPressedCallback.remove(); mMapIndex.removeMapStateListener(this); - mFragmentHolder.removeBackClickListener(this); mFragmentHolder = null; mListener = null; mResources = null; @@ -204,12 +205,15 @@ public void onSaveInstanceState(@NonNull Bundle outState) { super.onSaveInstanceState(outState); } - @Override - public boolean onBackClick() { - mFragmentHolder.disableActionButton(); - mListener.onFinishMapManagement(); - return false; - } + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + mFragmentHolder.disableActionButton(); + mListener.onFinishMapManagement(); + this.remove(); + requireActivity().getOnBackPressedDispatcher().onBackPressed(); + } + }; @Override public void onMapSelected(final int x, final int y, Index.ACTION action, Index.IndexStats stats) { diff --git a/app/src/main/java/mobi/maptrek/fragments/MarkerInformation.java b/app/src/main/java/mobi/maptrek/fragments/MarkerInformation.java index 26974975..048e074a 100644 --- a/app/src/main/java/mobi/maptrek/fragments/MarkerInformation.java +++ b/app/src/main/java/mobi/maptrek/fragments/MarkerInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -18,12 +18,15 @@ import android.content.Context; import android.os.Bundle; + +import com.google.android.material.bottomsheet.BottomSheetBehavior; import com.google.android.material.floatingactionbutton.FloatingActionButton; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; @@ -36,7 +39,7 @@ import mobi.maptrek.R; import mobi.maptrek.util.StringFormatter; -public class MarkerInformation extends Fragment implements OnBackPressedListener { +public class MarkerInformation extends Fragment { public static final String ARG_LATITUDE = "latitude"; public static final String ARG_LONGITUDE = "longitude"; public static final String ARG_NAME = "name"; @@ -116,17 +119,17 @@ public void onAttach(@NonNull Context context) { } try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); + mBackPressedCallback.remove(); mMapHolder.removeMarker(); - mFragmentHolder.removeBackClickListener(this); mFragmentHolder = null; mListener = null; mMapHolder = null; @@ -140,9 +143,12 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putString(ARG_NAME, mName); } - @Override - public boolean onBackClick() { - mFragmentHolder.disableActionButton(); - return false; - } + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + mFragmentHolder.disableActionButton(); + this.remove(); + requireActivity().getOnBackPressedDispatcher().onBackPressed(); + } + }; } diff --git a/app/src/main/java/mobi/maptrek/fragments/OnBackPressedListener.java b/app/src/main/java/mobi/maptrek/fragments/OnBackPressedListener.java deleted file mode 100644 index da6d40a7..00000000 --- a/app/src/main/java/mobi/maptrek/fragments/OnBackPressedListener.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2018 Andrey Novikov - * - * This program is free software: you can redistribute it and/or modify it under the - * terms of the GNU Lesser General Public License as published by the Free Software - * Foundation, either version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT ANY - * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A - * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License along with - * this program. If not, see . - * - */ - -package mobi.maptrek.fragments; - -public interface OnBackPressedListener { - /** - * Called when back button is pressed - * @return true if fragment wants to handle back press - */ - boolean onBackClick(); -} diff --git a/app/src/main/java/mobi/maptrek/fragments/Ruler.java b/app/src/main/java/mobi/maptrek/fragments/Ruler.java index 4d12db37..b8665ae6 100644 --- a/app/src/main/java/mobi/maptrek/fragments/Ruler.java +++ b/app/src/main/java/mobi/maptrek/fragments/Ruler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -18,7 +18,6 @@ import android.content.Context; import android.os.Bundle; -import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; @@ -142,7 +141,6 @@ public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle sa @Override public void onAttach(@NonNull Context context) { super.onAttach(context); - Log.e("R", "onAttach"); try { mMapHolder = (MapHolder) context; } catch (ClassCastException e) { @@ -155,7 +153,7 @@ public void onStart() { super.onStart(); mRouteLayer = new RouteLayer(mMapHolder.getMap(), Color.RED, 5, mRoute); mMapHolder.getMap().layers().add(mRouteLayer); - Bitmap bitmap = new AndroidBitmap(MarkerFactory.getMarkerSymbol(getContext(), R.drawable.dot_black, Color.RED)); + Bitmap bitmap = new AndroidBitmap(MarkerFactory.getMarkerSymbol(requireContext(), R.drawable.dot_black, Color.RED)); MarkerSymbol symbol = new MarkerSymbol(bitmap, MarkerItem.HotspotPlace.CENTER); ArrayList items = new ArrayList<>(mRoute.length()); for (GeoPoint point : mRoute.getCoordinates()) { @@ -193,7 +191,6 @@ public void onStop() { @Override public void onDetach() { super.onDetach(); - Log.e("R", "onDetach"); mMapHolder = null; } diff --git a/app/src/main/java/mobi/maptrek/fragments/TrackInformation.java b/app/src/main/java/mobi/maptrek/fragments/TrackInformation.java index c7d46d90..06aa3c3b 100644 --- a/app/src/main/java/mobi/maptrek/fragments/TrackInformation.java +++ b/app/src/main/java/mobi/maptrek/fragments/TrackInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -39,6 +39,7 @@ import android.widget.PopupMenu; import android.widget.TextView; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.appcompat.content.res.AppCompatResources; @@ -71,7 +72,7 @@ import mobi.maptrek.util.MeanValue; import mobi.maptrek.util.StringFormatter; -public class TrackInformation extends Fragment implements PopupMenu.OnMenuItemClickListener, OnBackPressedListener { +public class TrackInformation extends Fragment implements PopupMenu.OnMenuItemClickListener { private Track mTrack; private boolean mIsCurrent; @@ -186,10 +187,10 @@ public void onAttach(@NonNull Context context) { } try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override @@ -208,7 +209,7 @@ public void onDestroy() { @Override public void onDetach() { super.onDetach(); - mFragmentHolder.removeBackClickListener(this); + mBackPressedCallback.remove(); mFragmentHolder = null; mMapHolder = null; mListener = null; @@ -498,17 +499,15 @@ private void setEditorMode(boolean enabled) { colorSwatch.setVisibility(editsState); mEditorMode = enabled; + mBackPressedCallback.setEnabled(enabled); } - @Override - public boolean onBackClick() { - if (mEditorMode) { + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(false) { + @Override + public void handleOnBackPressed() { setEditorMode(false); - return true; - } else { - return false; } - } + }; private final ServiceConnection mTrackingConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder service) { diff --git a/app/src/main/java/mobi/maptrek/fragments/WaypointInformation.java b/app/src/main/java/mobi/maptrek/fragments/WaypointInformation.java index bac1cd56..cb7361f4 100644 --- a/app/src/main/java/mobi/maptrek/fragments/WaypointInformation.java +++ b/app/src/main/java/mobi/maptrek/fragments/WaypointInformation.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -25,6 +25,8 @@ import android.location.Location; import android.net.Uri; import android.os.Bundle; + +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import com.google.android.material.bottomsheet.BottomSheetBehavior; @@ -70,7 +72,7 @@ import mobi.maptrek.util.StringFormatter; import mobi.maptrek.view.LimitedWebView; -public class WaypointInformation extends Fragment implements OnBackPressedListener, LocationChangeListener { +public class WaypointInformation extends Fragment implements LocationChangeListener { public static final String ARG_LATITUDE = "lat"; public static final String ARG_LONGITUDE = "lon"; public static final String ARG_DETAILS = "details"; @@ -230,17 +232,17 @@ public void onAttach(@NonNull Context context) { } try { mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); } catch (ClassCastException e) { throw new ClassCastException(context + " must implement FragmentHolder"); } + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); + mBackPressedCallback.remove(); mListener.onWaypointFocus(null); - mFragmentHolder.removeBackClickListener(this); mFragmentHolder = null; mListener = null; mMapHolder = null; @@ -505,21 +507,22 @@ private void updatePeekHeight(ViewGroup rootView, boolean setState) { mBottomSheetBehavior.setState(mBottomSheetBehavior.getState()); } - @Override - public boolean onBackClick() { - if (mEditorMode) - setEditorMode(false); - else - mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); - return true; - } - @Override public void onLocationChanged(Location location) { if (!mEditorMode) updateWaypointInformation(location.getLatitude(), location.getLongitude()); } + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + if (mEditorMode) + setEditorMode(false); + else + mBottomSheetBehavior.setState(BottomSheetBehavior.STATE_HIDDEN); + } + }; + private class WaypointBottomSheetCallback extends BottomSheetBehavior.BottomSheetCallback { @Override public void onStateChanged(@NonNull View bottomSheet, int newState) { diff --git a/app/src/main/java/mobi/maptrek/fragments/WaypointProperties.java b/app/src/main/java/mobi/maptrek/fragments/WaypointProperties.java index bc3f7a25..112728c4 100644 --- a/app/src/main/java/mobi/maptrek/fragments/WaypointProperties.java +++ b/app/src/main/java/mobi/maptrek/fragments/WaypointProperties.java @@ -1,5 +1,5 @@ /* - * Copyright 2022 Andrey Novikov + * Copyright 2023 Andrey Novikov * * This program is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free Software @@ -24,6 +24,7 @@ import android.view.inputmethod.EditorInfo; import android.widget.EditText; +import androidx.activity.OnBackPressedCallback; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; @@ -33,7 +34,7 @@ import mobi.maptrek.R; import mobi.maptrek.data.style.MarkerStyle; -public class WaypointProperties extends Fragment implements OnBackPressedListener { +public class WaypointProperties extends Fragment { public static final String ARG_NAME = "name"; public static final String ARG_COLOR = "color"; @@ -101,13 +102,13 @@ public void onAttach(@NonNull Context context) { throw new ClassCastException(context + " must implement OnWaypointPropertiesChangedListener"); } mFragmentHolder = (FragmentHolder) context; - mFragmentHolder.addBackClickListener(this); + requireActivity().getOnBackPressedDispatcher().addCallback(this, mBackPressedCallback); } @Override public void onDetach() { super.onDetach(); - mFragmentHolder.removeBackClickListener(this); + mBackPressedCallback.remove(); mFragmentHolder = null; mListener = null; } @@ -119,12 +120,6 @@ public void onSaveInstanceState(@NonNull Bundle outState) { outState.putInt(ARG_COLOR, mColorSwatch.getColor()); } - @Override - public boolean onBackClick() { - returnResult(); - return false; - } - private void returnResult() { String name = mNameEdit.getText().toString(); int color = mColorSwatch.getColor(); @@ -135,6 +130,15 @@ private void returnResult() { } } + OnBackPressedCallback mBackPressedCallback = new OnBackPressedCallback(true) { + @Override + public void handleOnBackPressed() { + returnResult(); + this.remove(); + requireActivity().getOnBackPressedDispatcher().onBackPressed(); + } + }; + public interface OnWaypointPropertiesChangedListener { void onWaypointPropertiesChanged(String name, int color); }