[android] Get rid of MapFragment

Signed-off-by: Andrei Shkrob <github@shkrob.dev>
This commit is contained in:
Andrei Shkrob
2025-09-12 09:46:30 +02:00
committed by x7z4w
parent 30f624a070
commit 9912d19302
9 changed files with 329 additions and 308 deletions

View File

@@ -1,210 +0,0 @@
package app.organicmaps;
import android.content.Context;
import android.os.Build;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.content.res.ConfigurationHelper;
import app.organicmaps.base.BaseMwmFragment;
import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.MapRenderingListener;
import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.util.log.Logger;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
public class MapFragment extends BaseMwmFragment implements View.OnTouchListener, SurfaceHolder.Callback
{
private static final String TAG = MapFragment.class.getSimpleName();
@NonNull
private final Map mMap = new Map(DisplayType.Device);
public void updateCompassOffset(int offsetX, int offsetY)
{
mMap.updateCompassOffset(requireContext(), offsetX, offsetY, true);
}
public void updateBottomWidgetsOffset(int offsetX, int offsetY)
{
mMap.updateBottomWidgetsOffset(requireContext(), offsetX, offsetY);
}
public void updateMyPositionRoutingOffset(int offsetY)
{
mMap.updateMyPositionRoutingOffset(offsetY);
}
public void destroySurface(boolean activityIsChangingConfigurations)
{
mMap.onSurfaceDestroyed(activityIsChangingConfigurations, isAdded());
}
public boolean isContextCreated()
{
return mMap.isContextCreated();
}
@Override
public void surfaceCreated(@NonNull SurfaceHolder surfaceHolder)
{
Logger.d(TAG);
int densityDpi;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
densityDpi = ConfigurationHelper.getDensityDpi(requireContext().getResources());
else
densityDpi = getDensityDpiOld();
mMap.onSurfaceCreated(requireContext(), surfaceHolder.getSurface(), surfaceHolder.getSurfaceFrame(), densityDpi);
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int format, int width, int height)
{
Logger.d(TAG);
mMap.onSurfaceChanged(requireContext(), surfaceHolder.getSurface(), surfaceHolder.getSurfaceFrame(),
surfaceHolder.isCreating());
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder surfaceHolder)
{
Logger.d(TAG);
mMap.onSurfaceDestroyed(requireActivity().isChangingConfigurations(), true);
}
@Override
public void onAttach(Context context)
{
Logger.d(TAG);
super.onAttach(context);
mMap.setLocationHelper(MwmApplication.from(requireContext()).getLocationHelper());
mMap.setMapRenderingListener((MapRenderingListener) context);
mMap.setCallbackUnsupported(this::reportUnsupported);
}
@Override
public void onDetach()
{
Logger.d(TAG);
super.onDetach();
mMap.setMapRenderingListener(null);
mMap.setCallbackUnsupported(null);
}
@Override
public void onCreate(Bundle b)
{
Logger.d(TAG);
super.onCreate(b);
setRetainInstance(true);
boolean launchByDeepLink = false;
Bundle args = getArguments();
if (args != null)
launchByDeepLink = args.getBoolean(Map.ARG_LAUNCH_BY_DEEP_LINK);
mMap.onCreate(launchByDeepLink);
}
@Override
public void onStart()
{
Logger.d(TAG);
super.onStart();
mMap.onStart();
}
@Override
public void onStop()
{
Logger.d(TAG);
super.onStop();
mMap.onStop();
}
@Override
public void onPause()
{
Logger.d(TAG);
super.onPause();
mMap.onPause(requireContext());
}
@Override
public void onResume()
{
Logger.d(TAG);
super.onResume();
mMap.onResume();
}
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState)
{
Logger.d(TAG);
final View view = inflater.inflate(R.layout.fragment_map, container, false);
final SurfaceView mSurfaceView = view.findViewById(R.id.map_surfaceview);
mSurfaceView.getHolder().addCallback(this);
return view;
}
@Override
public boolean onTouch(View view, MotionEvent event)
{
int action = event.getActionMasked();
int pointerIndex = event.getActionIndex();
switch (action)
{
case MotionEvent.ACTION_POINTER_UP -> action = Map.NATIVE_ACTION_UP;
case MotionEvent.ACTION_UP ->
{
action = Map.NATIVE_ACTION_UP;
pointerIndex = 0;
}
case MotionEvent.ACTION_POINTER_DOWN -> action = Map.NATIVE_ACTION_DOWN;
case MotionEvent.ACTION_DOWN ->
{
action = Map.NATIVE_ACTION_DOWN;
pointerIndex = 0;
}
case MotionEvent.ACTION_MOVE ->
{
action = Map.NATIVE_ACTION_MOVE;
pointerIndex = Map.INVALID_POINTER_MASK;
}
case MotionEvent.ACTION_CANCEL -> action = Map.NATIVE_ACTION_CANCEL;
}
Map.onTouch(action, event, pointerIndex);
return true;
}
public void notifyOnSurfaceDestroyed(@NonNull Runnable task)
{
mMap.onSurfaceDestroyed(false, true);
task.run();
}
private void reportUnsupported()
{
new MaterialAlertDialogBuilder(requireContext(), R.style.MwmTheme_AlertDialog)
.setMessage(R.string.unsupported_phone)
.setCancelable(false)
.setPositiveButton(R.string.close, (dlg, which) -> requireActivity().moveTaskToBack(true))
.show();
}
private int getDensityDpiOld()
{
final DisplayMetrics metrics = new DisplayMetrics();
requireActivity().getWindowManager().getDefaultDisplay().getMetrics(metrics);
return metrics.densityDpi;
}
}

View File

@@ -84,6 +84,7 @@ import app.organicmaps.routing.RoutingPlanInplaceController;
import app.organicmaps.sdk.ChoosePositionMode; import app.organicmaps.sdk.ChoosePositionMode;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Map; import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.MapController;
import app.organicmaps.sdk.MapRenderingListener; import app.organicmaps.sdk.MapRenderingListener;
import app.organicmaps.sdk.PlacePageActivationListener; import app.organicmaps.sdk.PlacePageActivationListener;
import app.organicmaps.sdk.Router; import app.organicmaps.sdk.Router;
@@ -137,10 +138,10 @@ import java.util.ArrayList;
import java.util.Objects; import java.util.Objects;
public class MwmActivity extends BaseMwmFragmentActivity public class MwmActivity extends BaseMwmFragmentActivity
implements PlacePageActivationListener, View.OnTouchListener, MapRenderingListener, RoutingController.Container, implements PlacePageActivationListener, MapRenderingListener, RoutingController.Container, LocationListener,
LocationListener, SensorListener, LocationState.ModeChangeListener, SensorListener, LocationState.ModeChangeListener, RoutingPlanInplaceController.RoutingPlanListener,
RoutingPlanInplaceController.RoutingPlanListener, RoutingBottomMenuListener, RoutingBottomMenuListener, BookmarkManager.BookmarksLoadingListener,
BookmarkManager.BookmarksLoadingListener, FloatingSearchToolbarController.SearchToolbarListener, FloatingSearchToolbarController.SearchToolbarListener,
MenuBottomSheetFragment.MenuBottomSheetInterfaceWithHeader, MenuBottomSheetFragment.MenuBottomSheetInterfaceWithHeader,
PlacePageController.PlacePageRouteSettingsListener, MapButtonsController.MapButtonClickListener, PlacePageController.PlacePageRouteSettingsListener, MapButtonsController.MapButtonClickListener,
DisplayChangedListener DisplayChangedListener
@@ -170,8 +171,9 @@ public class MwmActivity extends BaseMwmFragmentActivity
private static final String POWER_SAVE_DISCLAIMER_SHOWN = "POWER_SAVE_DISCLAIMER_SHOWN"; private static final String POWER_SAVE_DISCLAIMER_SHOWN = "POWER_SAVE_DISCLAIMER_SHOWN";
@Nullable @SuppressWarnings("NotNullFieldNotInitialized")
private MapFragment mMapFragment; @NonNull
private MapController mMapController;
private View mPointChooser; private View mPointChooser;
private MaterialToolbar mPointChooserToolbar; private MaterialToolbar mPointChooserToolbar;
@@ -459,7 +461,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
{ {
mRemoveDisplayListener = false; mRemoveDisplayListener = false;
startActivity(new Intent(this, MapPlaceholderActivity.class)); startActivity(new Intent(this, MapPlaceholderActivity.class));
Objects.requireNonNull(mMapFragment).notifyOnSurfaceDestroyed(onTaskFinishedCallback); mMapController.setOnDestroyListener(onTaskFinishedCallback);
finish(); finish();
} }
@@ -536,7 +538,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
updateViewsInsets(); updateViewsInsets();
if (getIntent().getBooleanExtra(EXTRA_UPDATE_THEME, false)) if (getIntent().getBooleanExtra(EXTRA_UPDATE_THEME, false))
ThemeSwitcher.INSTANCE.restart(isMapRendererActive()); ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
/* /*
* onRenderingInitializationFinished() hook is not called when MwmActivity is recreated with the already * onRenderingInitializationFinished() hook is not called when MwmActivity is recreated with the already
@@ -604,7 +606,10 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void initViews(boolean isLaunchByDeeplink) private void initViews(boolean isLaunchByDeeplink)
{ {
initMap(isLaunchByDeeplink); mMapController = new MapController(findViewById(R.id.map), MwmApplication.from(this).getLocationHelper(), this,
this::reportUnsupported, isLaunchByDeeplink);
getLifecycle().addObserver(mMapController);
initNavigationButtons(); initNavigationButtons();
if (!mIsTabletLayout) if (!mIsTabletLayout)
@@ -737,29 +742,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
finish(); finish();
} }
private void initMap(boolean isLaunchByDeepLink)
{
final FragmentManager manager = getSupportFragmentManager();
mMapFragment = (MapFragment) manager.findFragmentByTag(MapFragment.class.getName());
if (mMapFragment == null)
{
Bundle args = new Bundle();
args.putBoolean(Map.ARG_LAUNCH_BY_DEEP_LINK, isLaunchByDeepLink);
final FragmentFactory factory = manager.getFragmentFactory();
mMapFragment = (MapFragment) factory.instantiate(getClassLoader(), MapFragment.class.getName());
mMapFragment.setArguments(args);
manager.beginTransaction()
.replace(R.id.map_fragment_container, mMapFragment, MapFragment.class.getName())
.commit();
}
View container = findViewById(R.id.map_fragment_container);
if (container != null)
{
container.setOnTouchListener(this);
}
}
private void initNavigationButtons() private void initNavigationButtons()
{ {
prepareNavigationButtons(); prepareNavigationButtons();
@@ -1188,7 +1170,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
{ {
setIntent(intent); setIntent(intent);
super.onNewIntent(intent); super.onNewIntent(intent);
if (isMapRendererActive()) if (mMapController.isRenderingActive())
processIntent(); processIntent();
if (intent.getAction() != null && intent.getAction().equals(TrackRecordingService.STOP_TRACK_RECORDING)) if (intent.getAction() != null && intent.getAction().equals(TrackRecordingService.STOP_TRACK_RECORDING))
{ {
@@ -1198,17 +1180,12 @@ public class MwmActivity extends BaseMwmFragmentActivity
} }
} }
private boolean isMapRendererActive()
{
return mMapFragment != null && Map.isEngineCreated() && mMapFragment.isContextCreated();
}
@CallSuper @CallSuper
@Override @Override
protected void onResume() protected void onResume()
{ {
super.onResume(); super.onResume();
ThemeSwitcher.INSTANCE.restart(isMapRendererActive()); ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
refreshSearchToolbar(); refreshSearchToolbar();
setFullscreen(isFullscreen()); setFullscreen(isFullscreen());
makeNavigationBarTransparentInLightMode(); makeNavigationBarTransparentInLightMode();
@@ -1226,15 +1203,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
MwmApplication.from(this).getSensorHelper().addListener(this); MwmApplication.from(this).getSensorHelper().addListener(this);
} }
@Override
public void recreate()
{
// Explicitly destroy surface before activity recreation.
if (mMapFragment != null)
mMapFragment.destroySurface(true);
super.recreate();
}
@Override @Override
protected void onResumeFragments() protected void onResumeFragments()
{ {
@@ -1436,12 +1404,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
return super.onGenericMotionEvent(event); return super.onGenericMotionEvent(event);
} }
@Override
public boolean onTouch(View view, MotionEvent event)
{
return mMapFragment != null && mMapFragment.onTouch(view, event);
}
public void customOnNavigateUp() public void customOnNavigateUp()
{ {
if (removeCurrentFragment(true)) if (removeCurrentFragment(true))
@@ -1457,10 +1419,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
void updateCompassOffset(int offsetY, int offsetX) void updateCompassOffset(int offsetY, int offsetX)
{ {
if (mMapFragment == null || !mMapFragment.isAdded()) mMapController.updateCompassOffset(offsetX, offsetY);
return;
mMapFragment.updateCompassOffset(offsetX, offsetY);
final double north = MwmApplication.from(this).getSensorHelper().getSavedNorth(); final double north = MwmApplication.from(this).getSensorHelper().getSavedNorth();
if (!Double.isNaN(north)) if (!Double.isNaN(north))
@@ -1479,9 +1438,6 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void updateBottomWidgetsOffset(int offsetX) public void updateBottomWidgetsOffset(int offsetX)
{ {
if (mMapFragment == null || !mMapFragment.isAdded())
return;
int offsetY = mNavBarHeight; int offsetY = mNavBarHeight;
final Float bottomButtonHeight = mMapButtonsViewModel.getBottomButtonsHeight().getValue(); final Float bottomButtonHeight = mMapButtonsViewModel.getBottomButtonsHeight().getValue();
if (bottomButtonHeight != null) if (bottomButtonHeight != null)
@@ -1496,8 +1452,8 @@ public class MwmActivity extends BaseMwmFragmentActivity
if (mDisplayManager.isDeviceDisplayUsed()) if (mDisplayManager.isDeviceDisplayUsed())
{ {
mMapFragment.updateBottomWidgetsOffset(offsetX, offsetY); mMapController.updateBottomWidgetsOffset(offsetX, offsetY);
mMapFragment.updateMyPositionRoutingOffset(offsetY); mMapController.updateMyPositionRoutingOffset(offsetY);
} }
} }
@@ -1715,7 +1671,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onNavigationCancelled() public void onNavigationCancelled()
{ {
closeFloatingToolbarsAndPanels(true); closeFloatingToolbarsAndPanels(true);
ThemeSwitcher.INSTANCE.restart(isMapRendererActive()); ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
if (mRoutingPlanInplaceController == null) if (mRoutingPlanInplaceController == null)
return; return;
@@ -1731,7 +1687,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onNavigationStarted() public void onNavigationStarted()
{ {
closeFloatingToolbarsAndPanels(true); closeFloatingToolbarsAndPanels(true);
ThemeSwitcher.INSTANCE.restart(isMapRendererActive()); ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.navigation); mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.navigation);
refreshLightStatusBar(); refreshLightStatusBar();
@@ -1767,7 +1723,7 @@ public class MwmActivity extends BaseMwmFragmentActivity
public void onResetToPlanningState() public void onResetToPlanningState()
{ {
closeFloatingToolbarsAndPanels(true); closeFloatingToolbarsAndPanels(true);
ThemeSwitcher.INSTANCE.restart(isMapRendererActive()); ThemeSwitcher.INSTANCE.restart(mMapController.isRenderingActive());
NavigationService.stopService(this); NavigationService.stopService(this);
mMapButtonsViewModel.setSearchOption(null); mMapButtonsViewModel.setSearchOption(null);
mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.planning); mMapButtonsViewModel.setLayoutMode(MapButtonsController.LayoutMode.planning);
@@ -2596,4 +2552,13 @@ public class MwmActivity extends BaseMwmFragmentActivity
window.setNavigationBarContrastEnforced(false); window.setNavigationBarContrastEnforced(false);
} }
} }
private void reportUnsupported()
{
new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
.setMessage(R.string.unsupported_phone)
.setCancelable(false)
.setPositiveButton(R.string.close, (dlg, which) -> this.moveTaskToBack(true))
.show();
}
} }

View File

@@ -8,19 +8,16 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.car.app.AppManager; import androidx.car.app.AppManager;
import androidx.car.app.CarContext; import androidx.car.app.CarContext;
import androidx.car.app.CarToast;
import androidx.car.app.SurfaceCallback; import androidx.car.app.SurfaceCallback;
import androidx.car.app.SurfaceContainer; import androidx.car.app.SurfaceContainer;
import androidx.lifecycle.DefaultLifecycleObserver; import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import app.organicmaps.MwmApplication; import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.sdk.Framework; import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Map; import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.MapRenderingListener; import app.organicmaps.sdk.MapRenderingListener;
import app.organicmaps.sdk.settings.UnitLocale; import app.organicmaps.sdk.settings.UnitLocale;
import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.sdk.util.log.Logger; import app.organicmaps.sdk.util.log.Logger;
public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallback, MapRenderingListener public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallback, MapRenderingListener
@@ -96,7 +93,7 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
mSurface.release(); mSurface.release();
mSurface = null; mSurface = null;
} }
mMap.onSurfaceDestroyed(false, true); mMap.onSurfaceDestroyed(false);
} }
@Override @Override
@@ -112,7 +109,6 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
{ {
Logger.d(TAG); Logger.d(TAG);
mMap.onStart(); mMap.onStart();
mMap.setCallbackUnsupported(this::reportUnsupported);
} }
@Override @Override
@@ -121,14 +117,14 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
Logger.d(TAG); Logger.d(TAG);
mMap.onResume(); mMap.onResume();
if (MwmApplication.from(mCarContext).getDisplayManager().isCarDisplayUsed()) if (MwmApplication.from(mCarContext).getDisplayManager().isCarDisplayUsed())
UiThread.runLater(() -> mMap.updateMyPositionRoutingOffset(0)); mMap.updateMyPositionRoutingOffset(0);
} }
@Override @Override
public void onPause(@NonNull LifecycleOwner owner) public void onPause(@NonNull LifecycleOwner owner)
{ {
Logger.d(TAG); Logger.d(TAG);
mMap.onPause(mCarContext); mMap.onPause();
} }
@Override @Override
@@ -199,7 +195,8 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
} }
mCarContext.getCarService(AppManager.class).setSurfaceCallback(null); mCarContext.getCarService(AppManager.class).setSurfaceCallback(null);
mMap.onSurfaceDestroyed(false, true); mMap.onPause();
mMap.onSurfaceDestroyed(false);
mMap.onStop(); mMap.onStop();
mMap.setCallbackUnsupported(null); mMap.setCallbackUnsupported(null);
mMap.setMapRenderingListener(null); mMap.setMapRenderingListener(null);
@@ -217,9 +214,8 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
mCarContext.getCarService(AppManager.class).setSurfaceCallback(this); mCarContext.getCarService(AppManager.class).setSurfaceCallback(this);
mMap.onStart(); mMap.onStart();
mMap.setCallbackUnsupported(this::reportUnsupported);
mMap.setMapRenderingListener(this); mMap.setMapRenderingListener(this);
UiThread.runLater(() -> mMap.updateMyPositionRoutingOffset(0)); mMap.updateMyPositionRoutingOffset(0);
mIsRunning = true; mIsRunning = true;
} }
@@ -229,13 +225,6 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
return mIsRunning; return mIsRunning;
} }
private void reportUnsupported()
{
String message = mCarContext.getString(R.string.unsupported_phone);
Logger.e(TAG, message);
CarToast.makeText(mCarContext, message, CarToast.LENGTH_LONG).show();
}
@Override @Override
public void onRenderingCreated() public void onRenderingCreated()
{ {

View File

@@ -9,8 +9,8 @@
android:id="@+id/map_container" android:id="@+id/map_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<FrameLayout <app.organicmaps.sdk.MapView
android:id="@+id/map_fragment_container" android:id="@+id/map"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" /> android:layout_height="match_parent" />
<include <include

View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.view.SurfaceView
android:id="@+id/map_surfaceview"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/transparent"/>

View File

@@ -21,7 +21,6 @@ public final class Map
void report(); void report();
} }
public static final String ARG_LAUNCH_BY_DEEP_LINK = "launch_by_deep_link";
private static final String TAG = Map.class.getSimpleName(); private static final String TAG = Map.class.getSimpleName();
// Should correspond to android::MultiTouchAction from Framework.cpp // Should correspond to android::MultiTouchAction from Framework.cpp
@@ -220,11 +219,10 @@ public final class Map
mMapRenderingListener.onRenderingRestored(); mMapRenderingListener.onRenderingRestored();
} }
public void onSurfaceDestroyed(boolean activityIsChangingConfigurations, boolean isAdded) public void onSurfaceDestroyed(boolean activityIsChangingConfigurations)
{ {
Logger.d(TAG, "mSurfaceCreated = " + mSurfaceCreated + ", mSurfaceAttached = " + mSurfaceAttached Logger.d(TAG, "mSurfaceCreated = " + mSurfaceCreated + ", mSurfaceAttached = " + mSurfaceAttached);
+ ", isAdded = " + isAdded); if (!mSurfaceCreated || !mSurfaceAttached)
if (!mSurfaceCreated || !mSurfaceAttached || !isAdded)
return; return;
nativeDetachSurface(!activityIsChangingConfigurations); nativeDetachSurface(!activityIsChangingConfigurations);
@@ -261,7 +259,7 @@ public final class Map
nativeSetRenderingInitializationFinishedListener(null); nativeSetRenderingInitializationFinishedListener(null);
} }
public void onPause(final Context context) public void onPause()
{ {
mUiThemeOnPause = Config.UiTheme.getCurrent(); mUiThemeOnPause = Config.UiTheme.getCurrent();

View File

@@ -0,0 +1,102 @@
package app.organicmaps.sdk;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import app.organicmaps.sdk.location.LocationHelper;
import app.organicmaps.sdk.util.log.Logger;
public class MapController implements DefaultLifecycleObserver
{
private static final String TAG = MapController.class.getSimpleName();
private final MapView mMapView;
private final Map mMap;
@Nullable
private Runnable mOnSurfaceDestroyedListener = null;
public MapController(@NonNull MapView mapView, @NonNull LocationHelper locationHelper,
@NonNull MapRenderingListener mapRenderingListener,
@NonNull Map.CallbackUnsupported callbackUnsupported, boolean launchByDeepLink)
{
mMapView = mapView;
mMap = mMapView.getMap();
mMap.onCreate(launchByDeepLink);
mMap.setLocationHelper(locationHelper);
mMap.setMapRenderingListener(mapRenderingListener);
mMap.setCallbackUnsupported(callbackUnsupported);
}
public MapView getView()
{
return mMapView;
}
public boolean isRenderingActive()
{
return Map.isEngineCreated() && mMap.isContextCreated();
}
public void updateCompassOffset(int offsetX, int offsetY)
{
mMap.updateCompassOffset(mMapView.getContext(), offsetX, offsetY, true);
}
public void updateBottomWidgetsOffset(int offsetX, int offsetY)
{
mMap.updateBottomWidgetsOffset(mMapView.getContext(), offsetX, offsetY);
}
public void updateMyPositionRoutingOffset(int offsetY)
{
mMap.updateMyPositionRoutingOffset(offsetY);
}
public void setOnDestroyListener(@NonNull Runnable task)
{
mOnSurfaceDestroyedListener = task;
}
@Override
public void onStart(@NonNull LifecycleOwner owner)
{
Logger.d(TAG);
mMap.onStart();
}
@Override
public void onResume(@NonNull LifecycleOwner owner)
{
Logger.d(TAG);
mMap.onResume();
}
@Override
public void onPause(@NonNull LifecycleOwner owner)
{
Logger.d(TAG);
mMap.onPause();
}
@Override
public void onStop(@NonNull LifecycleOwner owner)
{
Logger.d(TAG);
mMap.onStop();
}
@Override
public void onDestroy(@NonNull LifecycleOwner owner)
{
Logger.d(TAG);
mMap.setMapRenderingListener(null);
mMap.setCallbackUnsupported(null);
if (mOnSurfaceDestroyedListener != null)
{
mOnSurfaceDestroyedListener.run();
mOnSurfaceDestroyedListener = null;
}
}
}

View File

@@ -0,0 +1,177 @@
package app.organicmaps.sdk;
import android.app.Activity;
import android.content.Context;
import android.content.ContextWrapper;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import androidx.annotation.NonNull;
import androidx.core.content.res.ConfigurationHelper;
import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.util.Utils;
import app.organicmaps.sdk.util.log.Logger;
public class MapView extends SurfaceView
{
private static final String TAG = MapView.class.getSimpleName();
private class SurfaceHolderCallback implements SurfaceHolder.Callback
{
@Override
public void surfaceCreated(@NonNull SurfaceHolder holder)
{
Logger.d(TAG);
mMap.onSurfaceCreated(MapView.this.getContext(), holder.getSurface(), holder.getSurfaceFrame(),
ConfigurationHelper.getDensityDpi(MapView.this.getResources()));
}
@Override
public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height)
{
Logger.d(TAG);
mMap.onSurfaceChanged(MapView.this.getContext(), holder.getSurface(), holder.getSurfaceFrame(),
holder.isCreating());
}
@Override
public void surfaceDestroyed(@NonNull SurfaceHolder holder)
{
Logger.d(TAG);
mMap.onSurfaceDestroyed(isHostActivityChangingConfigurations());
}
}
@NonNull
private final Map mMap;
public MapView(Context context)
{
this(context, null);
}
public MapView(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public MapView(Context context, AttributeSet attrs, int defStyleAttr)
{
this(context, attrs, defStyleAttr, 0);
}
public MapView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
{
super(context, attrs, defStyleAttr, defStyleRes);
mMap = new Map(DisplayType.Device);
super.getHolder().addCallback(new SurfaceHolderCallback());
}
public final void onDraw(@NonNull Canvas canvas)
{
super.onDraw(canvas);
if (isInEditMode())
drawMapPreview(canvas);
}
@Override
public boolean onTouchEvent(@NonNull MotionEvent event)
{
int action = event.getActionMasked();
int pointerIndex = event.getActionIndex();
switch (action)
{
case MotionEvent.ACTION_POINTER_UP -> action = Map.NATIVE_ACTION_UP;
case MotionEvent.ACTION_UP ->
{
action = Map.NATIVE_ACTION_UP;
pointerIndex = 0;
}
case MotionEvent.ACTION_POINTER_DOWN -> action = Map.NATIVE_ACTION_DOWN;
case MotionEvent.ACTION_DOWN ->
{
action = Map.NATIVE_ACTION_DOWN;
pointerIndex = 0;
}
case MotionEvent.ACTION_MOVE ->
{
action = Map.NATIVE_ACTION_MOVE;
pointerIndex = Map.INVALID_POINTER_MASK;
}
case MotionEvent.ACTION_CANCEL -> action = Map.NATIVE_ACTION_CANCEL;
}
Map.onTouch(action, event, pointerIndex);
performClick();
return true;
}
@Override
public boolean performClick()
{
super.performClick();
return false;
}
@Override
public final SurfaceHolder getHolder()
{
throw new UnsupportedOperationException("Not supported.");
}
@NonNull
Map getMap()
{
return mMap;
}
/// The function is called only in the design mode of Android Studio.
private void drawMapPreview(@NonNull Canvas canvas)
{
final int w = getWidth();
final int h = getHeight();
// Background
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
paint.setStyle(Paint.Style.FILL);
if (Utils.isDarkMode(getContext()))
paint.setColor(Color.rgb(30, 30, 30));
else
paint.setColor(Color.rgb(245, 242, 230));
canvas.drawRect(0, 0, w, h, paint);
// Grid lines (lat/lon)
paint.setColor(Color.LTGRAY);
paint.setStrokeWidth(2f);
final int step = Math.min(w, h) / 6;
for (int i = 0; i < Math.max(w, h); i += step)
{
if (i < w)
canvas.drawLine(i, 0, i, h, paint);
if (i < h)
canvas.drawLine(0, i, w, i, paint);
}
}
private boolean isHostActivityChangingConfigurations()
{
Activity activity = findActivity(getContext());
return activity != null && activity.isChangingConfigurations();
}
private static Activity findActivity(Context context)
{
while (context instanceof ContextWrapper)
{
if (context instanceof Activity)
{
return (Activity) context;
}
context = ((ContextWrapper) context).getBaseContext();
}
return null;
}
}

View File

@@ -6,6 +6,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo; import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo; import android.content.pm.ResolveInfo;
import android.content.res.Configuration;
import android.content.res.Resources; import android.content.res.Resources;
import android.os.Build; import android.os.Build;
import android.text.TextUtils; import android.text.TextUtils;
@@ -346,4 +347,10 @@ public class Utils
{ {
return context.getResources().getDimensionPixelSize(id); return context.getResources().getDimensionPixelSize(id);
} }
public static boolean isDarkMode(@NonNull Context context)
{
return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
== Configuration.UI_MODE_NIGHT_YES;
}
} }