Added OsmAndCore-sample

This commit is contained in:
Alexey Kulish 2016-06-15 22:05:12 +03:00
parent 2176a23b86
commit 32ead7416e
48 changed files with 1629 additions and 1 deletions

13
OsmAndCore-sample/.gitignore vendored Normal file
View file

@ -0,0 +1,13 @@
# Android Studio
/.idea
*.iml
# Gradle
.gradle
/local.properties
# MacOSX
.DS_Store
# Output
/build

View file

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.osmand.core.samples.android.sample1" >
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:allowBackup="true"
android:icon="@mipmap/sample_app"
android:label="@string/app_name"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/title_activity_main">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>

View file

@ -0,0 +1,92 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 23
buildToolsVersion "23.0.3"
defaultConfig {
minSdkVersion 14
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
lintOptions {
abortOnError false
}
// This is from OsmAndCore_android.aar - for some reason it's not inherited
aaptOptions {
// Don't compress any embedded resources
noCompress "qz"
}
sourceSets {
main {
manifest.srcFile "AndroidManifest.xml"
jni.srcDirs = []
jniLibs.srcDirs = ["libs"]
java.srcDirs = ["src"]
resources.srcDirs = ["src"]
renderscript.srcDirs = ["src"]
res.srcDirs = ["res"]
assets.srcDirs = ["assets"]
}
}
productFlavors {
x86 {
ndk {
abiFilter "x86"
}
}
mips {
ndk {
abiFilter "mips"
}
}
armv7 {
ndk {
abiFilter "armeabi-v7a"
}
}
armv5 {
ndk {
abiFilter "armeabi"
}
}
fat
}
buildTypes {
debug {
signingConfig android.signingConfigs.debug
}
nativeDebug {
signingConfig android.signingConfigs.debug
}
release {
signingConfig android.signingConfigs.debug
}
}
}
repositories {
ivy {
name = "OsmAndBinariesIvy"
url = "http://builder.osmand.net"
layout "pattern" , {
artifact "ivy/[organisation]/[module]/[revision]/[artifact]-[revision].[ext]"
}
}
}
dependencies {
compile project(path: ':OsmAnd-java', configuration: 'android')
compile 'com.android.support:appcompat-v7:23.3.0'
compile fileTree(dir: "libs", include: ["*.jar"])
compile "net.osmand:OsmAndCore_android:0.1-SNAPSHOT@aar"
debugCompile "net.osmand:OsmAndCore_androidNativeRelease:0.1-SNAPSHOT@aar"
nativeDebugCompile "net.osmand:OsmAndCore_androidNativeDebug:0.1-SNAPSHOT@aar"
releaseCompile "net.osmand:OsmAndCore_androidNativeRelease:0.1-SNAPSHOT@aar"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/btn_circle_p" android:state_pressed="true"/>
<item android:drawable="@drawable/btn_circle_n"></item>
</selector>

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<bitmap
android:gravity="fill"
android:src="@drawable/map_bt_round_1_shadow" />
</item>
<item>
<inset
android:insetBottom="2dp"
android:insetLeft="2dp"
android:insetRight="2dp"
android:insetTop="2dp" >
<shape android:shape="oval" >
<solid android:color="#fff" />
</shape>
</inset>
</item>
</layer-list>

View file

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<bitmap
android:gravity="fill"
android:src="@drawable/map_bt_round_1_shadow" />
</item>
<item>
<inset
android:insetBottom="2dp"
android:insetLeft="2dp"
android:insetRight="2dp"
android:insetTop="2dp" >
<shape android:shape="oval" >
<solid android:color="#fff" />
</shape>
</inset>
</item>
</layer-list>

View file

@ -0,0 +1,120 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="net.osmand.core.samples.android.sample1.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="@color/colorPrimary"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageButton
android:id="@+id/clearButton"
style="@style/Widget.AppCompat.ActionButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:contentDescription="@string/shared_string_close"
android:src="@drawable/ic_action_remove_dark"/>
<EditText
android:id="@+id/searchEditText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:background="@null"
android:hint="@string/search_hint"
android:gravity="center_vertical"
android:lines="1"
android:textColor="@color/titleTextColor"
tools:text="Search request"/>
</LinearLayout>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:foreground="@drawable/bg_contextmenu_shadow"
android:foregroundGravity="top|fill_horizontal">
<net.osmand.core.android.AtlasMapRendererView
android:id="@+id/mapRendererView"
android:focusable="true"
android:focusableInTouchMode="true"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|right"
android:layout_marginRight="10dp"
android:layout_marginTop="10dp">
<ImageButton
android:id="@+id/map_azimuth_north_button"
android:layout_width="52dp"
android:layout_height="52dp"
android:background="@drawable/btn_circle"
android:contentDescription="@string/azimuthNorth"
android:src="@drawable/map_compass_niu"/>
</FrameLayout>
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|right"
android:layout_marginBottom="10dp"
android:layout_marginRight="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/text_zoom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="10"
android:textColor="#000"
android:textSize="18sp"
android:textStyle="bold"/>
<ImageButton
android:id="@+id/map_zoom_in_button"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginTop="10dp"
android:background="@drawable/btn_circle"
android:contentDescription="@string/zoomIn"
android:src="@drawable/map_zoom_in"/>
<ImageButton
android:id="@+id/map_zoom_out_button"
android:layout_width="52dp"
android:layout_height="52dp"
android:layout_marginTop="10dp"
android:background="@drawable/btn_circle"
android:contentDescription="@string/zoomOut"
android:src="@drawable/map_zoom_out"/>
</LinearLayout>
</FrameLayout>
<ListView
android:id="@android:id/list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:drawSelectorOnTop="true"
android:background="@color/listBackgroundColor"
android:visibility="gone"/>
</FrameLayout>
</LinearLayout>

View file

@ -0,0 +1,58 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="?attr/listPreferredItemHeight"
android:orientation="horizontal"
android:paddingBottom="12dp"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:paddingTop="8dp">
<ImageView
android:id="@+id/imageView"
android:layout_width="36dp"
android:layout_height="36dp"
android:layout_gravity="center"
android:visibility="gone"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingRight="16dp"
android:textAppearance="@style/TextAppearance.AppCompat.Subhead"
tools:text="Amsterdam"/>
<TextView
android:id="@+id/distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="right"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
tools:text="100 km"/>
</LinearLayout>
<TextView
android:id="@+id/subtitle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
tools:text="City"/>
</LinearLayout>
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

View file

@ -0,0 +1,6 @@
<resources>
<!-- Example customization of dimensions originally defined in res/values/dimens.xml
(such as screen margins) for screens with more than 820dp of available width. This
would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
<dimen name="activity_horizontal_margin">64dp</dimen>
</resources>

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#ff8f00</color>
<color name="colorPrimaryDark">#e68200</color>
<color name="colorAccent">#FF4081</color>
<color name="dividerColor">#F0F0F0</color>
<color name="windowBackgroundColor">#EAEAEA</color>
<color name="itemBackgroundColor">#FFF</color>
<color name="iconColor">#727272</color>
<color name="dialogTitleBackgroundColor">#2f7af5</color>
<color name="listBackgroundColor">#EAEAEA</color>
<color name="titleTextColor">#FFF</color>
<color name="listTextColor">#000</color>
</resources>

View file

@ -0,0 +1,6 @@
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
<dimen name="list_content_padding">16dp</dimen>
</resources>

View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">OsmAnd Core API sample 1 for Android OS</string>
<string name="title_activity_main">OsmAnd Core Sample 1</string>
<string name="zoomIn">Zoom in</string>
<string name="zoomOut">Zoom out</string>
<string name="azimuthNorth">Azimuth to North</string>
<string name="search_hint">Type and Search</string>
<string name="shared_string_close">Close</string>
</resources>

View file

@ -0,0 +1,11 @@
<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="android:windowBackground">@color/windowBackgroundColor</item>
<item name="android:colorBackground">@color/windowBackgroundColor</item>
</style>
</resources>

View file

@ -0,0 +1,546 @@
package net.osmand.core.samples.android.sample1;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.graphics.PointF;
import android.os.Bundle;
import android.os.Environment;
import android.support.v4.view.ViewCompat;
import android.support.v4.view.ViewPropertyAnimatorListener;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.GestureDetector;
import android.view.GestureDetector.SimpleOnGestureListener;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import android.widget.TextView;
import net.osmand.core.android.AtlasMapRendererView;
import net.osmand.core.android.CoreResourcesFromAndroidAssets;
import net.osmand.core.android.NativeCore;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.IMapLayerProvider;
import net.osmand.core.jni.IMapStylesCollection;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.LogSeverityLevel;
import net.osmand.core.jni.Logger;
import net.osmand.core.jni.MapObjectsSymbolsProvider;
import net.osmand.core.jni.MapPresentationEnvironment;
import net.osmand.core.jni.MapPrimitivesProvider;
import net.osmand.core.jni.MapPrimitiviser;
import net.osmand.core.jni.MapRasterLayerProvider_Software;
import net.osmand.core.jni.MapStylesCollection;
import net.osmand.core.jni.ObfMapObjectsProvider;
import net.osmand.core.jni.ObfsCollection;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QIODeviceLogSink;
import net.osmand.core.jni.ResolvedMapStyle;
import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.MultiTouchSupport.MultiTouchZoomListener;
import net.osmand.core.samples.android.sample1.SearchAPI.SearchAPICallback;
import net.osmand.core.samples.android.sample1.SearchAPI.SearchItem;
import net.osmand.core.samples.android.sample1.SearchUIHelper.SearchListAdapter;
import net.osmand.core.samples.android.sample1.SearchUIHelper.SearchRow;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
public class MainActivity extends Activity {
private static final String TAG = "OsmAndCoreSample";
private float displayDensityFactor;
private int referenceTileSize;
private int rasterTileSize;
private IMapStylesCollection mapStylesCollection;
private ResolvedMapStyle mapStyle;
private ObfsCollection obfsCollection;
private MapPresentationEnvironment mapPresentationEnvironment;
private MapPrimitiviser mapPrimitiviser;
private ObfMapObjectsProvider obfMapObjectsProvider;
private MapPrimitivesProvider mapPrimitivesProvider;
private MapObjectsSymbolsProvider mapObjectsSymbolsProvider;
private IMapLayerProvider mapLayerProvider0;
private IMapLayerProvider mapLayerProvider1;
private QIODeviceLogSink fileLogSink;
private AtlasMapRendererView mapView;
private TextView textZoom;
private ImageButton azimuthNorthButton;
private GestureDetector gestureDetector;
private PointI target31;
private float zoom;
private float azimuth;
private float elevationAngle;
private MultiTouchSupport multiTouchSupport;
private SearchAPI searchAPI;
private ListView searchListView;
private SearchListAdapter adapter;
private final static int MAX_SEARCH_RESULTS = 50;
// Germany
private final static float INIT_LAT = 49.353953f;
private final static float INIT_LON = 11.214384f;
// Kyiv
//private final static float INIT_LAT = 50.450117f;
//private final static float INIT_LON = 30.524142f;
private final static float INIT_ZOOM = 6.0f;
private final static float INIT_AZIMUTH = 0.0f;
private final static float INIT_ELEVATION_ANGLE = 90.0f;
private final static int MIN_ZOOM_LEVEL = 2;
private final static int MAX_ZOOM_LEVEL = 22;
private static final String PREF_MAP_CENTER_LAT = "MAP_CENTER_LAT";
private static final String PREF_MAP_CENTER_LON = "MAP_CENTER_LON";
private static final String PREF_MAP_AZIMUTH = "MAP_AZIMUTH";
private static final String PREF_MAP_ZOOM = "MAP_ZOOM";
private static final String PREF_MAP_ELEVATION_ANGLE = "MAP_ELEVATION_ANGLE";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
gestureDetector = new GestureDetector(this, new MapViewOnGestureListener());
multiTouchSupport = new MultiTouchSupport(this, new MapViewMultiTouchZoomListener());
long startTime = System.currentTimeMillis();
// Initialize native core prior (if needed)
if (NativeCore.isAvailable() && !NativeCore.isLoaded())
NativeCore.load(CoreResourcesFromAndroidAssets.loadFromCurrentApplication(this));
Logger.get().setSeverityLevelThreshold(LogSeverityLevel.Debug);
// Inflate views
setContentView(R.layout.activity_main);
// Get map view
mapView = (AtlasMapRendererView) findViewById(R.id.mapRendererView);
textZoom = (TextView) findViewById(R.id.text_zoom);
azimuthNorthButton = (ImageButton) findViewById(R.id.map_azimuth_north_button);
azimuthNorthButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setAzimuth(0f);
}
});
findViewById(R.id.map_zoom_in_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setZoom(zoom + 1f);
}
});
findViewById(R.id.map_zoom_out_button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setZoom(zoom - 1f);
}
});
// Additional log sink
fileLogSink = QIODeviceLogSink.createFileLogSink(
Environment.getExternalStorageDirectory() + "/osmand/osmandcore.log");
Logger.get().addLogSink(fileLogSink);
// Get device display density factor
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
displayDensityFactor = displayMetrics.densityDpi / 160.0f;
referenceTileSize = (int)(256 * displayDensityFactor);
rasterTileSize = Integer.highestOneBit(referenceTileSize - 1) * 2;
Log.i(TAG, "displayDensityFactor = " + displayDensityFactor);
Log.i(TAG, "referenceTileSize = " + referenceTileSize);
Log.i(TAG, "rasterTileSize = " + rasterTileSize);
Log.i(TAG, "Going to resolve default embedded style...");
mapStylesCollection = new MapStylesCollection();
mapStyle = mapStylesCollection.getResolvedStyleByName("default");
if (mapStyle == null)
{
Log.e(TAG, "Failed to resolve style 'default'");
System.exit(0);
}
Log.i(TAG, "Going to prepare OBFs collection");
obfsCollection = new ObfsCollection();
Log.i(TAG, "Will load OBFs from " + Environment.getExternalStorageDirectory() + "/osmand");
obfsCollection.addDirectory(Environment.getExternalStorageDirectory() + "/osmand", false);
Log.i(TAG, "Going to prepare all resources for renderer");
mapPresentationEnvironment = new MapPresentationEnvironment(
mapStyle,
displayDensityFactor,
1.0f,
1.0f,
MapUtils.LANGUAGE);
//mapPresentationEnvironment->setSettings(configuration.styleSettings);
mapPrimitiviser = new MapPrimitiviser(
mapPresentationEnvironment);
obfMapObjectsProvider = new ObfMapObjectsProvider(
obfsCollection);
mapPrimitivesProvider = new MapPrimitivesProvider(
obfMapObjectsProvider,
mapPrimitiviser,
rasterTileSize);
mapObjectsSymbolsProvider = new MapObjectsSymbolsProvider(
mapPrimitivesProvider,
rasterTileSize);
mapView.setReferenceTileSizeOnScreenInPixels(referenceTileSize);
mapView.addSymbolsProvider(mapObjectsSymbolsProvider);
restoreMapState();
mapLayerProvider0 = new MapRasterLayerProvider_Software(mapPrimitivesProvider);
mapView.setMapLayerProvider(0, mapLayerProvider0);
System.out.println("NATIVE_INITIALIZED = " + (System.currentTimeMillis() - startTime) / 1000f);
//Setup search
searchAPI = new SearchAPI(obfsCollection);
final EditText searchEditText = (EditText) findViewById(R.id.searchEditText);
searchEditText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (s.length() > 2) {
runSearch(getScreenBounds31(), s.toString());
}
}
});
searchEditText.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
if (hasFocus && adapter.getCount() > 0 && isSearchListHidden()) {
showSearchList();
LatLon latLon = Utilities.convert31ToLatLon(target31);
adapter.updateDistance(latLon.getLatitude(), latLon.getLongitude());
adapter.notifyDataSetChanged();
}
}
});
ImageButton clearButton = (ImageButton) findViewById(R.id.clearButton);
clearButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
searchEditText.setText("");
adapter.clear();
adapter.notifyDataSetChanged();
hideSearchList();
}
});
searchListView = (ListView) findViewById(android.R.id.list);
adapter = new SearchListAdapter(this);
searchListView.setAdapter(adapter);
searchListView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
hideSearchList();
mapView.requestFocus();
SearchRow item = adapter.getItem(position);
PointI target = Utilities.convertLatLonTo31(new LatLon(item.getLatitude(), item.getLongitude()));
setTarget(target);
setZoom(17f);
}
});
}
@Override
protected void onResume() {
super.onResume();
mapView.handleOnResume();
}
@Override
protected void onPause() {
saveMapState();
mapView.handleOnPause();
super.onPause();
}
@Override
protected void onDestroy() {
mapView.handleOnDestroy();
super.onDestroy();
}
private AreaI getScreenBounds31() {
PointI topLeftPoint = new PointI();
PointI bottomRightPoint = new PointI();
mapView.getLocationFromScreenPoint(new PointI(0, 0), topLeftPoint);
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth(), mapView.getHeight()), bottomRightPoint);
return new AreaI(topLeftPoint, bottomRightPoint);
}
private boolean isSearchListHidden() {
return searchListView.getVisibility() != View.VISIBLE;
}
private void showSearchList() {
if (isSearchListHidden()) {
ViewCompat.setAlpha(searchListView, 0f);
searchListView.setVisibility(View.VISIBLE);
ViewCompat.animate(searchListView).alpha(1f).setListener(null);
}
}
private void hideSearchList() {
ViewCompat.animate(searchListView).alpha(0f).setListener(new ViewPropertyAnimatorListener() {
@Override
public void onAnimationStart(View view) {
}
@Override
public void onAnimationEnd(View view) {
searchListView.setVisibility(View.GONE);
}
@Override
public void onAnimationCancel(View view) {
searchListView.setVisibility(View.GONE);
}
});
}
public void saveMapState() {
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
Editor edit = prefs.edit();
LatLon latLon = Utilities.convert31ToLatLon(target31);
edit.putFloat(PREF_MAP_CENTER_LAT, (float)latLon.getLatitude());
edit.putFloat(PREF_MAP_CENTER_LON, (float)latLon.getLongitude());
edit.putFloat(PREF_MAP_AZIMUTH, azimuth);
edit.putFloat(PREF_MAP_ZOOM, zoom);
edit.putFloat(PREF_MAP_ELEVATION_ANGLE, elevationAngle);
edit.commit();
}
public void restoreMapState() {
SharedPreferences prefs = getPreferences(MODE_PRIVATE);
float prefLat = prefs.getFloat(PREF_MAP_CENTER_LAT, INIT_LAT);
float prefLon = prefs.getFloat(PREF_MAP_CENTER_LON, INIT_LON);
float prefAzimuth = prefs.getFloat(PREF_MAP_AZIMUTH, INIT_AZIMUTH);
float prefZoom = prefs.getFloat(PREF_MAP_ZOOM, INIT_ZOOM);
float prefElevationAngle = prefs.getFloat(PREF_MAP_ELEVATION_ANGLE, INIT_ELEVATION_ANGLE);
setAzimuth(prefAzimuth);
setElevationAngle(prefElevationAngle);
setTarget(Utilities.convertLatLonTo31(new LatLon(prefLat, prefLon)));
setZoom(prefZoom);
}
public boolean setTarget(PointI pointI) {
target31 = pointI;
return mapView.setTarget(pointI);
}
@SuppressLint("DefaultLocale")
public boolean setZoom(float zoom) {
if (zoom < MIN_ZOOM_LEVEL) {
zoom = MIN_ZOOM_LEVEL;
} else if (zoom > MAX_ZOOM_LEVEL) {
zoom = MAX_ZOOM_LEVEL;
}
this.zoom = zoom;
textZoom.setText(String.format("%.0f", zoom));
return mapView.setZoom(zoom);
}
public void setAzimuth(float angle) {
angle = MapUtils.unifyRotationTo360(angle);
this.azimuth = angle;
mapView.setAzimuth(angle);
if (angle == 0f && azimuthNorthButton.getVisibility() == View.VISIBLE) {
azimuthNorthButton.setVisibility(View.INVISIBLE);
} else if (angle != 0f && azimuthNorthButton.getVisibility() == View.INVISIBLE) {
azimuthNorthButton.setVisibility(View.VISIBLE);
}
}
public void setElevationAngle(float angle) {
if (angle < 35f) {
angle = 35f;
} else if (angle > 90f) {
angle = 90f;
}
this.elevationAngle = angle;
mapView.setElevationAngle(angle);
}
public boolean onTouchEvent(MotionEvent event) {
return multiTouchSupport.onTouchEvent(event)
|| gestureDetector.onTouchEvent(event);
}
private void runSearch(AreaI bounds31, String keyword) {
searchAPI.setObfAreaFilter(bounds31);
searchAPI.startSearch(keyword, MAX_SEARCH_RESULTS, new SearchAPICallback() {
@Override
public void onSearchFinished(List<SearchItem> searchItems, boolean cancelled) {
if (searchItems != null && !cancelled) {
LatLon latLon = Utilities.convert31ToLatLon(target31);
List<SearchRow> rows = new ArrayList<>();
for (SearchItem item : searchItems) {
SearchRow row = new SearchRow(item);
rows.add(row);
}
adapter.clear();
adapter.addAll(rows);
adapter.updateDistance(latLon.getLatitude(), latLon.getLongitude());
adapter.sort(new Comparator<SearchRow>() {
@Override
public int compare(SearchRow lhs, SearchRow rhs) {
int res = Double.compare(lhs.getDistance(), rhs.getDistance());
if (res == 0) {
return lhs.getSearchItem().getLocalizedName().compareToIgnoreCase(rhs.getSearchItem().getLocalizedName());
} else {
return res;
}
}
});
adapter.notifyDataSetChanged();
if (adapter.getCount() > 0) {
searchListView.setSelection(0);
}
showSearchList();
}
}
});
}
private class MapViewOnGestureListener extends SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
mapView.requestFocus();
return true;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
float fromX = e2.getX() + distanceX;
float fromY = e2.getY() + distanceY;
float toX = e2.getX();
float toY = e2.getY();
float dx = (fromX - toX);
float dy = (fromY - toY);
PointI newTarget = new PointI();
mapView.getLocationFromScreenPoint(new PointI(mapView.getWidth() / 2 + (int)dx, mapView.getHeight() / 2 + (int)dy), newTarget);
setTarget(newTarget);
mapView.requestFocus();
return true;
}
}
private class MapViewMultiTouchZoomListener implements MultiTouchZoomListener {
private float initialZoom;
private float initialAzimuth;
private float initialElevation;
private PointF centerPoint;
@Override
public void onGestureFinished(float scale, float rotation) {
}
@Override
public void onGestureInit(float x1, float y1, float x2, float y2) {
}
@Override
public void onZoomStarted(PointF centerPoint) {
initialZoom = zoom;
initialAzimuth = azimuth;
this.centerPoint = centerPoint;
}
@Override
public void onZoomingOrRotating(float scale, float rotation) {
PointI centerLocationBefore = new PointI();
mapView.getLocationFromScreenPoint(
new PointI((int)centerPoint.x, (int)centerPoint.y), centerLocationBefore);
// Change zoom
setZoom(initialZoom + (float)(Math.log(scale) / Math.log(2)));
// Adjust current target position to keep touch center the same
PointI centerLocationAfter = new PointI();
mapView.getLocationFromScreenPoint(
new PointI((int)centerPoint.x, (int)centerPoint.y), centerLocationAfter);
PointI centerLocationDelta = new PointI(
centerLocationAfter.getX() - centerLocationBefore.getX(),
centerLocationAfter.getY() - centerLocationBefore.getY());
setTarget(new PointI(target31.getX() - centerLocationDelta.getX(), target31.getY() - centerLocationDelta.getY()));
/*
// Convert point from screen to location
PointI centerLocation = new PointI();
mapView.getLocationFromScreenPoint(
new PointI((int)centerPoint.x, (int)centerPoint.y), centerLocation);
// Rotate current target around center location
PointI target = new PointI(xI - centerLocation.getX(), yI - centerLocation.getY());
double cosAngle = Math.cos(-Math.toRadians(rotation));
double sinAngle = Math.sin(-Math.toRadians(rotation));
PointI newTarget = new PointI(
(int)(target.getX() * cosAngle - target.getY() * sinAngle + centerLocation.getX()),
(int)(target.getX() * sinAngle + target.getY() * cosAngle + centerLocation.getY()));
setTarget(newTarget);
*/
// Set rotation
setAzimuth(initialAzimuth - rotation);
}
@Override
public void onChangeViewAngleStarted() {
initialElevation = elevationAngle;
}
@Override
public void onChangingViewAngle(float angle) {
setElevationAngle(initialElevation - angle);
}
}
}

View file

@ -0,0 +1,30 @@
package net.osmand.core.samples.android.sample1;
import java.util.Locale;
public class MapUtils {
public static final String LANGUAGE;
static {
LANGUAGE = getLanguage();
}
public static float unifyRotationTo360(float rotate) {
while (rotate < -180) {
rotate += 360;
}
while (rotate > +180) {
rotate -= 360;
}
return rotate;
}
private static String getLanguage() {
String langCode = Locale.getDefault().getLanguage();
if (langCode.isEmpty()) {
langCode = "en";
}
return langCode;
}
}

View file

@ -0,0 +1,202 @@
package net.osmand.core.samples.android.sample1;
import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
import android.view.MotionEvent;
import java.lang.reflect.Method;
public class MultiTouchSupport {
private static final String TAG = "MultiTouchSupport";
public static final int ACTION_MASK = 255;
protected final Context ctx;
private final MultiTouchZoomListener listener;
protected Method getPointerCount;
protected Method getX;
protected Method getY;
protected Method getPointerId;
private float initialAngle;
private float rotation;
private static final float ROTATION_THRESHOLD_DEG = 15.0f;
private boolean isRotating;
private boolean multiTouchAPISupported = false;
private boolean inTiltMode = false;
private PointF firstFingerStart = new PointF();
private PointF secondFingerStart = new PointF();
private static final int TILT_X_THRESHOLD_PX = 40;
private static final int TILT_Y_THRESHOLD_PX = 40;
private static final int TILT_DY_THRESHOLD_PX = 40;
private boolean inZoomMode = false;
private float initialDistance = 100;
private float scale = 1;
private PointF centerPoint = new PointF();
private boolean multiTouch;
public MultiTouchSupport(Context ctx, MultiTouchZoomListener listener) {
this.ctx = ctx;
this.listener = listener;
initMethods();
}
public boolean isMultiTouchSupported(){
return multiTouchAPISupported;
}
public boolean isInZoomMode(){
return inZoomMode;
}
public boolean isInTiltMode() {
return inTiltMode;
}
private void initMethods() {
try {
getPointerCount = MotionEvent.class.getMethod("getPointerCount"); //$NON-NLS-1$
getPointerId = MotionEvent.class.getMethod("getPointerId", Integer.TYPE); //$NON-NLS-1$
getX = MotionEvent.class.getMethod("getX", Integer.TYPE); //$NON-NLS-1$
getY = MotionEvent.class.getMethod("getY", Integer.TYPE); //$NON-NLS-1$
multiTouchAPISupported = true;
} catch (Exception e) {
multiTouchAPISupported = false;
}
}
public boolean onTouchEvent(MotionEvent event){
if(!isMultiTouchSupported()){
return false;
}
int actionCode = event.getAction() & ACTION_MASK;
try {
if (actionCode == MotionEvent.ACTION_UP || actionCode == MotionEvent.ACTION_CANCEL) {
multiTouch = false;
}
Integer pointCount = (Integer) getPointerCount.invoke(event);
if (pointCount < 2) {
if (inZoomMode || inTiltMode) {
listener.onGestureFinished(scale, rotation);
inZoomMode = false;
inTiltMode = false;
}
return multiTouch;
} else {
multiTouch = true;
}
Float x1 = (Float) getX.invoke(event, 0);
Float x2 = (Float) getX.invoke(event, 1);
Float y1 = (Float) getY.invoke(event, 0);
Float y2 = (Float) getY.invoke(event, 1);
float distance = (float) Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1));
float angle = 0;
boolean angleDefined = false;
if (x1.floatValue() != x2.floatValue() || y1.floatValue() != y2.floatValue()) {
angleDefined = true;
angle = (float) (Math.atan2(y2 - y1, x2 -x1) * 180 / Math.PI);
}
switch (actionCode) {
case MotionEvent.ACTION_POINTER_DOWN: {
centerPoint = new PointF((x1 + x2) / 2, (y1 + y2) / 2);
firstFingerStart = new PointF(x1, y1);
secondFingerStart = new PointF(x2, y2);
listener.onGestureInit(x1, y1, x2, y2);
return true;
}
case MotionEvent.ACTION_POINTER_UP: {
if (inZoomMode || inTiltMode) {
listener.onGestureFinished(scale, rotation);
inZoomMode = false;
inTiltMode = false;
}
return true;
}
case MotionEvent.ACTION_MOVE: {
if (inZoomMode) {
if (angleDefined) {
float a = MapUtils.unifyRotationTo360(angle - initialAngle);
if (!isRotating && Math.abs(a) > ROTATION_THRESHOLD_DEG) {
isRotating = true;
initialAngle = angle;
} else if (isRotating) {
rotation = a;
}
}
scale = distance / initialDistance;
listener.onZoomingOrRotating(scale, rotation);
return true;
} else if (inTiltMode) {
float dy2 = secondFingerStart.y - y2;
float viewAngle = dy2 / 8f;
listener.onChangingViewAngle(viewAngle);
} else {
float dx1 = Math.abs(firstFingerStart.x - x1);
float dx2 = Math.abs(secondFingerStart.x - x2);
float dy1 = Math.abs(firstFingerStart.y - y1);
float dy2 = Math.abs(secondFingerStart.y - y2);
float startDy = Math.abs(secondFingerStart.y - firstFingerStart.y);
if (dx1 < TILT_X_THRESHOLD_PX && dx2 < TILT_X_THRESHOLD_PX
&& dy1 > TILT_Y_THRESHOLD_PX && dy2 > TILT_Y_THRESHOLD_PX
&& startDy < TILT_Y_THRESHOLD_PX * 6
&& Math.abs(dy2 - dy1) < TILT_DY_THRESHOLD_PX) {
listener.onChangeViewAngleStarted();
inTiltMode = true;
} else if (dx1 > TILT_X_THRESHOLD_PX || dx2 > TILT_X_THRESHOLD_PX
|| Math.abs(dy2 - dy1) > TILT_DY_THRESHOLD_PX
|| Math.abs(dy1 - dy2) > TILT_DY_THRESHOLD_PX) {
listener.onZoomStarted(centerPoint);
initialDistance = distance;
initialAngle = angle;
rotation = 0;
scale = 0;
isRotating = false;
inZoomMode = true;
}
}
}
default:
break;
}
} catch (Exception e) {
Log.e(TAG, "Multi touch exception" , e); //$NON-NLS-1$
}
return true;
}
public PointF getCenterPoint() {
return centerPoint;
}
public interface MultiTouchZoomListener {
void onZoomStarted(PointF centerPoint);
void onZoomingOrRotating(float scale, float rotation);
void onChangeViewAngleStarted();
void onChangingViewAngle(float angle);
void onGestureFinished(float scale, float rotation);
void onGestureInit(float x1, float y1, float x2, float y2);
}
}

View file

@ -0,0 +1,306 @@
package net.osmand.core.samples.android.sample1;
import android.os.AsyncTask;
import net.osmand.core.jni.AmenitiesByNameSearch;
import net.osmand.core.jni.Amenity;
import net.osmand.core.jni.Amenity.DecodedCategory;
import net.osmand.core.jni.AreaI;
import net.osmand.core.jni.DecodedCategoryList;
import net.osmand.core.jni.IObfsCollection;
import net.osmand.core.jni.IQueryController;
import net.osmand.core.jni.ISearch;
import net.osmand.core.jni.LatLon;
import net.osmand.core.jni.NullableAreaI;
import net.osmand.core.jni.ObfInfo;
import net.osmand.core.jni.ObfsCollection;
import net.osmand.core.jni.PointI;
import net.osmand.core.jni.QStringStringHash;
import net.osmand.core.jni.Utilities;
import java.util.ArrayList;
import java.util.List;
public class SearchAPI {
private ObfsCollection obfsCollection;
private AreaI searchableArea;
private AreaI obfAreaFilter;
private SearchRequestExecutor executor;
interface SearchAPICallback {
void onSearchFinished(List<SearchItem> searchItems, boolean cancelled);
}
public SearchAPI(ObfsCollection obfsCollection) {
this.obfsCollection = obfsCollection;
executor = new SearchRequestExecutor();
}
public AreaI getSearchableArea() {
return searchableArea;
}
public void setSearchableArea(AreaI searchableArea) {
this.searchableArea = searchableArea;
}
public AreaI getObfAreaFilter() {
return obfAreaFilter;
}
public void setObfAreaFilter(AreaI obfAreaFilter) {
this.obfAreaFilter = obfAreaFilter;
}
public void startSearch(String keyword, int maxSearchResults, SearchAPICallback apiCallback) {
executor.run(new SearchRequest(keyword, maxSearchResults, apiCallback), true);
}
public void cancelSearch() {
executor.cancel();
}
public class SearchRequestExecutor {
private SearchRequest ongoingSearchRequest;
private SearchRequest nextSearchRequest;
public void run(SearchRequest searchRequest, boolean cancelCurrentRequest) {
if (ongoingSearchRequest != null) {
nextSearchRequest = searchRequest;
if (cancelCurrentRequest) {
ongoingSearchRequest.cancel();
}
} else {
ongoingSearchRequest = searchRequest;
nextSearchRequest = null;
searchRequest.setOnFinishedCallback(new Runnable() {
@Override
public void run() {
operationFinished();
}
});
searchRequest.run();
}
}
public void cancel() {
if (nextSearchRequest != null) {
nextSearchRequest = null;
}
if (ongoingSearchRequest != null) {
ongoingSearchRequest.cancel();
}
}
private void operationFinished() {
ongoingSearchRequest = null;
if (nextSearchRequest != null) {
run(nextSearchRequest, false);
}
}
}
public class SearchRequest {
private String keyword;
private int maxSearchResults;
private Runnable onFinished;
private SearchAPICallback apiCallback;
private boolean cancelled;
private int resCount;
public SearchRequest(String keyword, int maxSearchResults, SearchAPICallback apiCallback) {
this.keyword = keyword;
this.maxSearchResults = maxSearchResults;
this.apiCallback = apiCallback;
}
public void run() {
new AsyncTask<String, Void, List<SearchItem>>() {
@Override
protected List<SearchItem> doInBackground(String... params) {
return doSearch(params[0]);
}
@Override
protected void onPostExecute(List<SearchItem> searchItems) {
if (onFinished != null) {
onFinished.run();
}
if (apiCallback != null) {
apiCallback.onSearchFinished(searchItems, cancelled);
}
}
}.execute(keyword);
}
private List<SearchItem> doSearch(String keyword) {
System.out.println("=== Start search");
resCount = 0;
final List<SearchItem> searchItems = new ArrayList<>();
AmenitiesByNameSearch byNameSearch = new AmenitiesByNameSearch(obfsCollection);
AmenitiesByNameSearch.Criteria criteria = new AmenitiesByNameSearch.Criteria();
criteria.setName(keyword);
if (obfAreaFilter != null) {
criteria.setObfInfoAreaFilter(new NullableAreaI(new AreaI(obfAreaFilter)));
}
ISearch.INewResultEntryCallback newResultEntryCallback = new ISearch.INewResultEntryCallback() {
@Override
public void method(ISearch.Criteria criteria, ISearch.IResultEntry resultEntry) {
Amenity amenity = new ResultEntry(resultEntry).getAmenity();
searchItems.add(new AmenitySearchItem(amenity));
System.out.println("Poi found === " + amenity.getNativeName());
resCount++;
/*
QStringStringHash locNames = amenity.getLocalizedNames();
if (locNames.size() > 0) {
QStringList keys = locNames.keys();
StringBuilder sb = new StringBuilder("=== Localized names: ");
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
sb.append(key).append("=").append(locNames.get(key)).append(" | ");
}
System.out.println(sb.toString());
}
*/
}
};
byNameSearch.performSearch(criteria, newResultEntryCallback.getBinding(), new IQueryController() {
@Override
public boolean isAborted() {
return resCount >= maxSearchResults || cancelled;
}
});
System.out.println("=== Finish search");
return searchItems;
}
public void cancel() {
cancelled = true;
}
public void setOnFinishedCallback(Runnable onFinished) {
this.onFinished = onFinished;
}
}
private static class ResultEntry extends AmenitiesByNameSearch.ResultEntry {
protected ResultEntry(ISearch.IResultEntry resultEntry) {
super(ISearch.IResultEntry.getCPtr(resultEntry), false);
}
}
public static abstract class SearchItem {
protected double latitude;
protected double longitude;
public SearchItem(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public SearchItem(PointI location31) {
LatLon latLon = Utilities.convert31ToLatLon(location31);
latitude = latLon.getLatitude();
longitude = latLon.getLongitude();
}
public abstract String getNativeName();
public abstract String getLocalizedName();
public abstract String getTypeName();
public abstract String getSubTypeName();
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
@Override
public String toString() {
return getNativeName() + " {lat:" + getLatitude() + " lon: " + getLongitude() + "}";
}
}
public static class AmenitySearchItem extends SearchItem {
private String nativeName;
private String localizedName;
private String category;
private String subcategory;
public AmenitySearchItem(Amenity amenity) {
super(amenity.getPosition31());
nativeName = amenity.getNativeName();
QStringStringHash locNames = amenity.getLocalizedNames();
if (locNames.has_key(MapUtils.LANGUAGE)) {
localizedName = locNames.get(MapUtils.LANGUAGE);
}
/*
if (locNames.size() > 0) {
QStringList keys = locNames.keys();
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
localizedNamesMap.put(key, locNames.get(key));
}
}
*/
DecodedCategoryList catList = amenity.getDecodedCategories();
if (catList.size() > 0) {
DecodedCategory decodedCategory = catList.get(0);
category = decodedCategory.getCategory();
subcategory = decodedCategory.getSubcategory();
}
}
@Override
public String getNativeName() {
return nativeName;
}
@Override
public String getLocalizedName() {
return localizedName != null ? localizedName : nativeName;
}
@Override
public String getTypeName() {
return category;
}
@Override
public String getSubTypeName() {
return subcategory;
}
@Override
public double getLatitude() {
return latitude;
}
@Override
public double getLongitude() {
return longitude;
}
}
}

View file

@ -0,0 +1,139 @@
package net.osmand.core.samples.android.sample1;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.TextView;
import net.osmand.core.jni.Utilities;
import net.osmand.core.samples.android.sample1.SearchAPI.SearchItem;
import java.text.MessageFormat;
public class SearchUIHelper {
public static Drawable getIcon(Context ctx, SearchItem item) {
return null;
}
public static class SearchRow {
private SearchItem searchItem;
private double distance;
public SearchRow(SearchItem searchItem) {
this.searchItem = searchItem;
}
public SearchItem getSearchItem() {
return searchItem;
}
public double getLatitude() {
return searchItem.getLatitude();
}
public double getLongitude() {
return searchItem.getLongitude();
}
public double getDistance() {
return distance;
}
public void setDistance(double distance) {
this.distance = distance;
}
}
public static class SearchListAdapter extends ArrayAdapter<SearchRow> {
private Context ctx;
public SearchListAdapter(Context ctx) {
super(ctx, R.layout.search_list_item);
this.ctx = ctx;
}
public void updateDistance(double latitude, double longitude) {
for (int i = 0; i < getCount(); i++) {
SearchRow item = getItem(i);
item.setDistance(Utilities.distance(
longitude, latitude,
item.getLongitude(), item.getLatitude()));
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
SearchRow item = getItem(position);
LinearLayout view;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) ctx
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = (LinearLayout) inflater.inflate(
R.layout.search_list_item, null);
} else {
view = (LinearLayout) convertView;
}
TextView title = (TextView) view.findViewById(R.id.title);
TextView subtitle = (TextView) view.findViewById(R.id.subtitle);
TextView distance = (TextView) view.findViewById(R.id.distance);
title.setText(item.searchItem.getLocalizedName());
StringBuilder sb = new StringBuilder();
if (!item.searchItem.getSubTypeName().isEmpty()) {
sb.append(getNiceString(item.searchItem.getSubTypeName()));
}
if (!item.searchItem.getTypeName().isEmpty()) {
if (sb.length() > 0) {
sb.append("");
}
sb.append(getNiceString(item.searchItem.getTypeName()));
}
subtitle.setText(sb.toString());
if (item.getDistance() == 0) {
distance.setText("");
} else {
distance.setText(getFormattedDistance(item.getDistance()));
}
//text1.setTextColor(ctx.getResources().getColor(R.color.listTextColor));
//view.setCompoundDrawablesWithIntrinsicBounds(getIcon(ctx, item), null, null, null);
//view.setCompoundDrawablePadding(ctx.getResources().getDimensionPixelSize(R.dimen.list_content_padding));
return view;
}
}
public static String capitalizeFirstLetterAndLowercase(String s) {
if (s != null && s.length() > 1) {
// not very efficient algorithm
return Character.toUpperCase(s.charAt(0)) + s.substring(1).toLowerCase();
} else {
return s;
}
}
public static String getNiceString(String s) {
return capitalizeFirstLetterAndLowercase(s.replaceAll("_", " "));
}
public static String getFormattedDistance(double meters) {
double mainUnitInMeters = 1000;
String mainUnitStr = "km";
if (meters >= 100 * mainUnitInMeters) {
return (int) (meters / mainUnitInMeters + 0.5) + " " + mainUnitStr;
} else if (meters > 9.99f * mainUnitInMeters) {
return MessageFormat.format("{0,number,#.#} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
} else if (meters > 0.999f * mainUnitInMeters) {
return MessageFormat.format("{0,number,#.##} " + mainUnitStr, ((float) meters) / mainUnitInMeters).replace('\n', ' ');
} else {
return ((int) (meters + 0.5)) + " m";
}
}
}

View file

@ -1,4 +1,4 @@
include ':OsmAnd-java' include ':OsmAnd-java', ':OsmAndCore-sample'
include ':OsmAnd' include ':OsmAnd'
include ':plugins:OsmAnd-AddressPlugin' include ':plugins:OsmAnd-AddressPlugin'
include ':plugins:Osmand-ParkingPlugin' include ':plugins:Osmand-ParkingPlugin'