[android][sdk] Refactoring

Signed-off-by: Andrei Shkrob <github@shkrob.dev>
This commit is contained in:
Andrei Shkrob
2025-07-09 22:49:18 +02:00
committed by Konstantin Pastbin
parent 0000ec149c
commit 9833918aac
50 changed files with 156 additions and 198 deletions

View File

@@ -23,7 +23,10 @@ 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();
private final Map mMap = new Map(DisplayType.Device);
@SuppressWarnings("NonNullFieldNotInitialized")
@NonNull
private Map mMap;
public void updateCompassOffset(int offsetX, int offsetY)
{
@@ -84,6 +87,7 @@ public class MapFragment extends BaseMwmFragment implements View.OnTouchListener
{
Logger.d(TAG);
super.onAttach(context);
mMap = new Map(DisplayType.Device, MwmApplication.from(requireContext()).getLocationHelper());
mMap.setMapRenderingListener((MapRenderingListener) context);
mMap.setCallbackUnsupported(this::reportUnsupported);
}

View File

@@ -82,7 +82,6 @@ import app.organicmaps.routing.ManageRouteBottomSheet;
import app.organicmaps.routing.NavigationController;
import app.organicmaps.routing.NavigationService;
import app.organicmaps.routing.RoutingBottomMenuListener;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.routing.RoutingErrorDialogFragment;
import app.organicmaps.routing.RoutingPlanFragment;
import app.organicmaps.routing.RoutingPlanInplaceController;
@@ -108,6 +107,7 @@ import app.organicmaps.sdk.location.SensorListener;
import app.organicmaps.sdk.location.TrackRecorder;
import app.organicmaps.sdk.maplayer.isolines.IsolinesState;
import app.organicmaps.sdk.routing.RouteMarkType;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.settings.RoadType;
@@ -115,7 +115,6 @@ import app.organicmaps.sdk.settings.UnitLocale;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.LocationUtils;
import app.organicmaps.sdk.util.PowerManagment;
import app.organicmaps.sdk.util.ThemeSwitcher;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.sdk.widget.placepage.PlacePageData;
@@ -125,6 +124,7 @@ import app.organicmaps.search.SearchFragment;
import app.organicmaps.settings.DrivingOptionsActivity;
import app.organicmaps.settings.SettingsActivity;
import app.organicmaps.util.SharingUtils;
import app.organicmaps.util.ThemeSwitcher;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
@@ -1223,22 +1223,23 @@ public class MwmActivity extends BaseMwmFragmentActivity
private void onIsolinesStateChanged(@NonNull IsolinesState type)
{
if (type != IsolinesState.EXPIREDDATA)
if (type == IsolinesState.NODATA)
{
type.activate(this, findViewById(R.id.coordinator), findViewById(R.id.menu_frame));
return;
Toast.makeText(this, R.string.isolines_location_error_dialog, Toast.LENGTH_SHORT).show();
}
dismissAlertDialog();
if (type == IsolinesState.EXPIREDDATA)
{
mAlertDialog = new MaterialAlertDialogBuilder(this, R.style.MwmTheme_AlertDialog)
.setTitle(R.string.downloader_update_maps)
.setMessage(R.string.isolines_activation_error_dialog)
.setPositiveButton(R.string.ok,
(dialog, which) -> startActivity(new Intent(this, DownloaderActivity.class)))
.setPositiveButton(
R.string.ok, (dialog, which) -> startActivity(new Intent(this, DownloaderActivity.class)))
.setNegativeButton(R.string.cancel, null)
.setOnDismissListener(dialog -> mAlertDialog = null)
.show();
}
}
@Override
protected void onNewIntent(Intent intent)

View File

@@ -18,7 +18,6 @@ import app.organicmaps.background.OsmUploadWork;
import app.organicmaps.downloader.DownloaderNotifier;
import app.organicmaps.location.TrackRecordingService;
import app.organicmaps.routing.NavigationService;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.OrganicMaps;
import app.organicmaps.sdk.display.DisplayManager;
@@ -28,9 +27,11 @@ import app.organicmaps.sdk.location.SensorHelper;
import app.organicmaps.sdk.location.TrackRecorder;
import app.organicmaps.sdk.maplayer.isolines.IsolinesManager;
import app.organicmaps.sdk.maplayer.subway.SubwayManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.ConnectionState;
import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.util.ThemeSwitcher;
import app.organicmaps.util.Utils;
import java.io.IOException;
import java.lang.ref.WeakReference;
@@ -133,6 +134,8 @@ public class MwmApplication extends Application implements Application.ActivityL
public boolean initOrganicMaps(@NonNull Runnable onComplete) throws IOException
{
return mOrganicMaps.init(() -> {
ThemeSwitcher.INSTANCE.initialize(this);
ThemeSwitcher.INSTANCE.restart(false);
ProcessLifecycleOwner.get().getLifecycle().addObserver(mProcessLifecycleObserver);
onComplete.run();
});

View File

@@ -26,7 +26,6 @@ import app.organicmaps.car.util.CurrentCountryChangedListener;
import app.organicmaps.car.util.IntentUtils;
import app.organicmaps.car.util.ThemeUtils;
import app.organicmaps.car.util.UserActionRequired;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.PlacePageActivationListener;
import app.organicmaps.sdk.bookmarks.data.MapObject;
@@ -34,6 +33,7 @@ import app.organicmaps.sdk.display.DisplayChangedListener;
import app.organicmaps.sdk.display.DisplayManager;
import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.location.LocationState;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.LocationUtils;
import app.organicmaps.sdk.util.log.Logger;

View File

@@ -27,8 +27,11 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
{
private static final String TAG = SurfaceRenderer.class.getSimpleName();
@NonNull
private final CarContext mCarContext;
private final Map mMap = new Map(Car);
@NonNull
private final Map mMap;
@NonNull
private Rect mVisibleArea = new Rect();
@@ -42,6 +45,7 @@ public class SurfaceRenderer implements DefaultLifecycleObserver, SurfaceCallbac
{
Logger.d(TAG, "SurfaceRenderer()");
mCarContext = carContext;
mMap = new Map(Car, MwmApplication.from(mCarContext).getLocationHelper());
mIsRunning = true;
lifecycle.addObserver(this);
mMap.setMapRenderingListener(this);

View File

@@ -28,11 +28,11 @@ import app.organicmaps.car.util.RoutingUtils;
import app.organicmaps.car.util.ThemeUtils;
import app.organicmaps.car.util.UiHelpers;
import app.organicmaps.routing.NavigationService;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.location.LocationHelper;
import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.routing.JunctionInfo;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.sound.TtsPlayer;
import app.organicmaps.sdk.util.LocationUtils;

View File

@@ -35,11 +35,11 @@ import app.organicmaps.car.util.OnBackPressedCallback;
import app.organicmaps.car.util.RoutingHelpers;
import app.organicmaps.car.util.UiHelpers;
import app.organicmaps.routing.ResultCodesHelper;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Router;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.Metadata;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.util.Config;
import java.util.Objects;

View File

@@ -7,9 +7,9 @@ import androidx.car.app.CarContext;
import androidx.car.app.ScreenManager;
import app.organicmaps.car.screens.download.DownloadMapsScreen;
import app.organicmaps.car.screens.download.DownloadMapsScreenBuilder;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
public class CurrentCountryChangedListener implements MapManager.CurrentCountryChangedListener
{

View File

@@ -15,13 +15,13 @@ import app.organicmaps.car.CarAppService;
import app.organicmaps.car.SurfaceRenderer;
import app.organicmaps.car.screens.NavigationScreen;
import app.organicmaps.car.screens.search.SearchScreen;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.api.ParsedSearchRequest;
import app.organicmaps.sdk.api.RequestType;
import app.organicmaps.sdk.display.DisplayManager;
import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.log.Logger;
public final class IntentUtils

View File

@@ -8,8 +8,8 @@ import androidx.annotation.StringRes;
import androidx.annotation.UiThread;
import androidx.car.app.CarContext;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.MapStyle;
import app.organicmaps.sdk.routing.RoutingController;
public final class ThemeUtils
{

View File

@@ -20,9 +20,9 @@ import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;

View File

@@ -9,9 +9,9 @@ import androidx.core.view.ViewCompat;
import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.ConnectionState;
import app.organicmaps.sdk.util.StringUtils;

View File

@@ -10,7 +10,6 @@ import androidx.core.content.IntentCompat;
import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication;
import app.organicmaps.editor.OsmLoginActivity;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.api.ParsedRoutingData;
@@ -20,6 +19,7 @@ import app.organicmaps.sdk.api.RoutePoint;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.FeatureId;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.util.StorageUtils;
import app.organicmaps.sdk.util.concurrency.ThreadPool;

View File

@@ -26,7 +26,6 @@ import app.organicmaps.MwmActivity;
import app.organicmaps.R;
import app.organicmaps.leftbutton.LeftButton;
import app.organicmaps.leftbutton.LeftToggleButton;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.downloader.UpdateInfo;
@@ -34,6 +33,7 @@ import app.organicmaps.sdk.location.TrackRecorder;
import app.organicmaps.sdk.maplayer.isolines.IsolinesManager;
import app.organicmaps.sdk.maplayer.subway.SubwayManager;
import app.organicmaps.sdk.maplayer.traffic.TrafficManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.ThemeUtils;

View File

@@ -14,7 +14,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.concurrency.UiThread;

View File

@@ -14,6 +14,7 @@ import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.sdk.maplayer.Mode;
import app.organicmaps.sdk.util.SharedPropertiesUtils;
import app.organicmaps.util.ThemeSwitcher;
import app.organicmaps.util.Utils;
import app.organicmaps.util.bottomsheet.MenuBottomSheetFragment;
import app.organicmaps.widget.recycler.SpanningLinearLayoutManager;
@@ -72,6 +73,9 @@ public class ToggleMapLayerFragment extends Fragment
Context context = v.getContext();
SharedPropertiesUtils.setLayerMarkerShownForLayerMode(mode);
mode.setEnabled(context, !mode.isEnabled(context));
// TODO: dirty hack :(
if (mode == Mode.OUTDOORS)
ThemeSwitcher.INSTANCE.restart(true);
mAdapter.notifyDataSetChanged();
mMapButtonsController.updateLayerButton();
if (MwmApplication.from(context).getIsolinesManager().shouldShowNotification())

View File

@@ -15,6 +15,7 @@ import app.organicmaps.R;
import app.organicmaps.adapter.DisabledChildSimpleExpandableListAdapter;
import app.organicmaps.base.BaseMwmDialogFragment;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;

View File

@@ -22,6 +22,7 @@ import app.organicmaps.R;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.routing.RouteMarkData;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.UiUtils;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.BottomSheetDialog;

View File

@@ -18,6 +18,7 @@ import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Router;
import app.organicmaps.sdk.maplayer.traffic.TrafficManager;
import app.organicmaps.sdk.routing.CarDirection;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;

View File

@@ -35,6 +35,7 @@ import app.organicmaps.R;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.location.LocationHelper;
import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.sound.MediaPlayerWrapper;
import app.organicmaps.sdk.sound.TtsPlayer;

View File

@@ -32,6 +32,7 @@ import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.DistanceAndAzimut;
import app.organicmaps.sdk.routing.RouteMarkData;
import app.organicmaps.sdk.routing.RouteMarkType;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.routing.TransitRouteInfo;
import app.organicmaps.sdk.routing.TransitStepInfo;
@@ -39,6 +40,7 @@ import app.organicmaps.sdk.util.Distance;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.Graphics;
import app.organicmaps.util.ThemeUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.recycler.DotDividerItemDecoration;
import app.organicmaps.widget.recycler.MultilineLayoutManager;
import com.google.android.material.imageview.ShapeableImageView;
@@ -191,8 +193,7 @@ final class RoutingBottomMenuController implements View.OnClickListener
scrollToBottom(rv);
MaterialTextView totalTimeView = mTransitFrame.findViewById(R.id.total_time);
totalTimeView.setText(
RoutingController.formatRoutingTime(mContext, info.getTotalTime(), R.dimen.text_size_routing_number));
totalTimeView.setText(Utils.formatRoutingTime(mContext, info.getTotalTime(), R.dimen.text_size_routing_number));
View dotView = mTransitFrame.findViewById(R.id.dot);
View pedestrianIcon = mTransitFrame.findViewById(R.id.pedestrian_icon);
MaterialTextView distanceView = mTransitFrame.findViewById(R.id.total_distance);
@@ -382,7 +383,7 @@ final class RoutingBottomMenuController implements View.OnClickListener
if (mArrival != null)
{
String arrivalTime = RoutingController.formatArrivalTime(rinfo.totalTimeInSeconds);
String arrivalTime = Utils.formatArrivalTime(rinfo.totalTimeInSeconds);
mArrival.setText(arrivalTime);
}
}
@@ -400,7 +401,7 @@ final class RoutingBottomMenuController implements View.OnClickListener
{
CharSequence time =
RoutingController.formatRoutingTime(context, routingInfo.totalTimeInSeconds, R.dimen.text_size_routing_number);
Utils.formatRoutingTime(context, routingInfo.totalTimeInSeconds, R.dimen.text_size_routing_number);
SpannableStringBuilder builder = new SpannableStringBuilder();
initTimeBuilderSequence(context, time, builder);

View File

@@ -11,6 +11,7 @@ import androidx.fragment.app.FragmentFactory;
import app.organicmaps.R;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.widget.WheelProgressView;
import java.util.HashSet;

View File

@@ -17,6 +17,7 @@ import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Router;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.sdk.routing.TransitRouteInfo;

View File

@@ -10,6 +10,7 @@ import app.organicmaps.MwmActivity;
import app.organicmaps.R;
import app.organicmaps.base.BaseMwmFragment;
import app.organicmaps.sdk.Router;
import app.organicmaps.sdk.routing.RoutingController;
public class RoutingPlanFragment extends BaseMwmFragment
{

View File

@@ -4,9 +4,9 @@ import android.content.Context;
import android.graphics.Rect;
import android.view.MotionEvent;
import android.view.Surface;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.organicmaps.BuildConfig;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.sdk.display.DisplayType;
import app.organicmaps.sdk.location.LocationHelper;
@@ -53,8 +53,12 @@ public final class Map
public static final int INVALID_POINTER_MASK = 0xFF;
public static final int INVALID_TOUCH_ID = -1;
@NonNull
private final DisplayType mDisplayType;
@NonNull
private final LocationHelper mLocationHelper;
private int mCurrentCompassOffsetX;
private int mCurrentCompassOffsetY;
private int mBottomWidgetOffsetX;
@@ -75,9 +79,10 @@ public final class Map
private static int sCurrentDpi = 0;
public Map(DisplayType mapType)
public Map(@NonNull DisplayType mapType, @NonNull LocationHelper locationHelper)
{
mDisplayType = mapType;
mLocationHelper = locationHelper;
onCreate(false);
}
@@ -169,9 +174,7 @@ public final class Map
mRequireResize = false;
setupWidgets(context, surfaceFrame.width(), surfaceFrame.height());
final LocationHelper locationHelper = MwmApplication.from(context).getLocationHelper();
final boolean firstStart = locationHelper.isInFirstRun();
final boolean firstStart = mLocationHelper.isInFirstRun();
if (!nativeCreateEngine(surface, surfaceDpi, firstStart, mLaunchByDeepLink, BuildConfig.VERSION_CODE,
ROMUtils.isCustomROM()))
{
@@ -182,7 +185,7 @@ public final class Map
sCurrentDpi = surfaceDpi;
if (firstStart)
UiThread.runLater(locationHelper::onExitFromFirstRun);
UiThread.runLater(mLocationHelper::onExitFromFirstRun);
mSurfaceCreated = true;
mSurfaceAttached = true;

View File

@@ -7,7 +7,6 @@ import androidx.lifecycle.DefaultLifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.ProcessLifecycleOwner;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.Icon;
import app.organicmaps.sdk.downloader.Android7RootCertificateWorkaround;
@@ -17,16 +16,16 @@ import app.organicmaps.sdk.location.SensorHelper;
import app.organicmaps.sdk.maplayer.isolines.IsolinesManager;
import app.organicmaps.sdk.maplayer.subway.SubwayManager;
import app.organicmaps.sdk.maplayer.traffic.TrafficManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.settings.StoragePathManager;
import app.organicmaps.sdk.sound.TtsPlayer;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.SharedPropertiesUtils;
import app.organicmaps.sdk.util.StorageUtils;
import app.organicmaps.sdk.util.ThemeSwitcher;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.sdk.util.log.LogsManager;
import app.organicmaps.settings.StoragePathManager;
import java.io.IOException;
public final class OrganicMaps implements DefaultLifecycleObserver
@@ -101,7 +100,7 @@ public final class OrganicMaps implements DefaultLifecycleObserver
mSensorHelper = new SensorHelper(mContext);
mLocationHelper = new LocationHelper(mContext, mSensorHelper);
mIsolinesManager = new IsolinesManager(mContext);
mIsolinesManager = new IsolinesManager();
mSubwayManager = new SubwayManager(mContext);
}
@@ -177,12 +176,10 @@ public final class OrganicMaps implements DefaultLifecycleObserver
nativeInitFramework(onComplete);
initNativeStrings();
ThemeSwitcher.INSTANCE.initialize(mContext);
SearchEngine.INSTANCE.initialize();
BookmarkManager.loadBookmarks();
TtsPlayer.INSTANCE.initialize(mContext);
ThemeSwitcher.INSTANCE.restart(false);
RoutingController.get().initialize(mContext);
RoutingController.get().initialize(mLocationHelper);
TrafficManager.INSTANCE.initialize();
mSubwayManager.initialize();
mIsolinesManager.initialize();

View File

@@ -10,12 +10,12 @@ import java.lang.annotation.RetentionPolicy;
public @interface RequestType
{
// Represents url_scheme::ParsedMapApi::UrlType from c++ part.
public static final int INCORRECT = 0;
public static final int MAP = 1;
public static final int ROUTE = 2;
public static final int SEARCH = 3;
public static final int CROSSHAIR = 4;
public static final int OAUTH2 = 5;
public static final int MENU = 6;
public static final int SETTINGS = 7;
int INCORRECT = 0;
int MAP = 1;
int ROUTE = 2;
int SEARCH = 3;
int CROSSHAIR = 4;
int OAUTH2 = 5;
int MENU = 6;
int SETTINGS = 7;
}

View File

@@ -16,13 +16,12 @@ import androidx.annotation.UiThread;
import androidx.core.content.ContextCompat;
import androidx.core.location.GnssStatusCompat;
import androidx.core.location.LocationManagerCompat;
import app.organicmaps.MwmApplication;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Map;
import app.organicmaps.sdk.bookmarks.data.FeatureId;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.routing.JunctionInfo;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.LocationUtils;
import app.organicmaps.sdk.util.NetworkPolicy;

View File

@@ -6,7 +6,6 @@ import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.maplayer.isolines.IsolinesManager;
import app.organicmaps.sdk.maplayer.subway.SubwayManager;
import app.organicmaps.sdk.maplayer.traffic.TrafficManager;
import app.organicmaps.sdk.util.ThemeSwitcher;
public enum Mode
{
@@ -61,7 +60,8 @@ public enum Mode
public void setEnabled(@NonNull Context context, boolean isEnabled)
{
Framework.nativeSetOutdoorsLayerEnabled(isEnabled);
ThemeSwitcher.INSTANCE.restart(true);
// TODO: ThemeSwitcher is outside sdk package. Properly fix dependencies
// ThemeSwitcher.INSTANCE.restart(true);
}
};

View File

@@ -1,18 +1,12 @@
package app.organicmaps.sdk.maplayer.isolines;
import android.content.Context;
import androidx.annotation.NonNull;
import app.organicmaps.sdk.Framework;
public class IsolinesManager
{
@NonNull
private final OnIsolinesChangedListener mListener;
public IsolinesManager(@NonNull Context context)
{
mListener = new OnIsolinesChangedListener(context);
}
private final OnIsolinesChangedListener mListener = new OnIsolinesChangedListener();
static public boolean isEnabled()
{

View File

@@ -1,40 +1,9 @@
package app.organicmaps.sdk.maplayer.isolines;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import app.organicmaps.R;
import app.organicmaps.util.Utils;
public enum IsolinesState
{
DISABLED,
ENABLED,
EXPIREDDATA {
@Override
public void activate(@NonNull Context context, @Nullable View view, @Nullable View viewAbove)
{
if (view != null)
Utils.showSnackbar(context, view, viewAbove, R.string.isolines_activation_error_dialog);
else
Toast.makeText(context, R.string.isolines_activation_error_dialog, Toast.LENGTH_SHORT).show();
}
},
NODATA {
@Override
public void activate(@NonNull Context context, @Nullable View view, @Nullable View viewAbove)
{
if (view != null)
Utils.showSnackbar(context, view, viewAbove, R.string.isolines_location_error_dialog);
else
Toast.makeText(context, R.string.isolines_location_error_dialog, Toast.LENGTH_SHORT).show();
}
};
public void activate(@NonNull Context context, @Nullable View viewAbove, @Nullable View view)
{
/* Do nothing by default */
}
EXPIREDDATA,
NODATA;
}

View File

@@ -1,33 +1,22 @@
package app.organicmaps.sdk.maplayer.isolines;
import android.content.Context;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
class OnIsolinesChangedListener
{
@NonNull
private final Context mContext;
@Nullable
private IsolinesErrorDialogListener mListener;
OnIsolinesChangedListener(@NonNull Context app)
{
mContext = app;
}
// Called from JNI.
@Keep
@SuppressWarnings("unused")
public void onStateChanged(int type)
{
IsolinesState state = IsolinesState.values()[type];
if (mListener == null)
{
state.activate(mContext, null, null);
return;
}
mListener.onStateChanged(state);
mListener.onStateChanged(IsolinesState.values()[type]);
}
public void attach(@NonNull IsolinesErrorDialogListener listener)

View File

@@ -1,38 +1,19 @@
package app.organicmaps.routing;
package app.organicmaps.sdk.routing;
import android.content.Context;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import androidx.annotation.DimenRes;
import androidx.annotation.IntRange;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.util.Pair;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.Router;
import app.organicmaps.sdk.bookmarks.data.FeatureId;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.routing.ResultCodes;
import app.organicmaps.sdk.routing.RouteMarkData;
import app.organicmaps.sdk.routing.RouteMarkType;
import app.organicmaps.sdk.routing.RoutePointInfo;
import app.organicmaps.sdk.routing.RouteRecommendationType;
import app.organicmaps.sdk.routing.RoutingInfo;
import app.organicmaps.sdk.routing.RoutingListener;
import app.organicmaps.sdk.routing.RoutingLoadPointsListener;
import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.sdk.routing.RoutingProgressListener;
import app.organicmaps.sdk.routing.TransitRouteInfo;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.location.LocationHelper;
import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.placepage.CoordinatesFormat;
import java.time.LocalTime;
import java.util.concurrent.TimeUnit;
import app.organicmaps.sdk.widget.placepage.CoordinatesFormat;
@androidx.annotation.UiThread
public class RoutingController
@@ -114,7 +95,7 @@ public class RoutingController
mLastMissingMaps = missingMaps;
mContainsCachedResult = true;
if (mLastResultCode == ResultCodes.NO_ERROR || ResultCodesHelper.isMoreMapsNeeded(mLastResultCode))
if (mLastResultCode == ResultCodes.NO_ERROR || resultCode == ResultCodes.NEED_MORE_MAPS)
{
onBuiltRoute();
}
@@ -180,7 +161,7 @@ public class RoutingController
return;
}
if (!ResultCodesHelper.isMoreMapsNeeded(mLastResultCode))
if (mLastResultCode != ResultCodes.NEED_MORE_MAPS)
{
setBuildState(BuildState.ERROR);
mLastBuildProgress = 0;
@@ -195,8 +176,7 @@ public class RoutingController
private boolean isDrivingOptionsBuildError()
{
return !ResultCodesHelper.isMoreMapsNeeded(mLastResultCode) && RoutingOptions.hasAnyOptions()
&& !isRulerRouterType();
return mLastResultCode != ResultCodes.NEED_MORE_MAPS && RoutingOptions.hasAnyOptions() && !isRulerRouterType();
}
private void setState(State newState)
@@ -250,7 +230,7 @@ public class RoutingController
mContainer = container;
}
public void initialize(@NonNull Context context)
public void initialize(@NonNull LocationHelper locationHelper)
{
mLastRouterType = Router.getLastUsed();
mInvalidRoutePointsTransactionId = Framework.nativeInvalidRoutePointsTransactionId();
@@ -260,7 +240,7 @@ public class RoutingController
Framework.nativeSetRouteProgressListener(mRoutingProgressListener);
Framework.nativeSetRoutingRecommendationListener(recommendation -> UiThread.run(() -> {
if (recommendation == RouteRecommendationType.RebuildAfterPointsLoading)
setStartPoint(MwmApplication.from(context).getLocationHelper().getMyPosition());
setStartPoint(locationHelper.getMyPosition());
}));
Framework.nativeSetRoutingLoadPointsListener(mRoutingLoadPointsListener);
}
@@ -557,7 +537,7 @@ public class RoutingController
return mLastRouterType == Router.Vehicle;
}
boolean isRulerRouterType()
public boolean isRulerRouterType()
{
return mLastRouterType == Router.Ruler;
}
@@ -883,26 +863,4 @@ public class RoutingController
mWaitingPoiPickType = null;
}
public static CharSequence formatRoutingTime(Context context, int seconds, @DimenRes int unitsSize)
{
return formatRoutingTime(context, seconds, unitsSize, R.dimen.text_size_routing_number);
}
public static CharSequence formatRoutingTime(Context context, int seconds, @DimenRes int unitsSize,
@DimenRes int textSize)
{
long minutes = TimeUnit.SECONDS.toMinutes(seconds) % 60;
long hours = TimeUnit.SECONDS.toHours(seconds);
String min = context.getString(R.string.minute);
String hour = context.getString(R.string.hour);
SpannableStringBuilder displayedH = Utils.formatTime(context, textSize, unitsSize, String.valueOf(hours), hour);
SpannableStringBuilder displayedM = Utils.formatTime(context, textSize, unitsSize, String.valueOf(minutes), min);
return hours == 0 ? displayedM : TextUtils.concat(displayedH + "\u00A0", displayedM);
}
static String formatArrivalTime(int seconds)
{
final LocalTime time = LocalTime.now().plusSeconds(seconds);
return StringUtils.formatUsingUsLocale("%d:%02d", time.getHour(), time.getMinute());
}
}

View File

@@ -1,4 +1,4 @@
package app.organicmaps.settings;
package app.organicmaps.sdk.settings;
/**
* Represents storage option.

View File

@@ -1,4 +1,4 @@
package app.organicmaps.settings;
package app.organicmaps.sdk.settings;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
@@ -28,7 +28,7 @@ public class StoragePathManager
private static final String TAG = StoragePathManager.class.getSimpleName();
private static final String DATA_FILE_EXT = Framework.nativeGetDataFileExt();
private static final String[] MOVABLE_EXTS = Framework.nativeGetMovableFilesExts();
static final FilenameFilter MOVABLE_FILES_FILTER = (dir, filename) ->
public static final FilenameFilter MOVABLE_FILES_FILTER = (dir, filename) ->
{
for (String ext : MOVABLE_EXTS)
if (filename.endsWith(ext))
@@ -37,7 +37,7 @@ public class StoragePathManager
return false;
};
interface OnStorageListChangedListener
public interface OnStorageListChangedListener
{
void onStorageListChanged(List<StorageItem> storageItems, int currentStorageIndex);
}

View File

@@ -231,7 +231,7 @@ public final class Config
return defaultTheme;
}
static void setCurrentUiTheme(@NonNull Context context, @NonNull String theme)
public static void setCurrentUiTheme(@NonNull Context context, @NonNull String theme)
{
if (getCurrentUiTheme(context).equals(theme))
return;

View File

@@ -1,7 +1,5 @@
package app.organicmaps.sdk.util;
import app.organicmaps.BuildConfig;
public final class Constants
{
public static final int KB = 1024;
@@ -36,13 +34,6 @@ public final class Constants
private Url() {}
}
public static class Email
{
public static final String SUPPORT = BuildConfig.SUPPORT_MAIL;
private Email() {}
}
public static class Package
{
public static final String FB_PACKAGE = "com.facebook.katana";

View File

@@ -1,4 +1,4 @@
package app.organicmaps.widget.placepage;
package app.organicmaps.sdk.widget.placepage;
public enum CoordinatesFormat
{

View File

@@ -26,12 +26,12 @@ import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.base.BaseMwmFragment;
import app.organicmaps.downloader.CountrySuggestFragment;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.FeatureId;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.search.SearchEngine;
import app.organicmaps.sdk.search.SearchListener;
import app.organicmaps.sdk.search.SearchRecents;

View File

@@ -8,7 +8,7 @@ import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.search.SearchRecents;
import app.organicmaps.util.Graphics;
import app.organicmaps.widget.SearchToolbarController;

View File

@@ -10,7 +10,7 @@ import androidx.recyclerview.widget.RecyclerView;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.base.BaseMwmRecyclerFragment;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.widget.PlaceholderView;
import app.organicmaps.widget.SearchToolbarController;

View File

@@ -11,7 +11,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.widget.SwitchCompat;
import app.organicmaps.R;
import app.organicmaps.base.BaseMwmToolbarFragment;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.routing.RoutingOptions;
import app.organicmaps.sdk.settings.RoadType;
import java.util.ArrayList;

View File

@@ -35,8 +35,8 @@ import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.NetworkPolicy;
import app.organicmaps.sdk.util.PowerManagment;
import app.organicmaps.sdk.util.SharedPropertiesUtils;
import app.organicmaps.sdk.util.ThemeSwitcher;
import app.organicmaps.sdk.util.log.LogsManager;
import app.organicmaps.util.ThemeSwitcher;
import app.organicmaps.util.Utils;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import java.util.ArrayList;

View File

@@ -11,6 +11,8 @@ import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.CheckedTextView;
import app.organicmaps.R;
import app.organicmaps.sdk.settings.StorageItem;
import app.organicmaps.sdk.settings.StoragePathManager;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.util.ThemeUtils;

View File

@@ -12,6 +12,8 @@ import androidx.activity.result.ActivityResultLauncher;
import androidx.annotation.NonNull;
import app.organicmaps.R;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.settings.StorageItem;
import app.organicmaps.sdk.settings.StoragePathManager;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.StorageUtils;
import app.organicmaps.sdk.util.concurrency.ThreadPool;

View File

@@ -1,4 +1,4 @@
package app.organicmaps.sdk.util;
package app.organicmaps.util;
import android.app.Activity;
import android.app.UiModeManager;
@@ -10,12 +10,11 @@ import androidx.appcompat.app.AppCompatDelegate;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.downloader.DownloaderStatusIcon;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.MapStyle;
import app.organicmaps.sdk.display.DisplayManager;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.Config;
import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.util.ThemeUtils;
import java.util.Calendar;
public enum ThemeSwitcher
@@ -150,6 +149,7 @@ public enum ThemeSwitcher
*
* @return theme_light/dark string
*/
@NonNull
private String calcAutoTheme()
{
String defaultTheme = mContext.getResources().getString(R.string.theme_default);

View File

@@ -41,12 +41,15 @@ import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.sdk.util.Constants;
import app.organicmaps.sdk.util.Distance;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.sdk.util.log.Logger;
import app.organicmaps.sdk.util.log.LogsManager;
import com.google.android.material.snackbar.Snackbar;
import java.lang.ref.WeakReference;
import java.time.LocalTime;
import java.util.concurrent.TimeUnit;
@Keep
public class Utils
@@ -259,7 +262,7 @@ public class Utils
subject =
activity.getString(R.string.project_name) + " Bug Report" + (TextUtils.isEmpty(subject) ? "" : ": " + subject);
LogsManager.INSTANCE.zipLogs(
new SupportInfoWithLogsCallback(launcher, activity, subject, body, Constants.Email.SUPPORT));
new SupportInfoWithLogsCallback(launcher, activity, subject, body, BuildConfig.SUPPORT_MAIL));
}
// TODO: Don't send logs with general feedback, send system information only (version, device name, connectivity,
@@ -268,7 +271,7 @@ public class Utils
@NonNull Activity activity)
{
LogsManager.INSTANCE.zipLogs(new SupportInfoWithLogsCallback(
launcher, activity, activity.getString(R.string.project_name) + " Feedback", "", Constants.Email.SUPPORT));
launcher, activity, activity.getString(R.string.project_name) + " Feedback", "", BuildConfig.SUPPORT_MAIL));
}
public static void navigateToParent(@NonNull Activity activity)
@@ -460,4 +463,30 @@ public class Utils
return getPackageInfoOld(manager, packageName, flags);
return manager.getPackageInfo(packageName, PackageManager.PackageInfoFlags.of(flags));
}
@NonNull
public static CharSequence formatRoutingTime(Context context, int seconds, @DimenRes int unitsSize)
{
return formatRoutingTime(context, seconds, unitsSize, R.dimen.text_size_routing_number);
}
@NonNull
public static CharSequence formatRoutingTime(Context context, int seconds, @DimenRes int unitsSize,
@DimenRes int textSize)
{
long minutes = TimeUnit.SECONDS.toMinutes(seconds) % 60;
long hours = TimeUnit.SECONDS.toHours(seconds);
String min = context.getString(R.string.minute);
String hour = context.getString(R.string.hour);
SpannableStringBuilder displayedH = Utils.formatTime(context, textSize, unitsSize, String.valueOf(hours), hour);
SpannableStringBuilder displayedM = Utils.formatTime(context, textSize, unitsSize, String.valueOf(minutes), min);
return hours == 0 ? displayedM : TextUtils.concat(displayedH + "\u00A0", displayedM);
}
@NonNull
public static String formatArrivalTime(int seconds)
{
final LocalTime time = LocalTime.now().plusSeconds(seconds);
return StringUtils.formatUsingUsLocale("%d:%02d", time.getHour(), time.getMinute());
}
}

View File

@@ -10,11 +10,11 @@ import androidx.annotation.Nullable;
import androidx.core.widget.NestedScrollView;
import app.organicmaps.ChartController;
import app.organicmaps.R;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.ElevationInfo;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.widget.placepage.PlacePageData;
import app.organicmaps.util.Utils;
import java.util.Objects;
@SuppressWarnings("unused") // https://github.com/organicmaps/organicmaps/issues/2829
@@ -72,8 +72,8 @@ public class ElevationProfileViewRenderer implements PlacePageStateListener
mMaxAltitude.setText(formatDistance(context, mElevationInfo.getMaxAltitude()));
mMinAltitude.setText(formatDistance(context, mElevationInfo.getMinAltitude()));
UiUtils.hideIf(mElevationInfo.getDuration() == 0, mTimeContainer);
mTime.setText(RoutingController.formatRoutingTime(mTitle.getContext(), (int) mElevationInfo.getDuration(),
R.dimen.text_size_body_2));
mTime.setText(
Utils.formatRoutingTime(mTitle.getContext(), (int) mElevationInfo.getDuration(), R.dimen.text_size_body_2));
}
@NonNull

View File

@@ -25,12 +25,12 @@ import app.organicmaps.MwmActivity;
import app.organicmaps.R;
import app.organicmaps.api.Const;
import app.organicmaps.intent.Factory;
import app.organicmaps.routing.RoutingController;
import app.organicmaps.sdk.ChoosePositionMode;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.BookmarkManager;
import app.organicmaps.sdk.bookmarks.data.MapObject;
import app.organicmaps.sdk.bookmarks.data.RoadWarningMarkType;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.settings.RoadType;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.log.Logger;

View File

@@ -30,8 +30,7 @@ import app.organicmaps.MwmActivity;
import app.organicmaps.MwmApplication;
import app.organicmaps.R;
import app.organicmaps.downloader.DownloaderStatusIcon;
import app.organicmaps.editor.OhState; //pastk: move?
import app.organicmaps.routing.RoutingController;
import app.organicmaps.editor.OhState;
import app.organicmaps.sdk.Framework;
import app.organicmaps.sdk.bookmarks.data.DistanceAndAzimut;
import app.organicmaps.sdk.bookmarks.data.MapObject;
@@ -39,15 +38,17 @@ import app.organicmaps.sdk.bookmarks.data.Metadata;
import app.organicmaps.sdk.downloader.CountryItem;
import app.organicmaps.sdk.downloader.MapManager;
import app.organicmaps.sdk.editor.Editor;
import app.organicmaps.sdk.editor.OpeningHours; //pastk: a part of Editor?
import app.organicmaps.sdk.editor.OpeningHours;
import app.organicmaps.sdk.editor.data.HoursMinutes;
import app.organicmaps.sdk.editor.data.Timetable;
import app.organicmaps.sdk.location.LocationListener;
import app.organicmaps.sdk.location.SensorListener;
import app.organicmaps.sdk.routing.RoutingController;
import app.organicmaps.sdk.util.DateUtils;
import app.organicmaps.sdk.util.StringUtils;
import app.organicmaps.sdk.util.UiUtils;
import app.organicmaps.sdk.util.concurrency.UiThread;
import app.organicmaps.sdk.widget.placepage.CoordinatesFormat;
import app.organicmaps.util.SharingUtils;
import app.organicmaps.util.Utils;
import app.organicmaps.widget.ArrowView;