Merge branch 'master' into trip_recording_process

# Conflicts:
#	OsmAnd/res/values/strings.xml
#	OsmAnd/src/net/osmand/plus/track/GpxBlockStatisticsBuilder.java
This commit is contained in:
Skalii 2021-02-08 17:47:06 +02:00
commit b1100e3c00
79 changed files with 1583 additions and 924 deletions

View file

@ -1,12 +0,0 @@
---
name: "📚 Outdated FAQ"
about: Report an issue in FAQ
---
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑
Please do not file FAQ issues on the GitHub issues tracker.
Instead use the [Google group](https://groups.google.com/forum/#!forum/osmand) to fix wrong or outdated FAQ.
🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑🛑

4
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View file

@ -0,0 +1,4 @@
contact_links:
- name: Outdated FAQ
url: https://groups.google.com/forum/#!forum/osmand
about: Fix wrong or outdated FAQ on the forum instead

View file

@ -38,6 +38,11 @@ public class ProfileSettingsParams extends AidlParams {
this.silent = silent;
}
public ProfileSettingsParams(Uri profileSettingsUri, List<AExportSettingsType> settingsTypeList,
boolean replace, String latestChanges, int version) {
this(profileSettingsUri, settingsTypeList, replace, false, latestChanges, version);
}
public ProfileSettingsParams(Parcel in) {
readFromParcel(in);
}

View file

@ -23,7 +23,9 @@ public class PlatformUtil {
}
public static XmlPullParser newXMLPullParser() throws XmlPullParserException{
return new org.kxml2.io.KXmlParser();
org.kxml2.io.KXmlParser xmlParser = new org.kxml2.io.KXmlParser();
xmlParser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
return xmlParser;
}
public static XmlSerializer newSerializer() {

View file

@ -8,6 +8,7 @@ import gnu.trove.set.hash.TIntHashSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
@ -627,7 +628,9 @@ public class BinaryMapAddressReaderAdapter {
indexOffset = codedIS.getTotalBytesRead();
int oldLimit = codedIS.pushLimit(length);
// here offsets are sorted by distance
map.readIndexedStringTable(stringMatcher.getCollator(), req.nameQuery, "", loffsets, 0);
TIntArrayList charsList = new TIntArrayList();
charsList.add(0);
map.readIndexedStringTable(stringMatcher.getCollator(), Collections.singletonList(req.nameQuery), "", Collections.singletonList(loffsets), charsList);
codedIS.popLimit(oldLimit);
break;
case OsmAndAddressNameIndexData.ATOM_FIELD_NUMBER:

View file

@ -2161,9 +2161,9 @@ public class BinaryMapIndexReader {
private static boolean testAddressSearch = false;
private static boolean testAddressSearchName = false;
private static boolean testAddressJustifySearch = false;
private static boolean testPoiSearch = false;
private static boolean testPoiSearch = true;
private static boolean testPoiSearchOnPath = false;
private static boolean testTransportSearch = true;
private static boolean testTransportSearch = false;
private static int sleft = MapUtils.get31TileNumberX(27.55079);
private static int sright = MapUtils.get31TileNumberX(27.55317);
@ -2177,7 +2177,7 @@ public class BinaryMapIndexReader {
public static void main(String[] args) throws IOException {
File fl = new File(System.getProperty("maps") + "/Synthetic_test_rendering.obf");
fl = new File("/home/madwasp79/OsmAnd-maps/Poly_center2.obf");
fl = new File(System.getProperty("maps") +"/Wikivoyage.obf__");
RandomAccessFile raf = new RandomAccessFile(fl, "r");
@ -2325,7 +2325,7 @@ public class BinaryMapIndexReader {
private static void testPoiSearchByName(BinaryMapIndexReader reader) throws IOException {
println("Searching by name...");
SearchRequest<Amenity> req = buildSearchPoiRequest(0, 0, "Art",
SearchRequest<Amenity> req = buildSearchPoiRequest(0, 0, "central ukraine",
0, Integer.MAX_VALUE, 0, Integer.MAX_VALUE, null);
reader.searchPoiByName(req);
@ -2385,54 +2385,72 @@ public class BinaryMapIndexReader {
}
int readIndexedStringTable(Collator instance, String query, String prefix, TIntArrayList list, int charMatches) throws IOException {
void readIndexedStringTable(Collator instance, List<String> queries, String prefix, List<TIntArrayList> listOffsets, TIntArrayList matchedCharacters) throws IOException {
String key = null;
boolean[] matched = new boolean[matchedCharacters.size()];
boolean shouldWeReadSubtable = false;
while (true) {
int t = codedIS.readTag();
int tag = WireFormat.getTagFieldNumber(t);
switch (tag) {
case 0:
return charMatches;
return;
case OsmandOdb.IndexedStringTable.KEY_FIELD_NUMBER :
key = codedIS.readString();
if(prefix.length() > 0){
if (prefix.length() > 0) {
key = prefix + key;
}
// check query is part of key (the best matching)
if(CollatorStringMatcher.cmatches(instance, key, query, StringMatcherMode.CHECK_ONLY_STARTS_WITH)){
if(query.length() >= charMatches){
if(query.length() > charMatches){
charMatches = query.length();
list.clear();
}
} else {
key = null;
shouldWeReadSubtable = false;
for (int i = 0; i < queries.size(); i++) {
int charMatches = matchedCharacters.get(i);
String query = queries.get(i);
matched[i] = false;
if (query == null) {
continue;
}
// check key is part of query
} else if (CollatorStringMatcher.cmatches(instance, query, key, StringMatcherMode.CHECK_ONLY_STARTS_WITH)) {
if (key.length() >= charMatches) {
if (key.length() > charMatches) {
charMatches = key.length();
list.clear();
// check query is part of key (the best matching)
if (CollatorStringMatcher.cmatches(instance, key, query, StringMatcherMode.CHECK_ONLY_STARTS_WITH)) {
if (query.length() >= charMatches) {
if (query.length() > charMatches) {
matchedCharacters.set(i, query.length());
listOffsets.get(i).clear();
}
matched[i] = true;
}
// check key is part of query
} else if (CollatorStringMatcher.cmatches(instance, query, key, StringMatcherMode.CHECK_ONLY_STARTS_WITH)) {
if (key.length() >= charMatches) {
if (key.length() > charMatches) {
matchedCharacters.set(i, key.length());
listOffsets.get(i).clear();
}
matched[i] = true;
}
} else {
key = null;
}
} else {
key = null;
shouldWeReadSubtable |= matched[i];
}
break;
case OsmandOdb.IndexedStringTable.VAL_FIELD_NUMBER :
int val = readInt();
if (key != null) {
list.add(val);
for (int i = 0; i < queries.size(); i++) {
if (matched[i]) {
listOffsets.get(i).add(val);
}
}
break;
case OsmandOdb.IndexedStringTable.SUBTABLES_FIELD_NUMBER :
int len = codedIS.readRawVarint32();
int oldLim = codedIS.pushLimit(len);
if (key != null) {
charMatches = readIndexedStringTable(instance, query, key, list, charMatches);
if (shouldWeReadSubtable && key != null) {
List<String> subqueries = new ArrayList<>(queries);
// reset query so we don't search what was not matched
for(int i = 0; i < queries.size(); i++) {
if(!matched[i]) {
subqueries.set(i, null);
}
}
readIndexedStringTable(instance, subqueries, key, listOffsets, matchedCharacters);
} else {
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
}

View file

@ -1,10 +1,6 @@
package net.osmand.binary;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntLongHashMap;
import gnu.trove.set.hash.TLongHashSet;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
@ -12,6 +8,14 @@ import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.WireFormat;
import gnu.trove.list.array.TIntArrayList;
import gnu.trove.map.hash.TIntLongHashMap;
import gnu.trove.set.hash.TLongHashSet;
import net.osmand.Collator;
import net.osmand.CollatorStringMatcher;
import net.osmand.CollatorStringMatcher.StringMatcherMode;
@ -26,11 +30,6 @@ import net.osmand.osm.MapPoiTypes;
import net.osmand.osm.PoiCategory;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import com.google.protobuf.CodedInputStream;
import com.google.protobuf.WireFormat;
public class BinaryMapPoiReaderAdapter {
private static final Log LOG = PlatformUtil.getLog(BinaryMapPoiReaderAdapter.class);
@ -38,7 +37,7 @@ public class BinaryMapPoiReaderAdapter {
private static final int CATEGORY_MASK = (1 << SHIFT_BITS_CATEGORY) - 1;
private static final int ZOOM_TO_SKIP_FILTER_READ = 6;
private static final int ZOOM_TO_SKIP_FILTER = 3;
private static final int BUCKET_SEARCH_BY_NAME = 5;
private static final int BUCKET_SEARCH_BY_NAME = 15; // should be bigger 100?
public static class PoiSubType {
public boolean text;
@ -332,7 +331,7 @@ public class BinaryMapPoiReaderAdapter {
});
int p = BUCKET_SEARCH_BY_NAME * 3;
if (p < offKeys.length) {
for (int i = p + BUCKET_SEARCH_BY_NAME; ; i += BUCKET_SEARCH_BY_NAME) {
for (int i = p + BUCKET_SEARCH_BY_NAME;; i += BUCKET_SEARCH_BY_NAME) {
if (i > offKeys.length) {
Arrays.sort(offKeys, p, offKeys.length);
break;
@ -344,7 +343,6 @@ public class BinaryMapPoiReaderAdapter {
}
}
LOG.info("Searched poi structure in " + (System.currentTimeMillis() - time) +
"ms. Found " + offKeys.length + " subtrees");
for (int j = 0; j < offKeys.length; j++) {
@ -370,7 +368,8 @@ public class BinaryMapPoiReaderAdapter {
private TIntLongHashMap readPoiNameIndex(Collator instance, String query, SearchRequest<Amenity> req) throws IOException {
TIntLongHashMap offsets = new TIntLongHashMap();
TIntArrayList dataOffsets = null;
List<TIntArrayList> listOffsets = null;
List<TIntLongHashMap> listOfSepOffsets = new ArrayList<TIntLongHashMap>();
int offset = 0;
while (true) {
int t = codedIS.readTag();
@ -381,24 +380,51 @@ public class BinaryMapPoiReaderAdapter {
case OsmandOdb.OsmAndPoiNameIndex.TABLE_FIELD_NUMBER: {
int length = readInt();
int oldLimit = codedIS.pushLimit(length);
dataOffsets = new TIntArrayList();
offset = codedIS.getTotalBytesRead();
map.readIndexedStringTable(instance, query, "", dataOffsets, 0);
List<String> queries = new ArrayList<>();
for (String word : query.split(" ")) {
if (word.trim().length() > 0) {
queries.add(word.trim());
}
}
TIntArrayList charsList = new TIntArrayList(queries.size());
listOffsets = new ArrayList<TIntArrayList>(queries.size());
while(listOffsets.size() < queries.size()) {
charsList.add(0);
listOffsets.add(new TIntArrayList());
}
map.readIndexedStringTable(instance, queries, "", listOffsets, charsList);
codedIS.popLimit(oldLimit);
break;
}
case OsmandOdb.OsmAndPoiNameIndex.DATA_FIELD_NUMBER: {
if (dataOffsets != null) {
dataOffsets.sort(); // 1104125
for (int i = 0; i < dataOffsets.size(); i++) {
codedIS.seek(dataOffsets.get(i) + offset);
int len = codedIS.readRawVarint32();
int oldLim = codedIS.pushLimit(len);
readPoiNameIndexData(offsets, req);
codedIS.popLimit(oldLim);
if (req.isCancelled()) {
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
return offsets;
if (listOffsets != null) {
for (TIntArrayList dataOffsets : listOffsets) {
TIntLongHashMap offsetMap = new TIntLongHashMap();
listOfSepOffsets.add(offsetMap);
dataOffsets.sort(); // 1104125
for (int i = 0; i < dataOffsets.size(); i++) {
codedIS.seek(dataOffsets.get(i) + offset);
int len = codedIS.readRawVarint32();
int oldLim = codedIS.pushLimit(len);
readPoiNameIndexData(offsetMap, req);
codedIS.popLimit(oldLim);
if (req.isCancelled()) {
codedIS.skipRawBytes(codedIS.getBytesUntilLimit());
return offsets;
}
}
}
}
if (listOfSepOffsets.size() > 0) {
offsets.putAll(listOfSepOffsets.get(0));
for (int j = 1; j < listOfSepOffsets.size(); j++) {
TIntLongHashMap mp = listOfSepOffsets.get(j);
// offsets.retainAll(mp); -- calculate intresection of mp & offsets
for (int chKey : offsets.keys()) {
if (!mp.containsKey(chKey)) {
offsets.remove(chKey);
}
}
}
}

View file

@ -0,0 +1,20 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:pathData="M3,19V16H5V19H19V16H21V19C21,20.1046 20.1046,21 19,21H5C3.8954,21 3,20.1046 3,19Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M8,12.5858V4H10V12.5858L12.2929,10.2929L13.7071,11.7071L9,16.4142L4.2929,11.7071L5.7071,10.2929L8,12.5858Z"
android:fillColor="#ffffff"
android:fillType="evenOdd"/>
<path
android:pathData="M14,12.5858V4H16V12.5858L18.2929,10.2929L19.7071,11.7071L15,16.4142L11.2929,12.7071L12.7071,11.2929L14,12.5858Z"
android:strokeAlpha="0.5"
android:fillColor="#ffffff"
android:fillType="evenOdd"
android:fillAlpha="0.5"/>
</vector>

View file

@ -1,36 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/bg_color"
android:clickable="true"
android:focusable="true"
android:orientation="vertical">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/bg_color"
android:orientation="vertical">
<LinearLayout
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height"
android:layout_marginTop="@dimen/dialog_content_margin">
android:gravity="center_vertical"
android:padding="0dp" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/back_button"
style="@style/Widget.AppCompat.Toolbar.Button.Navigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:contentDescription="@string/shared_string_back"
app:srcCompat="@drawable/ic_arrow_back"
app:tint="@color/icon_color_default_light" />
</LinearLayout>
<androidx.core.widget.NestedScrollView
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@id/toolbar"
android:layout_above="@id/buttons">
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
@ -49,7 +35,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/dashPadding"
android:gravity="center_horizontal"
@ -68,23 +54,25 @@
android:layout_marginTop="@dimen/dashPadding"
android:layout_marginRight="@dimen/content_padding"
android:lineSpacingMultiplier="@dimen/bottom_sheet_text_spacing_multiplier"
app:typeface="@string/font_roboto_regular"
android:text="@string/register_on_openplacereviews_desc"
android:textColor="?android:textColorPrimary"
android:textColorLink="@color/icon_color_active_light"
android:textSize="@dimen/default_list_text_size"
android:textColorLink="@color/icon_color_active_light" />
app:typeface="@string/font_roboto_regular" />
</LinearLayout>
</androidx.core.widget.NestedScrollView>
</ScrollView>
<LinearLayout
android:id="@+id/buttons"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginLeft="@dimen/content_padding"
android:layout_marginTop="@dimen/content_padding_small"
android:layout_marginRight="@dimen/content_padding"
android:layout_marginBottom="@dimen/content_padding_small"
android:layout_alignParentBottom="true"
android:orientation="vertical">
<include
@ -102,4 +90,4 @@
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View file

@ -1,5 +1,4 @@
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
@ -8,7 +7,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:layout_height="wrap_content"
android:minHeight="@dimen/context_menu_action_buttons_height"
android:background="?attr/pstsTabBackground"
android:gravity="center_vertical"
android:orientation="horizontal">
@ -19,19 +19,19 @@
android:layout_width="52dp"
android:layout_height="52dp"
android:contentDescription="@string/shared_string_close"
app:srcCompat="@drawable/ic_action_remove_dark"/>
app:srcCompat="@drawable/ic_action_remove_dark" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/titleTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="20dp"
android:layout_marginLeft="20dp"
android:text="@string/osm_live_subscription"
android:textColor="@color/color_white"
android:textSize="@dimen/default_list_text_size_large"
android:textStyle="bold"
app:typeface="@string/font_roboto_regular"
android:layout_marginStart="20dp" />
app:typeface="@string/font_roboto_regular" />
</LinearLayout>
@ -39,7 +39,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/card_bottom_divider"/>
<include layout="@layout/card_bottom_divider" />
<ScrollView
android:layout_width="match_parent"
@ -67,8 +67,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="8dp"
android:layout_marginBottom="8dp"
android:minHeight="56dp"
android:orientation="horizontal">
@ -76,54 +76,81 @@
android:layout_width="56dp"
android:layout_height="48dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_action_osm_live"
android:tint="@color/osmand_orange"/>
android:tint="@color/osmand_orange"
app:srcCompat="@drawable/ic_action_osm_live" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:paddingStart="2dp"
android:paddingLeft="2dp"
android:text="@string/osm_live_subscription_desc"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginEnd="16dp"
android:paddingStart="2dp"
android:layout_marginStart="16dp" />
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
android:minHeight="56dp"
android:orientation="vertical">
android:orientation="horizontal">
<androidx.appcompat.widget.AppCompatCheckBox
android:id="@+id/donationCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:paddingLeft="34dp"
android:text="@string/donation_to_osm"
android:paddingStart="34dp"
android:layout_marginStart="16dp" />
android:layout_marginTop="@dimen/context_menu_second_line_top_margin"
android:layout_marginStart="@dimen/list_content_padding"
android:layout_marginLeft="@dimen/list_content_padding"
android:paddingStart="@dimen/local_size_height"
android:paddingLeft="@dimen/local_size_height"
android:paddingEnd="@dimen/local_size_height"
android:paddingRight="@dimen/local_size_height"
android:text="@string/donation_to_osm" />
<TextView
android:layout_width="match_parent"
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="72dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:paddingLeft="2dp"
android:text="@string/donation_to_osm_desc"
android:textColor="?android:attr/textColorSecondary"
android:layout_marginEnd="16dp"
android:layout_marginStart="72dp"
android:paddingStart="2dp" />
android:minHeight="56dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/list_content_padding_large"
android:layout_marginLeft="@dimen/context_menu_progress_padding_left"
android:layout_marginEnd="@dimen/context_menu_progress_padding_left"
android:layout_marginRight="@dimen/context_menu_progress_padding_left"
android:paddingStart="@dimen/subHeaderPadding"
android:paddingLeft="@dimen/subHeaderPadding"
android:paddingEnd="@dimen/subHeaderPadding"
android:paddingRight="@dimen/subHeaderPadding"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_list_text_size"
android:text="@string/donation_to_osm" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/list_content_padding_large"
android:layout_marginLeft="@dimen/context_menu_progress_padding_left"
android:layout_marginEnd="@dimen/context_menu_progress_padding_left"
android:layout_marginRight="@dimen/context_menu_progress_padding_left"
android:paddingStart="@dimen/subHeaderPadding"
android:paddingLeft="@dimen/subHeaderPadding"
android:paddingEnd="@dimen/subHeaderPadding"
android:paddingRight="@dimen/subHeaderPadding"
android:text="@string/donation_to_osm_desc"
android:textColor="?android:attr/textColorSecondary"/>
</LinearLayout>
</LinearLayout>
@ -140,13 +167,13 @@
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="6dp"
android:background="?attr/dashboard_divider"/>
android:background="?attr/dashboard_divider" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginTop="4dp"
android:layout_marginBottom="8dp"
android:minHeight="56dp"
android:orientation="horizontal">
@ -155,47 +182,48 @@
android:layout_width="56dp"
android:layout_height="48dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_world_globe_dark"/>
app:srcCompat="@drawable/ic_world_globe_dark" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:orientation="vertical"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp">
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="2dp"
android:paddingStart="@dimen/subHeaderPadding"
android:paddingEnd="@dimen/subHeaderPadding"
android:paddingLeft="@dimen/subHeaderPadding"
android:paddingRight="@dimen/subHeaderPadding"
android:text="@string/osm_live_support_region"
android:textColor="?android:attr/textColorSecondary"
android:paddingStart="2dp" />
android:textColor="?android:attr/textColorSecondary" />
<net.osmand.plus.widgets.AutoCompleteTextViewEx
android:id="@+id/selectCountryEdit"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
app:drawableRightCompat="@drawable/ic_action_arrow_drop_down"
app:drawableEndCompat="@drawable/ic_action_arrow_drop_down"
android:editable="false"
android:paddingStart="2dp"
android:paddingLeft="2dp"
android:paddingEnd="0dp"
android:paddingRight="0dp"
android:text="Ukraine"
android:paddingStart="2dp"
android:paddingEnd="0dp" />
app:drawableEndCompat="@drawable/ic_action_arrow_drop_down"
app:drawableRightCompat="@drawable/ic_action_arrow_drop_down" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:paddingStart="2dp"
android:paddingLeft="2dp"
android:text="@string/osm_live_region_desc"
android:textColor="?android:attr/textColorSecondary"
android:paddingStart="2dp" />
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
@ -213,21 +241,21 @@
android:layout_width="56dp"
android:layout_height="48dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_action_message"/>
app:srcCompat="@drawable/ic_action_message" />
<EditText
android:id="@+id/emailEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:hint="@string/shared_string_email_address"
android:inputType="textEmailAddress"
android:paddingLeft="2dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:paddingStart="2dp" />
android:paddingStart="2dp"
android:paddingLeft="2dp" />
</LinearLayout>
@ -235,14 +263,14 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="72dp"
android:layout_marginLeft="72dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:paddingStart="2dp"
android:paddingLeft="2dp"
android:text="@string/osm_live_email_desc"
android:textColor="?android:attr/textColorSecondary"
android:paddingStart="2dp"
android:layout_marginStart="72dp"
android:layout_marginEnd="16dp" />
android:textColor="?android:attr/textColorSecondary" />
<LinearLayout
@ -261,21 +289,21 @@
android:layout_width="56dp"
android:layout_height="48dp"
android:scaleType="center"
app:srcCompat="@drawable/ic_action_user"/>
app:srcCompat="@drawable/ic_action_user" />
<EditText
android:id="@+id/userNameEdit"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="16dp"
android:layout_marginLeft="16dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:hint="@string/osm_live_user_public_name"
android:inputType="text"
android:paddingLeft="2dp"
android:layout_marginEnd="16dp"
android:layout_marginStart="16dp"
android:paddingStart="2dp" />
android:paddingStart="2dp"
android:paddingLeft="2dp" />
</LinearLayout>
@ -284,16 +312,16 @@
android:id="@+id/hideUserNameCheckbox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="12dp"
android:layout_marginStart="72dp"
android:layout_marginLeft="72dp"
android:layout_marginRight="16dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="12dp"
android:paddingStart="4dp"
android:paddingLeft="4dp"
android:text="@string/osm_live_hide_user_name"
android:textColor="?android:attr/textColorPrimary"
android:layout_marginEnd="16dp"
android:paddingStart="4dp"
android:layout_marginStart="72dp" />
android:textColor="?android:attr/textColorPrimary" />
</LinearLayout>
@ -303,35 +331,35 @@
android:id="@+id/editModeBottomView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:layout_marginTop="16dp"
android:layout_marginBottom="16dp"
android:visibility="visible">
<Button
android:id="@+id/saveChangesButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="72dp"
android:layout_marginLeft="72dp"
android:layout_marginEnd="16dp"
android:layout_marginRight="16dp"
android:background="?attr/btn_round"
android:paddingStart="16dp"
android:paddingLeft="16dp"
android:paddingEnd="16dp"
android:paddingRight="16dp"
android:text="@string/shared_string_save_changes"
android:textColor="@color/color_white"
android:layout_marginStart="72dp"
android:layout_marginEnd="16dp"
android:paddingStart="16dp"
android:paddingEnd="16dp" />
android:textColor="@color/color_white" />
</LinearLayout>
</LinearLayout>
<include layout="@layout/card_bottom_divider"/>
<include layout="@layout/card_bottom_divider" />
<View
android:layout_width="match_parent"
android:layout_height="16dp"/>
android:layout_height="16dp" />
</LinearLayout>

View file

@ -24,7 +24,7 @@
android:layout_gravity="center_vertical"
android:layout_marginRight="@dimen/favorites_icon_right_margin"
tools:src="@drawable/ic_map"
android:layout_marginEnd="@dimen/favorites_icon_right_margin" />
android:layout_marginEnd="@dimen/favorites_icon_right_margin" />
<LinearLayout
android:layout_width="0dp"
@ -81,26 +81,26 @@
android:visibility="gone"
tools:src="@drawable/ic_action_import"
tools:visibility="visible"
android:layout_marginStart="@dimen/dashFavIconMargin" />
android:layout_marginStart="@dimen/dashFavIconMargin" />
<Button
android:id="@+id/rightButton"
android:layout_width="wrap_content"
android:layout_height="33dp"
android:minWidth="40dp"
android:paddingLeft="18dp"
android:paddingRight="18dp"
android:background="@drawable/buy_btn_background_light"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginStart="@dimen/dashFavIconMargin"
android:layout_marginLeft="@dimen/dashFavIconMargin"
android:layout_marginRight="8dp"
android:textColor="@color/buy_button_color"
android:layout_marginEnd="@dimen/list_header_padding"
android:layout_marginRight="@dimen/list_header_padding"
android:minWidth="@dimen/list_header_height"
android:minHeight="@dimen/list_content_padding_large"
android:paddingStart="@dimen/context_menu_progress_padding_left"
android:paddingLeft="@dimen/context_menu_progress_padding_left"
android:paddingEnd="@dimen/context_menu_progress_padding_left"
android:paddingRight="@dimen/context_menu_progress_padding_left"
android:text="@string/buy"
android:visibility="gone"
android:layout_marginStart="@dimen/dashFavIconMargin"
android:layout_marginEnd="8dp"
android:paddingEnd="18dp"
android:paddingStart="18dp" />
android:textColor="@color/text_color_tab_active_light"
android:visibility="gone" />
</LinearLayout>

View file

@ -4332,5 +4332,17 @@
<string name="poi_wildlife_crossing_bat_bridge">Bat bridge</string>
<string name="poi_wildlife_crossing_bat_tunnel">Bat tunnel</string>
<string name="poi_piste_ski_jump">Ski jump</string>
<string name="poi_piste_name">Piste name</string>
<string name="poi_gladed_yes">Gladed: yes</string>
<string name="poi_patrolled_yes">Patrolled: yes</string>
<string name="poi_patrolled_no">Patrolled: no</string>
<string name="poi_piste_status_open">Piste status: open</string>
<string name="poi_piste_status_closed">Piste status: closed</string>
<string name="poi_summit_register_yes">Summit register: yes</string>
<string name="poi_summit_register_no">Summit register: no</string>
<string name="poi_mobile_library">Mobile library stop position</string>
</resources>

View file

@ -13,6 +13,10 @@
-->
<string name="on_pause">On pause</string>
<string name="login_open_place_reviews">Login to OpenPlaceReviews</string>
<string name="opr_use_dev_url">Use test.openplacereviews.org</string>
<string name="open_place_reviews">OpenPlaceReviews</string>
<string name="open_place_reviews_plugin_description">OpenPlaceReviews is a community-driven project about public places such as restaurants, hotels, museums, waypoints. It collects all public information about them such as photos, reviews, links to other systems link OpenStreetMap, Wikipedia.\n\nAll OpenPlaceReview data is open and available to everyone: http://openplacereviews.org/data.\n\nYou can read more at: http://openplacereviews.org</string>
<string name="hillshade_slope_contour_lines">Hillshade / Slope / Contour lines</string>
<string name="toast_select_edits_for_upload">Select edits for upload</string>
<string name="uploaded_count">Uploaded %1$d of %2$d</string>

View file

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:title="@string/open_place_reviews">
<Preference
android:key="opr_settings_info"
android:layout="@layout/preference_info"
android:persistent="false"
android:selectable="false"
android:title="@string/plugin_global_prefs_info" />
<Preference
android:key="opr_login_data"
android:layout="@layout/preference_with_descr"
android:persistent="false"
android:title="@string/login_open_place_reviews" />
<Preference
android:key="opr_logout"
android:layout="@layout/preference_login"
android:persistent="false"
android:title="@string/login_account" />
<net.osmand.plus.settings.preferences.SwitchPreferenceEx
android:key="opr_use_dev_url"
android:layout="@layout/preference_with_descr_dialog_and_switch"
android:title="@string/opr_use_dev_url"
tools:icon="@drawable/ic_plugin_developer" />
</PreferenceScreen>

View file

@ -63,11 +63,11 @@ public class LocationServiceHelperImpl extends LocationServiceHelper {
// Sets the fastest rate for active location updates. This interval is exact, and your
// application will never receive updates more frequently than this value.
.setFastestInterval(50)
//.setFastestInterval(50)
// Sets the maximum time when batched location updates are delivered. Updates may be
// delivered sooner than this interval.
.setMaxWaitTime(200)
.setMaxWaitTime(0)
.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

View file

@ -28,7 +28,6 @@ import net.osmand.map.OsmandRegions.RegionTranslation;
import net.osmand.map.WorldRegion;
import net.osmand.osm.AbstractPoiType;
import net.osmand.osm.MapPoiTypes;
import net.osmand.plus.helpers.DayNightHelper;
import net.osmand.plus.activities.LocalIndexHelper;
import net.osmand.plus.activities.LocalIndexInfo;
import net.osmand.plus.activities.SavingTrackHelper;
@ -36,6 +35,7 @@ import net.osmand.plus.base.MapViewTrackingUtilities;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.ui.AbstractLoadLocalIndexTask;
import net.osmand.plus.helpers.AvoidSpecificRoads;
import net.osmand.plus.helpers.DayNightHelper;
import net.osmand.plus.helpers.LockHelper;
import net.osmand.plus.helpers.WaypointHelper;
import net.osmand.plus.inapp.InAppPurchaseHelperImpl;
@ -45,6 +45,7 @@ import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
import net.osmand.plus.openplacereviews.OprAuthHelper;
import net.osmand.plus.osmedit.oauth.OsmOAuthHelper;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.quickaction.QuickActionRegistry;
@ -468,6 +469,7 @@ public class AppInitializer implements IProgress {
app.settingsHelper = startupInit(new SettingsHelper(app), SettingsHelper.class);
app.quickActionRegistry = startupInit(new QuickActionRegistry(app.getSettings()), QuickActionRegistry.class);
app.osmOAuthHelper = startupInit(new OsmOAuthHelper(app), OsmOAuthHelper.class);
app.oprAuthHelper = startupInit(new OprAuthHelper(app), OprAuthHelper.class);
app.onlineRoutingHelper = startupInit(new OnlineRoutingHelper(app), OnlineRoutingHelper.class);
initOpeningHoursParser();

View file

@ -8,10 +8,10 @@ import androidx.annotation.Nullable;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.plus.track.GpxSplitType;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.api.SQLiteAPI.SQLiteConnection;
import net.osmand.plus.track.GpxSplitType;
import net.osmand.plus.track.GradientScaleType;
import java.io.File;
@ -238,7 +238,7 @@ public class GpxDbHelper {
gpxFile = readingItems.poll();
while (gpxFile != null && !isCancelled()) {
GpxDataItem item = readingItemsMap.remove(gpxFile);
if (item.getFile() == null) {
if (item != null && item.getFile() == null) {
item = db.getItem(gpxFile, conn);
}
if (isAnalyseNeeded(gpxFile, item)) {

View file

@ -4,16 +4,13 @@ import android.app.Notification;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.plus.helpers.LocationServiceHelper;
import net.osmand.plus.helpers.LocationServiceHelper.LocationCallback;
import net.osmand.plus.notifications.OsmandNotification;
@ -95,12 +92,6 @@ public class NavigationService extends Service {
@Override
public void onLocationAvailability(boolean locationAvailable) {
if (!locationAvailable) {
OsmandApplication app = (OsmandApplication) getApplication();
if (app != null) {
app.showToastMessage(getString(R.string.off_router_service_no_gps_available));
}
}
}
});
} catch (SecurityException e) {
@ -137,10 +128,12 @@ public class NavigationService extends Service {
app.setNavigationService(null);
usedBy = 0;
// remove updates
try {
locationServiceHelper.removeLocationUpdates();
} catch (SecurityException e) {
// Location service permission not granted
if (locationServiceHelper != null) {
try {
locationServiceHelper.removeLocationUpdates();
} catch (SecurityException e) {
// Location service permission not granted
}
}
// remove notification
stopForeground(Boolean.TRUE);

View file

@ -70,6 +70,7 @@ import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.measurementtool.MeasurementEditingContext;
import net.osmand.plus.monitoring.LiveMonitoringHelper;
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
import net.osmand.plus.openplacereviews.OprAuthHelper;
import net.osmand.plus.osmedit.oauth.OsmOAuthHelper;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.quickaction.QuickActionRegistry;
@ -161,6 +162,7 @@ public class OsmandApplication extends MultiDexApplication {
GpxDbHelper gpxDbHelper;
QuickActionRegistry quickActionRegistry;
OsmOAuthHelper osmOAuthHelper;
OprAuthHelper oprAuthHelper;
MeasurementEditingContext measurementEditingContext;
OnlineRoutingHelper onlineRoutingHelper;
@ -396,6 +398,10 @@ public class OsmandApplication extends MultiDexApplication {
return osmOAuthHelper;
}
public OprAuthHelper getOprAuthHelper() {
return oprAuthHelper;
}
public synchronized DownloadIndexesThread getDownloadThread() {
if (downloadIndexesThread == null) {
downloadIndexesThread = new DownloadIndexesThread(this);

View file

@ -35,9 +35,12 @@ import net.osmand.plus.dialogs.PluginInstalledBottomSheetDialog;
import net.osmand.plus.download.IndexItem;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.MenuController;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask.GetImageCardsListener;
import net.osmand.plus.mapillary.MapillaryPlugin;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.myplaces.FavoritesActivity;
import net.osmand.plus.openplacereviews.OpenPlaceReviewsPlugin;
import net.osmand.plus.openseamapsplugin.NauticalMapsPlugin;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.plus.parkingpoint.ParkingPositionPlugin;
@ -66,6 +69,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
public abstract class OsmandPlugin {
@ -133,7 +137,7 @@ public abstract class OsmandPlugin {
public boolean init(@NonNull OsmandApplication app, @Nullable Activity activity) {
if (activity != null) {
// called from UI
for (ApplicationMode appMode: getAddedAppModes()) {
for (ApplicationMode appMode : getAddedAppModes()) {
ApplicationMode.changeProfileAvailability(appMode, true, app);
}
}
@ -208,6 +212,16 @@ public abstract class OsmandPlugin {
return Collections.emptyList();
}
protected List<ImageCard> getContextMenuImageCards(@NonNull Map<String, String> params,
@Nullable Map<String, String> additionalParams,
@Nullable GetImageCardsListener listener) {
return Collections.emptyList();
}
protected ImageCard createContextMenuImageCard(@NonNull JSONObject imageObject) {
return null;
}
/**
* Plugin was installed
*/
@ -263,25 +277,19 @@ public abstract class OsmandPlugin {
public static void initPlugins(@NonNull OsmandApplication app) {
Set<String> enabledPlugins = app.getSettings().getEnabledPlugins();
allPlugins.clear();
enableHiddenPlugin(app, enabledPlugins, new MapillaryPlugin(app));
enableHiddenPlugin(app, enabledPlugins, new WikipediaPlugin(app));
enablePluginByDefault(app, enabledPlugins, new WikipediaPlugin(app));
allPlugins.add(new OsmandRasterMapsPlugin(app));
allPlugins.add(new OsmandMonitoringPlugin(app));
checkMarketPlugin(app, enabledPlugins, new SRTMPlugin(app));
// ? questionable - definitely not market plugin
// checkMarketPlugin(app, enabledPlugins, new TouringViewPlugin(app), false, TouringViewPlugin.COMPONENT, null);
checkMarketPlugin(app, enabledPlugins, new NauticalMapsPlugin(app));
checkMarketPlugin(app, enabledPlugins, new SkiMapsPlugin(app));
allPlugins.add(new AudioVideoNotesPlugin(app));
checkMarketPlugin(app, enabledPlugins, new ParkingPositionPlugin(app));
allPlugins.add(new AccessibilityPlugin(app));
allPlugins.add(new OsmEditingPlugin(app));
enablePluginByDefault(app, enabledPlugins, new OpenPlaceReviewsPlugin(app));
enablePluginByDefault(app, enabledPlugins, new MapillaryPlugin(app));
allPlugins.add(new AccessibilityPlugin(app));
allPlugins.add(new OsmandDevelopmentPlugin(app));
loadCustomPlugins(app);
@ -373,7 +381,7 @@ public abstract class OsmandPlugin {
}
}
private static void enableHiddenPlugin(@NonNull OsmandApplication app, @NonNull Set<String> enabledPlugins, @NonNull OsmandPlugin plugin) {
private static void enablePluginByDefault(@NonNull OsmandApplication app, @NonNull Set<String> enabledPlugins, @NonNull OsmandPlugin plugin) {
allPlugins.add(plugin);
if (!enabledPlugins.contains(plugin.getId()) && !app.getSettings().getPlugins().contains("-" + plugin.getId())) {
enabledPlugins.add(plugin.getId());
@ -734,7 +742,6 @@ public abstract class OsmandPlugin {
return l;
}
public static void onMapActivityCreate(MapActivity activity) {
for (OsmandPlugin plugin : getEnabledPlugins()) {
plugin.mapActivityCreate(activity);
@ -868,6 +875,23 @@ public abstract class OsmandPlugin {
return collection;
}
public static void populateContextMenuImageCards(@NonNull List<ImageCard> imageCards, @NonNull Map<String, String> params,
@Nullable Map<String, String> additionalParams, @Nullable GetImageCardsListener listener) {
for (OsmandPlugin plugin : getEnabledPlugins()) {
imageCards.addAll(plugin.getContextMenuImageCards(params, additionalParams, listener));
}
}
public static ImageCard createImageCardForJson(@NonNull JSONObject imageObject) {
for (OsmandPlugin plugin : getEnabledPlugins()) {
ImageCard imageCard = plugin.createContextMenuImageCard(imageObject);
if (imageCard != null) {
return imageCard;
}
}
return null;
}
public static boolean isPackageInstalled(String packageInfo, Context ctx) {
if (packageInfo == null) {
return false;

View file

@ -1,6 +1,7 @@
package net.osmand.plus.api;
import androidx.annotation.Nullable;
public interface SQLiteAPI {
@ -55,8 +56,6 @@ public interface SQLiteAPI {
void close();
}
public interface SQLiteStatement {
@ -80,8 +79,10 @@ public interface SQLiteAPI {
void bindBlob(int i, byte[] val);
}
public SQLiteConnection getOrCreateDatabase(String name, boolean readOnly);
public SQLiteConnection openByAbsolutePath(String path, boolean readOnly);
@Nullable
SQLiteConnection getOrCreateDatabase(String name, boolean readOnly);
@Nullable
SQLiteConnection openByAbsolutePath(String path, boolean readOnly);
}

View file

@ -1,15 +1,17 @@
package net.osmand.plus.api;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import org.apache.commons.logging.Log;
import android.annotation.SuppressLint;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import androidx.annotation.Nullable;
import net.osmand.PlatformUtil;
import net.osmand.plus.OsmandApplication;
import org.apache.commons.logging.Log;
public class SQLiteAPIImpl implements SQLiteAPI {
private OsmandApplication app;
@ -20,6 +22,7 @@ public class SQLiteAPIImpl implements SQLiteAPI {
}
@SuppressLint("InlinedApi")
@Nullable
@Override
public SQLiteConnection getOrCreateDatabase(String name, boolean readOnly) {
android.database.sqlite.SQLiteDatabase db = null;
@ -29,13 +32,12 @@ public class SQLiteAPIImpl implements SQLiteAPI {
} catch (RuntimeException e) {
LOG.error(e.getMessage(), e);
}
if(db == null) {
if (db == null) {
return null;
}
return new SQLiteDatabaseWrapper(db) ;
return new SQLiteDatabaseWrapper(db);
}
public class SQLiteDatabaseWrapper implements SQLiteConnection {
android.database.sqlite.SQLiteDatabase ds;
@ -206,15 +208,15 @@ public class SQLiteAPIImpl implements SQLiteAPI {
}
@Nullable
@Override
public SQLiteConnection openByAbsolutePath(String path, boolean readOnly) {
// fix http://stackoverflow.com/questions/26937152/workaround-for-nexus-9-sqlite-file-write-operations-on-external-dirs
android.database.sqlite.SQLiteDatabase db = SQLiteDatabase.openDatabase(path, null,
readOnly? SQLiteDatabase.OPEN_READONLY : (SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING));
if(db == null) {
readOnly ? SQLiteDatabase.OPEN_READONLY : (SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.ENABLE_WRITE_AHEAD_LOGGING));
if (db == null) {
return null;
}
return new SQLiteDatabaseWrapper(db) ;
return new SQLiteDatabaseWrapper(db);
}
}

View file

@ -57,9 +57,6 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
private LinearLayout itemsContainer;
private LinearLayout buttonsContainer;
@StringRes
protected int dismissButtonStringRes = R.string.shared_string_cancel;
public void setUsedOnMap(boolean usedOnMap) {
this.usedOnMap = usedOnMap;
}
@ -261,11 +258,7 @@ public abstract class MenuBottomSheetDialogFragment extends BottomSheetDialogFra
@StringRes
protected int getDismissButtonTextId() {
return dismissButtonStringRes;
}
protected void setDismissButtonTextId(@StringRes int stringRes) {
dismissButtonStringRes = stringRes;
return R.string.shared_string_cancel;
}
protected int getDismissButtonHeight(){

View file

@ -143,8 +143,8 @@ public class OsmandDevelopmentPlugin extends OsmandPlugin {
@Override
public void disable(OsmandApplication app) {
if (app.getSettings().USE_DEV_URL.get()) {
app.getSettings().USE_DEV_URL.set(false);
if (app.getSettings().OSM_USE_DEV_URL.get()) {
app.getSettings().OSM_USE_DEV_URL.set(false);
app.getOsmOAuthHelper().resetAuthorization();
}
super.disable(app);

View file

@ -19,9 +19,9 @@ import net.osmand.plus.base.MenuBottomSheetDialogFragment;
import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.DividerSpaceItem;
import net.osmand.plus.mapcontextmenu.UploadPhotosAsyncTask.UploadPhotosListener;
import net.osmand.plus.mapcontextmenu.UploadPhotosAsyncTask.UploadPhotosProgressListener;
public class UploadPhotoProgressBottomSheet extends MenuBottomSheetDialogFragment implements UploadPhotosListener {
public class UploadPhotoProgressBottomSheet extends MenuBottomSheetDialogFragment implements UploadPhotosProgressListener {
public static final String TAG = UploadPhotoProgressBottomSheet.class.getSimpleName();
@ -103,7 +103,7 @@ public class UploadPhotoProgressBottomSheet extends MenuBottomSheetDialogFragmen
return uploadingFinished ? R.string.shared_string_close : R.string.shared_string_cancel;
}
public static UploadPhotosListener showInstance(@NonNull FragmentManager fragmentManager, int maxProgress, OnDismissListener listener) {
public static UploadPhotosProgressListener showInstance(@NonNull FragmentManager fragmentManager, int maxProgress, OnDismissListener listener) {
UploadPhotoProgressBottomSheet fragment = new UploadPhotoProgressBottomSheet();
fragment.setRetainInstance(true);
fragment.setMaxProgress(maxProgress);

View file

@ -22,6 +22,7 @@ import net.osmand.plus.mapmarkers.MapMarkersDialogFragment;
import net.osmand.plus.mapmarkers.MapMarkersGroup;
import net.osmand.plus.mapsource.EditMapSourceDialogFragment;
import net.osmand.plus.openplacereviews.OPRConstants;
import net.osmand.plus.openplacereviews.OprAuthHelper.OprAuthorizationListener;
import net.osmand.plus.search.QuickSearchDialogFragment;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings;
@ -256,7 +257,7 @@ public class IntentHelper {
if (intent.hasExtra(TrackMenuFragment.OPEN_TRACK_MENU)) {
String path = intent.getStringExtra(TRACK_FILE_NAME);
boolean currentRecording = intent.getBooleanExtra(CURRENT_RECORDING, false);
TrackMenuFragment.showInstance(mapActivity, path, currentRecording);
TrackMenuFragment.showInstance(mapActivity, path, currentRecording, null);
mapActivity.setIntent(null);
}
}
@ -326,8 +327,8 @@ public class IntentHelper {
if (uri.toString().startsWith(OPRConstants.OPR_OAUTH_PREFIX)) {
String token = uri.getQueryParameter("opr-token");
String username = uri.getQueryParameter("opr-nickname");
app.getSettings().OPR_ACCESS_TOKEN.set(token);
app.getSettings().OPR_USERNAME.set(username);
app.getOprAuthHelper().addListener(getOprAuthorizationListener());
app.getOprAuthHelper().authorize(token, username);
mapActivity.setIntent(null);
return true;
}
@ -348,6 +349,19 @@ public class IntentHelper {
};
}
private OprAuthorizationListener getOprAuthorizationListener() {
return new OprAuthorizationListener() {
@Override
public void authorizationCompleted() {
for (Fragment fragment : mapActivity.getSupportFragmentManager().getFragments()) {
if (fragment instanceof OprAuthorizationListener) {
((OprAuthorizationListener) fragment).authorizationCompleted();
}
}
}
};
}
private boolean handleSendText(Intent intent) {
String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
if (!Algorithms.isEmpty(sharedText)) {

View file

@ -63,7 +63,7 @@ class GpxOrFavouritesImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().endsWith(ImportHelper.KML_SUFFIX)) {
InputStream gpxStream = convertKmlToGpxStream(is);
InputStream gpxStream = convertKmlToGpxStream(zis);
if (gpxStream != null) {
fileSize = gpxStream.available();
return GPXUtilities.loadGPXFile(gpxStream);

View file

@ -1,6 +1,7 @@
package net.osmand.plus.importfiles;
import android.content.DialogInterface;
import android.content.DialogInterface.OnClickListener;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
@ -9,13 +10,13 @@ import android.os.Build;
import android.os.Bundle;
import android.provider.OpenableColumns;
import android.provider.Settings;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import net.osmand.AndroidUtils;
import net.osmand.CallbackWithObject;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
@ -418,7 +419,7 @@ public class ImportHelper {
final boolean useImportDir, boolean forceImportFavourites, boolean showInDetailsActivity) {
if (result != null) {
if (result.error != null) {
Toast.makeText(activity, result.error.getMessage(), Toast.LENGTH_LONG).show();
app.showToastMessage(result.error.getMessage());
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
}
@ -439,34 +440,36 @@ public class ImportHelper {
}
}
} else {
new AlertDialog.Builder(activity)
.setTitle(R.string.shared_string_import2osmand)
.setMessage(R.string.import_gpx_failed_descr)
.setNeutralButton(R.string.shared_string_permissions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromParts("package", app.getPackageName(), null);
intent.setData(uri);
app.startActivity(intent);
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
if (AndroidUtils.isActivityNotDestroyed(activity)) {
new AlertDialog.Builder(activity)
.setTitle(R.string.shared_string_import2osmand)
.setMessage(R.string.import_gpx_failed_descr)
.setNeutralButton(R.string.shared_string_permissions, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
Uri uri = Uri.fromParts("package", app.getPackageName(), null);
intent.setData(uri);
app.startActivity(intent);
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
}
}
}
})
.setNegativeButton(R.string.shared_string_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
})
.setNegativeButton(R.string.shared_string_cancel, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
if (gpxImportCompleteListener != null) {
gpxImportCompleteListener.onImportComplete(false);
}
}
}
})
.show();
})
.show();
}
}
if (forceImportFavourites) {
final Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
Intent newIntent = new Intent(activity, app.getAppCustomization().getFavoritesActivity());
newIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
newIntent.putExtra(TAB_ID, GPX_TAB);
activity.startActivity(newIntent);
@ -577,7 +580,7 @@ public class ImportHelper {
showPlanRouteFragment();
}
} else {
Toast.makeText(activity, warning, Toast.LENGTH_LONG).show();
app.showToastMessage(warning);
}
}
@ -619,26 +622,27 @@ public class ImportHelper {
final boolean forceImportFavourites, final boolean forceImportGpx) {
if (gpxFile == null || gpxFile.isPointsEmpty()) {
if (forceImportFavourites) {
final DialogInterface.OnClickListener importAsTrackListener = new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
handleResult(gpxFile, fileName, fileSize, save, useImportDir, true);
break;
case DialogInterface.BUTTON_NEGATIVE:
dialog.dismiss();
break;
if (AndroidUtils.isActivityNotDestroyed(activity)) {
OnClickListener importAsTrackListener = new OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
switch (which) {
case DialogInterface.BUTTON_POSITIVE:
handleResult(gpxFile, fileName, fileSize, save, useImportDir, true);
break;
case DialogInterface.BUTTON_NEGATIVE:
dialog.dismiss();
break;
}
}
}
};
new AlertDialog.Builder(activity)
.setTitle(R.string.import_track)
.setMessage(activity.getString(R.string.import_track_desc, fileName))
.setPositiveButton(R.string.shared_string_import, importAsTrackListener)
.setNegativeButton(R.string.shared_string_cancel, importAsTrackListener)
.show();
};
new AlertDialog.Builder(activity)
.setTitle(R.string.import_track)
.setMessage(activity.getString(R.string.import_track_desc, fileName))
.setPositiveButton(R.string.shared_string_import, importAsTrackListener)
.setNegativeButton(R.string.shared_string_cancel, importAsTrackListener)
.show();
}
} else {
handleResult(gpxFile, fileName, fileSize, save, useImportDir, false);
}

View file

@ -49,7 +49,7 @@ class KmzImportTask extends BaseLoadAsyncTask<Void, Void, GPXFile> {
ZipEntry entry;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().endsWith(KML_SUFFIX)) {
InputStream gpxStream = convertKmlToGpxStream(is);
InputStream gpxStream = convertKmlToGpxStream(zis);
if (gpxStream != null) {
fileSize = gpxStream.available();
return GPXUtilities.loadGPXFile(gpxStream);

View file

@ -36,6 +36,7 @@ import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
@ -47,11 +48,12 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.Version;
import net.osmand.plus.activities.ActivityResultListener;
import net.osmand.plus.activities.ActivityResultListener.OnActivityResultListener;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.mapcontextmenu.UploadPhotosAsyncTask.UploadPhotosListener;
import net.osmand.plus.mapcontextmenu.builders.cards.AbstractCard;
import net.osmand.plus.mapcontextmenu.builders.cards.CardsRowBuilder;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
@ -72,9 +74,14 @@ import net.osmand.plus.views.layers.POIMapLayer;
import net.osmand.plus.views.layers.TransportStopsLayer;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.plus.widgets.tools.ClickableSpanTouchListener;
import net.osmand.plus.wikipedia.WikiArticleHelper;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import org.apache.commons.logging.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -87,6 +94,7 @@ import static net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCa
public class MenuBuilder {
private static final Log LOG = PlatformUtil.getLog(MenuBuilder.class);
private static final int PICK_IMAGE = 1231;
public static final float SHADOW_HEIGHT_TOP_DP = 17f;
public static final int TITLE_LIMIT = 60;
@ -131,16 +139,14 @@ public class MenuBuilder {
}
@Override
public void onPlaceIdAcquired(String[] placeId) {
public void onPlaceIdAcquired(final String[] placeId) {
MenuBuilder.this.placeId = placeId;
if (placeId.length < 2) {
app.runInUIThread(new Runnable() {
@Override
public void run() {
photoButton.setVisibility(View.GONE);
}
});
}
app.runInUIThread(new Runnable() {
@Override
public void run() {
AndroidUiHelper.updateVisibility(photoButton, placeId.length >= 2);
}
});
}
@Override
@ -158,6 +164,16 @@ public class MenuBuilder {
}
};
public void addImageCard(ImageCard card) {
if (onlinePhotoCards.size() == 1 && onlinePhotoCards.get(0) instanceof NoImagesCard) {
onlinePhotoCards.clear();
}
onlinePhotoCards.add(0, card);
if (onlinePhotoCardsRow != null) {
onlinePhotoCardsRow.setCards(onlinePhotoCards);
}
}
public interface CollapseExpandListener {
void onCollapseExpand(boolean collapsed);
}
@ -443,10 +459,7 @@ public class MenuBuilder {
}
}
});
//TODO This feature is under development
if (!Version.isDeveloperVersion(app)) {
view.setVisibility(View.GONE);
}
AndroidUiHelper.updateVisibility(view, false);
photoButton = view;
return view;
}
@ -481,7 +494,27 @@ public class MenuBuilder {
}
}
}
execute(new UploadPhotosAsyncTask(mapActivity, imagesUri, getLatLon(), placeId, getAdditionalCardParams(), imageCardListener));
UploadPhotosListener listener = new UploadPhotosListener() {
@Override
public void uploadPhotosSuccess(final String response) {
app.runInUIThread(new Runnable() {
@Override
public void run() {
if (AndroidUtils.isActivityNotDestroyed(mapActivity)) {
try {
ImageCard imageCard = OsmandPlugin.createImageCardForJson(new JSONObject(response));
if (imageCard != null) {
addImageCard(imageCard);
}
} catch (JSONException e) {
LOG.error(e);
}
}
}
});
}
};
execute(new UploadPhotosAsyncTask(mapActivity, imagesUri, placeId, listener));
}
}
}));
@ -769,18 +802,98 @@ public class MenuBuilder {
return ll;
}
public View buildDescriptionRow(final View view, final String textPrefix, final String description, int textColor,
int textLinesLimit, boolean matchWidthDivider) {
OnClickListener clickListener = new OnClickListener() {
public View buildDescriptionRow(final View view, final String description) {
final String descriptionLabel = app.getString(R.string.shared_string_description);
View.OnClickListener onClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
POIMapLayer.showDescriptionDialog(view.getContext(), app, description, textPrefix);
POIMapLayer.showHtmlDescriptionDialog(view.getContext(), app, description, descriptionLabel);
}
};
return buildRow(view, null, null, textPrefix, description, textColor,
null, false, null, true, textLinesLimit,
false, false, false, clickListener, matchWidthDivider);
if (!isFirstRow()) {
buildRowDivider(view);
}
LinearLayout baseView = new LinearLayout(view.getContext());
baseView.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams llBaseViewParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
baseView.setLayoutParams(llBaseViewParams);
LinearLayout ll = new LinearLayout(view.getContext());
ll.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams llParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
ll.setLayoutParams(llParams);
ll.setBackgroundResource(AndroidUtils.resolveAttribute(view.getContext(), android.R.attr.selectableItemBackground));
ll.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View v) {
copyToClipboard(description, view.getContext());
return true;
}
});
baseView.addView(ll);
// Text
LinearLayout llText = new LinearLayout(view.getContext());
llText.setOrientation(LinearLayout.VERTICAL);
LinearLayout.LayoutParams llTextViewParams = new LinearLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT);
llTextViewParams.weight = 1f;
AndroidUtils.setMargins(llTextViewParams, 0, 0, dpToPx(10f), 0);
llTextViewParams.gravity = Gravity.CENTER_VERTICAL;
llText.setLayoutParams(llTextViewParams);
ll.addView(llText);
// Description label
TextViewEx textPrefixView = new TextViewEx(view.getContext());
LinearLayout.LayoutParams llTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
AndroidUtils.setMargins(llTextParams, dpToPx(16f), dpToPx(8f), 0, 0);
textPrefixView.setLayoutParams(llTextParams);
textPrefixView.setTypeface(FontCache.getRobotoRegular(view.getContext()));
textPrefixView.setTextSize(12);
textPrefixView.setTextColor(app.getResources().getColor(light ? R.color.text_color_secondary_light : R.color.text_color_secondary_dark));
textPrefixView.setMinLines(1);
textPrefixView.setMaxLines(1);
textPrefixView.setText(descriptionLabel);
llText.addView(textPrefixView);
// Description
TextViewEx textView = new TextViewEx(view.getContext());
LinearLayout.LayoutParams llDescriptionParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
AndroidUtils.setMargins(llDescriptionParams, dpToPx(16f), dpToPx(2f), 0, dpToPx(8f));
textView.setLayoutParams(llDescriptionParams);
textView.setTypeface(FontCache.getRobotoRegular(view.getContext()));
textView.setTextSize(16);
textView.setTextColor(app.getResources().getColor(light ? R.color.text_color_primary_light : R.color.text_color_primary_dark));
textView.setText(WikiArticleHelper.getPartialContent(description));
if (Linkify.addLinks(textView, Linkify.ALL)) {
textView.setMovementMethod(null);
int linkTextColor = ContextCompat.getColor(view.getContext(), light ?
R.color.ctx_menu_bottom_view_url_color_light : R.color.ctx_menu_bottom_view_url_color_dark);
textView.setLinkTextColor(linkTextColor);
textView.setOnTouchListener(new ClickableSpanTouchListener());
AndroidUtils.removeLinkUnderline(textView);
}
textView.setMinLines(1);
textView.setMaxLines(10);
textView.setEllipsize(TextUtils.TruncateAt.END);
llText.addView(textView);
// Read Full button
buildReadFullButton(llText, app.getString(R.string.context_menu_read_full), onClickListener);
if (onClickListener != null) {
ll.setOnClickListener(onClickListener);
}
((LinearLayout) view).addView(baseView);
rowBuilt();
setDividerWidth(true);
return ll;
}
protected void showDialog(String text, final String actionType, final String dataPrefix, final View v) {
@ -876,6 +989,38 @@ public class MenuBuilder {
((LinearLayout) view).addView(horizontalLine);
}
protected void buildReadFullButton(LinearLayout container, String btnText, View.OnClickListener onClickListener) {
Context ctx = container.getContext();
TextViewEx button = new TextViewEx(new ContextThemeWrapper(ctx, light ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme));
LinearLayout.LayoutParams llButtonParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dpToPx(36f));
AndroidUtils.setMargins(llButtonParams, dpToPx(16f), 0, 0, dpToPx(16f));
button.setLayoutParams(llButtonParams);
button.setTypeface(FontCache.getRobotoMedium(app));
button.setBackgroundResource(light ? R.drawable.context_menu_controller_bg_light : R.drawable.context_menu_controller_bg_dark);
button.setTextSize(14);
int paddingSides = dpToPx(10f);
button.setPadding(paddingSides, 0, paddingSides, 0);
ColorStateList buttonColorStateList = AndroidUtils.createPressedColorStateList(ctx, !light,
R.color.ctx_menu_controller_button_text_color_light_n, R.color.ctx_menu_controller_button_text_color_light_p,
R.color.ctx_menu_controller_button_text_color_dark_n, R.color.ctx_menu_controller_button_text_color_dark_p);
button.setTextColor(buttonColorStateList);
button.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
button.setSingleLine(true);
button.setEllipsize(TextUtils.TruncateAt.END);
button.setOnClickListener(onClickListener);
button.setAllCaps(true);
button.setText(btnText);
Drawable normal = app.getUIUtilities().getIcon(R.drawable.ic_action_read_text,
light ? R.color.ctx_menu_controller_button_text_color_light_n : R.color.ctx_menu_controller_button_text_color_dark_n);
Drawable pressed = app.getUIUtilities().getIcon(R.drawable.ic_action_read_text,
light ? R.color.ctx_menu_controller_button_text_color_light_p : R.color.ctx_menu_controller_button_text_color_dark_p);
AndroidUtils.setCompoundDrawablesWithIntrinsicBounds(button, Build.VERSION.SDK_INT >= 21
? AndroidUtils.createPressedStateListDrawable(normal, pressed) : normal, null, null, null);
button.setCompoundDrawablePadding(dpToPx(8f));
container.addView(button);
}
public boolean hasCustomAddressLine() {
return false;
}
@ -1112,7 +1257,9 @@ public class MenuBuilder {
controller.setOnBackButtonClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
mapContextMenu.show();
if (mapContextMenu != null) {
mapContextMenu.show();
}
}
});
controller.setOnTitleClickListener(new OnClickListener() {

View file

@ -4,23 +4,20 @@ import android.content.DialogInterface;
import android.content.DialogInterface.OnDismissListener;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.AsyncTask;
import androidx.annotation.Nullable;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.data.LatLon;
import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.dialogs.UploadPhotoProgressBottomSheet;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask.GetImageCardsListener;
import net.osmand.plus.openplacereviews.OPRConstants;
import net.osmand.plus.openplacereviews.OprStartFragment;
import net.osmand.plus.osmedit.opr.OpenDBAPI;
@ -36,33 +33,27 @@ import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
private static final Log LOG = PlatformUtil.getLog(UploadPhotosAsyncTask.class);
private static final int MAX_IMAGE_LENGTH = 2048;
private static final int IMAGE_MAX_SIZE = 4096;
private final OsmandApplication app;
private final WeakReference<MapActivity> activityRef;
private final OpenDBAPI openDBAPI = new OpenDBAPI();
private final LatLon latLon;
private final List<Uri> data;
private final String[] placeId;
private final Map<String, String> params;
private final GetImageCardsListener imageCardListener;
private UploadPhotosListener listener;
private final UploadPhotosListener listener;
private UploadPhotosProgressListener progressListener;
public UploadPhotosAsyncTask(MapActivity activity, List<Uri> data, LatLon latLon, String[] placeId,
Map<String, String> params, GetImageCardsListener imageCardListener) {
public UploadPhotosAsyncTask(MapActivity activity, List<Uri> data, String[] placeId, UploadPhotosListener listener) {
app = (OsmandApplication) activity.getApplicationContext();
activityRef = new WeakReference<>(activity);
this.data = data;
this.latLon = latLon;
this.params = params;
this.placeId = placeId;
this.imageCardListener = imageCardListener;
this.listener = listener;
}
@Override
@ -70,7 +61,7 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
FragmentActivity activity = activityRef.get();
if (AndroidUtils.isActivityNotDestroyed(activity)) {
FragmentManager manager = activity.getSupportFragmentManager();
listener = UploadPhotoProgressBottomSheet.showInstance(manager, data.size(), new OnDismissListener() {
progressListener = UploadPhotoProgressBottomSheet.showInstance(manager, data.size(), new OnDismissListener() {
@Override
public void onDismiss(DialogInterface dialog) {
cancel(false);
@ -81,8 +72,8 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onProgressUpdate(Integer... values) {
if (listener != null) {
listener.uploadPhotosProgressUpdate(values[0]);
if (progressListener != null) {
progressListener.uploadPhotosProgressUpdate(values[0]);
}
}
@ -103,18 +94,19 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPostExecute(Void aVoid) {
if (listener != null) {
listener.uploadPhotosFinished();
if (progressListener != null) {
progressListener.uploadPhotosFinished();
}
}
private boolean handleSelectedImage(final Uri uri) {
boolean success = false;
InputStream inputStream = null;
int[] imageDimensions = null;
try {
inputStream = app.getContentResolver().openInputStream(uri);
if (inputStream != null) {
success = uploadImageToPlace(inputStream);
imageDimensions = calcImageDimensions(inputStream);
}
} catch (Exception e) {
LOG.error(e);
@ -122,12 +114,32 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
} finally {
Algorithms.closeStream(inputStream);
}
if (imageDimensions != null && imageDimensions.length == 2) {
try {
inputStream = app.getContentResolver().openInputStream(uri);
if (inputStream != null) {
int width = imageDimensions[0];
int height = imageDimensions[1];
success = uploadImageToPlace(inputStream, width, height);
}
} catch (Exception e) {
LOG.error(e);
app.showToastMessage(R.string.cannot_upload_image);
} finally {
Algorithms.closeStream(inputStream);
}
}
return success;
}
private boolean uploadImageToPlace(InputStream image) {
private boolean uploadImageToPlace(InputStream image, int width, int height) {
boolean success = false;
InputStream serverData = new ByteArrayInputStream(compressImageToJpeg(image));
byte[] jpegImageBytes = compressImageToJpeg(image, width, height);
if (jpegImageBytes == null || jpegImageBytes.length == 0) {
app.showToastMessage(R.string.cannot_upload_image);
return false;
}
InputStream serverData = new ByteArrayInputStream(jpegImageBytes);
String baseUrl = OPRConstants.getBaseUrl(app);
// all these should be constant
String url = baseUrl + "api/ipfs/image";
@ -156,13 +168,9 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
checkTokenAndShowScreen();
} else {
success = true;
String str = app.getString(R.string.successfully_uploaded_pattern, 1, 1);
app.showToastMessage(str);
//refresh the image
MapActivity activity = activityRef.get();
if (activity != null) {
MenuBuilder.execute(new GetImageCardsTask(activity, latLon, params, imageCardListener));
if (listener != null) {
listener.uploadPhotosSuccess(response);
}
}
} else {
@ -191,36 +199,55 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
}
}
private byte[] compressImageToJpeg(InputStream image) {
private int[] calcImageDimensions(InputStream image) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(image);
Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int h = bmp.getHeight();
int w = bmp.getWidth();
boolean scale = false;
while (w > MAX_IMAGE_LENGTH || h > MAX_IMAGE_LENGTH) {
w = w / 2;
h = h / 2;
scale = true;
}
if (scale) {
Matrix matrix = new Matrix();
matrix.postScale(w, h);
Bitmap resizedBitmap = Bitmap.createBitmap(
bmp, 0, 0, w, h, matrix, false);
bmp.recycle();
bmp = resizedBitmap;
}
bmp.compress(Bitmap.CompressFormat.JPEG, 90, os);
return os.toByteArray();
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inJustDecodeBounds = true;
BitmapFactory.decodeStream(bufferedInputStream, null, opts);
return new int[] { opts.outWidth, opts.outHeight };
}
@Nullable
private byte[] compressImageToJpeg(InputStream image, int width, int height) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(image);
int w = width;
int h = height;
boolean scale = false;
int divider = 1;
while (w > IMAGE_MAX_SIZE || h > IMAGE_MAX_SIZE) {
w /= 2;
h /= 2;
divider *= 2;
scale = true;
}
Bitmap bmp;
if (scale) {
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = divider;
bmp = BitmapFactory.decodeStream(bufferedInputStream, null, opts);
} else {
bmp = BitmapFactory.decodeStream(bufferedInputStream);
}
if (bmp != null) {
ByteArrayOutputStream os = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.JPEG, 90, os);
return os.toByteArray();
} else {
return null;
}
}
public interface UploadPhotosListener {
public interface UploadPhotosProgressListener {
void uploadPhotosProgressUpdate(int progress);
void uploadPhotosFinished();
}
public interface UploadPhotosListener {
void uploadPhotosSuccess(String response);
}
}

View file

@ -2,10 +2,8 @@ package net.osmand.plus.mapcontextmenu.builders;
import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.Build;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.view.Gravity;
@ -15,10 +13,6 @@ import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.view.ContextThemeWrapper;
import androidx.core.content.ContextCompat;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.data.Amenity;
@ -31,7 +25,6 @@ import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.FontCache;
import net.osmand.plus.helpers.enums.MetricsConstants;
import net.osmand.plus.mapcontextmenu.CollapsableView;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
@ -67,6 +60,9 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
public class AmenityMenuBuilder extends MenuBuilder {
private static final String WIKI_LINK = ".wikipedia.org/w";
@ -259,38 +255,12 @@ public class AmenityMenuBuilder extends MenuBuilder {
}
if (isWiki) {
TextViewEx button = new TextViewEx(new ContextThemeWrapper(view.getContext(), light ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme));
LinearLayout.LayoutParams llWikiButtonParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, dpToPx(36f));
AndroidUtils.setMargins(llWikiButtonParams, dpToPx(16f), 0, 0, dpToPx(16f));
button.setLayoutParams(llWikiButtonParams);
button.setTypeface(FontCache.getRobotoMedium(app));
button.setBackgroundResource(light ? R.drawable.context_menu_controller_bg_light : R.drawable.context_menu_controller_bg_dark);
button.setTextSize(14);
int paddingSides = dpToPx(10f);
button.setPadding(paddingSides, 0, paddingSides, 0);
ColorStateList buttonColorStateList = AndroidUtils.createPressedColorStateList(view.getContext(), !light,
R.color.ctx_menu_controller_button_text_color_light_n, R.color.ctx_menu_controller_button_text_color_light_p,
R.color.ctx_menu_controller_button_text_color_dark_n, R.color.ctx_menu_controller_button_text_color_dark_p);
button.setTextColor(buttonColorStateList);
button.setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
button.setSingleLine(true);
button.setEllipsize(TextUtils.TruncateAt.END);
button.setOnClickListener(new View.OnClickListener() {
buildReadFullButton(llText, app.getString(R.string.context_menu_read_full_article), new View.OnClickListener() {
@Override
public void onClick(View view) {
WikipediaDialogFragment.showInstance(mapActivity, amenity);
}
});
button.setAllCaps(true);
button.setText(R.string.context_menu_read_full_article);
Drawable normal = app.getUIUtilities().getIcon(R.drawable.ic_action_read_text,
light ? R.color.ctx_menu_controller_button_text_color_light_n : R.color.ctx_menu_controller_button_text_color_dark_n);
Drawable pressed = app.getUIUtilities().getIcon(R.drawable.ic_action_read_text,
light ? R.color.ctx_menu_controller_button_text_color_light_p : R.color.ctx_menu_controller_button_text_color_dark_p);
AndroidUtils.setCompoundDrawablesWithIntrinsicBounds(button, Build.VERSION.SDK_INT >= 21
? AndroidUtils.createPressedStateListDrawable(normal, pressed) : normal, null, null, null);
button.setCompoundDrawablePadding(dpToPx(8f));
llText.addView(button);
}
((LinearLayout) view).addView(baseView);

View file

@ -4,8 +4,6 @@ import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.NonNull;
import net.osmand.PlatformUtil;
import net.osmand.ResultMatcher;
import net.osmand.binary.BinaryMapIndexReader;
@ -19,8 +17,8 @@ import net.osmand.osm.PoiCategory;
import net.osmand.plus.FavouritesDbHelper.FavoriteGroup;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.CollapsableView;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.myplaces.FavoritesActivity;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
@ -29,6 +27,8 @@ import net.osmand.util.MapUtils;
import java.io.IOException;
import java.util.List;
import androidx.annotation.NonNull;
public class FavouritePointMenuBuilder extends MenuBuilder {
private static final org.apache.commons.logging.Log LOG = PlatformUtil.getLog(FavouritePointMenuBuilder.class);
@ -85,7 +85,7 @@ public class FavouritePointMenuBuilder extends MenuBuilder {
protected void buildDescription(View view) {
String desc = fav.getDescription();
if (!Algorithms.isEmpty(desc)) {
buildDescriptionRow(view, app.getString(R.string.shared_string_description), desc, 0, 10, true);
buildDescriptionRow(view, desc);
}
}

View file

@ -4,10 +4,6 @@ import android.content.Context;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.IndexConstants;
@ -30,6 +26,10 @@ import java.text.DateFormat;
import java.util.Date;
import java.util.List;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
public class WptPtMenuBuilder extends MenuBuilder {
private final WptPt wpt;
@ -52,10 +52,22 @@ public class WptPtMenuBuilder extends MenuBuilder {
}
@Override
protected void buildDescription(View view) {
if (!Algorithms.isEmpty(wpt.desc)) {
buildDescriptionRow(view, app.getString(R.string.shared_string_description), wpt.desc, 0, 10, true);
protected void buildDescription(final View view) {
if (Algorithms.isEmpty(wpt.desc)) {
return;
}
final String textPrefix = app.getString(R.string.shared_string_description);
View.OnClickListener clickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
POIMapLayer.showDescriptionDialog(view.getContext(), app, wpt.desc, textPrefix);
}
};
buildRow(view, null, null, textPrefix, wpt.desc, 0,
null, false, null, true, 10,
false, false, false, clickListener, matchWidthDivider);
}
@Override

View file

@ -19,17 +19,13 @@ import net.osmand.AndroidNetworkUtils;
import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.data.Amenity;
import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapillary.MapillaryContributeCard;
import net.osmand.plus.mapillary.MapillaryImageCard;
import net.osmand.plus.openplacereviews.OPRConstants;
import net.osmand.plus.wikimedia.WikiImageHelper;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
@ -41,18 +37,17 @@ import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import static net.osmand.plus.mapillary.MapillaryPlugin.TYPE_MAPILLARY_CONTRIBUTE;
import static net.osmand.plus.mapillary.MapillaryPlugin.TYPE_MAPILLARY_PHOTO;
public abstract class ImageCard extends AbstractCard {
public static String TYPE_MAPILLARY_PHOTO = "mapillary-photo";
public static String TYPE_MAPILLARY_CONTRIBUTE = "mapillary-contribute";
private static final Log LOG = PlatformUtil.getLog(ImageCard.class);
protected String type;
@ -184,11 +179,7 @@ public abstract class ImageCard extends AbstractCard {
try {
if (imageObject.has("type")) {
String type = imageObject.getString("type");
if (TYPE_MAPILLARY_PHOTO.equals(type)) {
imageCard = new MapillaryImageCard(mapActivity, imageObject);
} else if (TYPE_MAPILLARY_CONTRIBUTE.equals(type)) {
imageCard = new MapillaryContributeCard(mapActivity, imageObject);
} else {
if (!TYPE_MAPILLARY_CONTRIBUTE.equals(type) && !TYPE_MAPILLARY_PHOTO.equals(type)) {
imageCard = new UrlImageCard(mapActivity, imageObject);
}
}
@ -198,14 +189,6 @@ public abstract class ImageCard extends AbstractCard {
return imageCard;
}
private static ImageCard createCardOpr(MapActivity mapActivity, JSONObject imageObject) {
ImageCard imageCard = null;
if (imageObject.has("cid")) {
imageCard = new IPFSImageCard(mapActivity, imageObject);
}
return imageCard;
}
public double getCa() {
return ca;
}
@ -410,28 +393,6 @@ public abstract class ImageCard extends AbstractCard {
}
}
private static String[] getIdFromResponse(String response) {
try {
JSONArray obj = new JSONObject(response).getJSONArray("objects");
JSONArray images = (JSONArray) ((JSONObject) obj.get(0)).get("id");
return toStringArray(images);
} catch (JSONException e) {
e.printStackTrace();
}
return new String[0];
}
private static String[] toStringArray(JSONArray array) {
if (array == null)
return null;
String[] arr = new String[array.length()];
for (int i = 0; i < arr.length; i++) {
arr[i] = array.optString(i);
}
return arr;
}
public static class GetImageCardsTask extends AsyncTask<Void, Void, List<ImageCard>> {
private MapActivity mapActivity;
@ -451,7 +412,7 @@ public abstract class ImageCard extends AbstractCard {
}
public GetImageCardsTask(@NonNull MapActivity mapActivity, LatLon latLon,
@Nullable Map<String, String> params, GetImageCardsListener listener) {
@Nullable Map<String, String> params, GetImageCardsListener listener) {
this.mapActivity = mapActivity;
this.app = mapActivity.getMyApplication();
this.latLon = latLon;
@ -460,23 +421,9 @@ public abstract class ImageCard extends AbstractCard {
}
@Override
protected List<ImageCard> doInBackground(Void... params) {
protected List<ImageCard> doInBackground(Void... voids) {
TrafficStats.setThreadStatsTag(GET_IMAGE_CARD_THREAD_ID);
List<ImageCard> result = new ArrayList<>();
Object o = mapActivity.getMapLayers().getContextMenuLayer().getSelectedObject();
if (o instanceof Amenity) {
Amenity am = (Amenity) o;
long amenityId = am.getId() >> 1;
String baseUrl = OPRConstants.getBaseUrl(app);
String url = baseUrl + "api/objects-by-index?type=opr.place&index=osmid&key=" + amenityId;
String response = AndroidNetworkUtils.sendRequest(app, url, Collections.<String, String>emptyMap(),
"Requesting location images...", false, false);
if (response != null) {
getPicturesForPlace(result, response);
String[] id = getIdFromResponse(response);
listener.onPlaceIdAcquired(id);
}
}
try {
final Map<String, String> pms = new LinkedHashMap<>();
pms.put("lat", "" + (float) latLon.getLatitude());
@ -493,19 +440,8 @@ public abstract class ImageCard extends AbstractCard {
if (!Algorithms.isEmpty(preferredLang)) {
pms.put("lang", preferredLang);
}
if (this.params != null) {
String wikidataId = this.params.get(Amenity.WIKIDATA);
if (wikidataId != null) {
this.params.remove(Amenity.WIKIDATA);
WikiImageHelper.addWikidataImageCards(mapActivity, wikidataId, result);
}
String wikimediaContent = this.params.get(Amenity.WIKIMEDIA_COMMONS);
if (wikimediaContent != null) {
this.params.remove(Amenity.WIKIMEDIA_COMMONS);
WikiImageHelper.addWikimediaImageCards(mapActivity, wikimediaContent, result);
}
pms.putAll(this.params);
}
OsmandPlugin.populateContextMenuImageCards(result, pms, params, listener);
String response = AndroidNetworkUtils.sendRequest(app, "https://osmand.net/api/cm_place", pms,
"Requesting location images...", false, false);
@ -517,7 +453,10 @@ public abstract class ImageCard extends AbstractCard {
try {
JSONObject imageObject = (JSONObject) images.get(i);
if (imageObject != JSONObject.NULL) {
ImageCard imageCard = ImageCard.createCard(mapActivity, imageObject);
ImageCard imageCard = OsmandPlugin.createImageCardForJson(imageObject);
if (imageCard == null) {
imageCard = ImageCard.createCard(mapActivity, imageObject);
}
if (imageCard != null) {
result.add(imageCard);
}
@ -537,36 +476,6 @@ public abstract class ImageCard extends AbstractCard {
return result;
}
private void getPicturesForPlace(List<ImageCard> result, String response) {
try {
if (!Algorithms.isEmpty(response)) {
JSONArray obj = new JSONObject(response).getJSONArray("objects");
JSONObject imagesWrapper = ((JSONObject) ((JSONObject) obj.get(0)).get("images"));
Iterator<String> it = imagesWrapper.keys();
while (it.hasNext()) {
JSONArray images = imagesWrapper.getJSONArray(it.next());
if (images.length() > 0) {
for (int i = 0; i < images.length(); i++) {
try {
JSONObject imageObject = (JSONObject) images.get(i);
if (imageObject != JSONObject.NULL) {
ImageCard imageCard = ImageCard.createCardOpr(mapActivity, imageObject);
if (imageCard != null) {
result.add(imageCard);
}
}
} catch (JSONException e) {
LOG.error(e);
}
}
}
}
}
} catch (Exception e) {
LOG.error(e);
}
}
@Override
protected void onPostExecute(List<ImageCard> cardList) {
result = cardList;

View file

@ -45,7 +45,9 @@ public class SelectedGpxMenuController extends MenuController {
mapContextMenu.hide(false);
WptPt wptPt = selectedGpxPoint.selectedPoint;
LatLon latLon = new LatLon(wptPt.lat, wptPt.lon);
TrackMenuFragment.showInstance(mapActivity, selectedGpxPoint.getSelectedGpxFile(), latLon);
SelectedGpxFile selectedGpxFile = selectedGpxPoint.getSelectedGpxFile();
String path = selectedGpxFile.getGpxFile().path;
TrackMenuFragment.showInstance(mapActivity, path, selectedGpxFile.isShowCurrentTrack(), latLon);
}
};
leftTitleButtonController.caption = mapActivity.getString(R.string.shared_string_open_track);

View file

@ -1,6 +1,7 @@
package net.osmand.plus.mapcontextmenu.controllers;
import android.graphics.drawable.Drawable;
import android.util.Pair;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
@ -11,25 +12,27 @@ import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.mapcontextmenu.MenuBuilder;
import net.osmand.plus.mapcontextmenu.MenuController;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.track.TrackMenuFragment;
import net.osmand.plus.wikivoyage.menu.WikivoyageWptPtMenuBuilder;
import net.osmand.plus.wikivoyage.menu.WikivoyageWptPtMenuController;
import net.osmand.util.Algorithms;
import java.io.File;
import java.util.ArrayList;
public class WptPtMenuController extends MenuController {
private WptPt wpt;
private MapMarker mapMarker;
public WptPtMenuController(@NonNull MenuBuilder menuBuilder, @NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull final WptPt wpt) {
public WptPtMenuController(@NonNull MenuBuilder menuBuilder, @NonNull MapActivity mapActivity,
@NonNull PointDescription pointDescription, @NonNull final WptPt wpt) {
super(menuBuilder, pointDescription, mapActivity);
this.wpt = wpt;
MapMarkersHelper markersHelper = mapActivity.getMyApplication().getMapMarkersHelper();
@ -37,11 +40,34 @@ public class WptPtMenuController extends MenuController {
if (mapMarker == null) {
mapMarker = markersHelper.getMapMarker(new LatLon(wpt.lat, wpt.lon));
}
TitleButtonController openTrackButtonController = new TitleButtonController() {
@Override
public void buttonPressed() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
GpxSelectionHelper selectionHelper = mapActivity.getMyApplication().getSelectedGpxHelper();
SelectedGpxFile selectedGpxFile = selectionHelper.getSelectedGPXFile(wpt);
if (selectedGpxFile != null) {
String path = selectedGpxFile.getGpxFile().path;
TrackMenuFragment.showInstance(mapActivity, path, selectedGpxFile.isShowCurrentTrack(), new LatLon(wpt.lon, wpt.lat));
}
}
}
};
openTrackButtonController.startIconId = R.drawable.ic_action_polygom_dark;
openTrackButtonController.caption = mapActivity.getString(R.string.shared_string_open_track);
if (mapMarker != null) {
MapMarkerMenuController markerMenuController =
new MapMarkerMenuController(mapActivity, mapMarker.getPointDescription(mapActivity), mapMarker);
PointDescription description = mapMarker.getPointDescription(mapActivity);
MapMarkerMenuController markerMenuController = new MapMarkerMenuController(mapActivity, description, mapMarker);
leftTitleButtonController = markerMenuController.getLeftTitleButtonController();
rightTitleButtonController = markerMenuController.getRightTitleButtonController();
additionalButtonsControllers = new ArrayList<>();
additionalButtonsControllers.add(Pair.<TitleButtonController, TitleButtonController>create(openTrackButtonController, null));
} else {
leftTitleButtonController = openTrackButtonController;
}
}
@ -143,10 +169,6 @@ public class WptPtMenuController extends MenuController {
}
public static WptPtMenuController getInstance(@NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull final WptPt wpt) {
WptPtMenuController controller = WikivoyageWptPtMenuController.getInstance(mapActivity, pointDescription, wpt);
if (controller == null) {
controller = new WptPtMenuController(new WikivoyageWptPtMenuBuilder(mapActivity, wpt), mapActivity, pointDescription, wpt);
}
return controller;
return new WptPtMenuController(new WikivoyageWptPtMenuBuilder(mapActivity, wpt), mapActivity, pointDescription, wpt);
}
}

View file

@ -17,27 +17,34 @@ import androidx.appcompat.widget.SwitchCompat;
import androidx.fragment.app.FragmentActivity;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.map.ITileSource;
import net.osmand.map.TileSourceManager;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.Version;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.MapActivityLayers;
import net.osmand.plus.base.BottomSheetDialogFragment;
import net.osmand.plus.dashboard.DashboardOnMap;
import net.osmand.plus.views.layers.MapInfoLayer;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
import net.osmand.plus.openplacereviews.OpenPlaceReviewsPlugin;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.views.MapTileLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.MapInfoLayer;
import net.osmand.plus.views.mapwidgets.MapWidgetRegistry.MapWidgetRegInfo;
import net.osmand.plus.views.mapwidgets.widgets.TextInfoWidget;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.json.JSONException;
import org.json.JSONObject;
import java.text.MessageFormat;
import java.util.List;
@ -47,11 +54,18 @@ import static net.osmand.plus.ContextMenuAdapter.makeDeleteAction;
public class MapillaryPlugin extends OsmandPlugin {
public static String TYPE_MAPILLARY_PHOTO = "mapillary-photo";
public static String TYPE_MAPILLARY_CONTRIBUTE = "mapillary-contribute";
public static final String ID = "osmand.mapillary";
private static final String MAPILLARY_PACKAGE_ID = "app.mapillary";
private static final Log LOG = PlatformUtil.getLog(OpenPlaceReviewsPlugin.class);
private OsmandSettings settings;
private MapActivity mapActivity;
private MapillaryRasterLayer rasterLayer;
private MapillaryVectorLayer vectorLayer;
private TextInfoWidget mapillaryControl;
@ -62,11 +76,6 @@ public class MapillaryPlugin extends OsmandPlugin {
settings = app.getSettings();
}
@Override
public boolean isVisible() {
return false;
}
@Override
public int getLogoResourceId() {
return R.drawable.ic_action_mapillary;
@ -92,6 +101,14 @@ public class MapillaryPlugin extends OsmandPlugin {
return app.getString(R.string.mapillary);
}
@Override
public boolean init(@NonNull OsmandApplication app, Activity activity) {
if (activity instanceof MapActivity) {
mapActivity = (MapActivity) activity;
}
return true;
}
@Override
public void registerLayers(MapActivity activity) {
createLayers();
@ -228,6 +245,41 @@ public class MapillaryPlugin extends OsmandPlugin {
}
}
@Override
protected ImageCard createContextMenuImageCard(@NonNull JSONObject imageObject) {
ImageCard imageCard = null;
if (mapActivity != null) {
try {
if (imageObject.has("type")) {
String type = imageObject.getString("type");
if (TYPE_MAPILLARY_PHOTO.equals(type)) {
imageCard = new MapillaryImageCard(mapActivity, imageObject);
} else if (TYPE_MAPILLARY_CONTRIBUTE.equals(type)) {
imageCard = new MapillaryContributeCard(mapActivity, imageObject);
}
}
} catch (JSONException e) {
LOG.error(e);
}
}
return imageCard;
}
@Override
public void mapActivityResume(MapActivity activity) {
this.mapActivity = activity;
}
@Override
public void mapActivityResumeOnTop(MapActivity activity) {
this.mapActivity = activity;
}
@Override
public void mapActivityPause(MapActivity activity) {
this.mapActivity = null;
}
public static boolean openMapillary(FragmentActivity activity, String imageKey) {
boolean success = false;
OsmandApplication app = (OsmandApplication) activity.getApplication();

View file

@ -1236,11 +1236,10 @@ public class MapMarkersHelper {
removeGroupActiveMarkers(group, true);
return;
}
for (FavouritePoint fp : favGroup.getPoints()) {
List<FavouritePoint> points = new ArrayList<>(favGroup.getPoints());
for (FavouritePoint fp : points) {
addNewMarkerIfNeeded(group, groupMarkers, new LatLon(fp.getLatitude(), fp.getLongitude()), fp.getName(), fp, null);
}
} else if (group.getType() == MapMarkersGroup.GPX_TYPE) {
GpxSelectionHelper gpxHelper = ctx.getSelectedGpxHelper();
File file = new File(group.getId());

View file

@ -19,8 +19,8 @@ import com.github.mikephil.charting.data.ChartData;
import com.github.mikephil.charting.data.LineData;
import com.github.mikephil.charting.interfaces.datasets.ILineDataSet;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.AndroidUtils;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
@ -30,10 +30,10 @@ import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter;
import net.osmand.plus.mapcontextmenu.other.HorizontalSelectionAdapter.HorizontalSelectionAdapterListener;
import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenu;
import net.osmand.plus.measurementtool.MeasurementToolFragment.OnUpdateInfoListener;
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter;
import net.osmand.plus.measurementtool.graph.CommonGraphAdapter;
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter;
import net.osmand.plus.measurementtool.graph.CustomGraphAdapter.LegendViewType;
import net.osmand.plus.measurementtool.graph.BaseGraphAdapter;
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper;
import net.osmand.plus.measurementtool.graph.GraphAdapterHelper.RefreshMapCallback;
import net.osmand.plus.routepreparationmenu.RouteDetailsFragment;
@ -422,7 +422,7 @@ public class GraphsCard extends BaseCard implements OnUpdateInfoListener {
GpxUiHelper.setupGPXChart(commonGraphAdapter.getChart(), 4, 24f, 16f, !nightMode, true);
List<ILineDataSet> dataSets = GpxUiHelper.getDataSets(commonGraphAdapter.getChart(),
app, analysis, firstType, secondType, false);
return !Algorithms.isEmpty(dataSets) ? new LineData(dataSets) : null;
return new LineData(dataSets);
}
}
@ -447,12 +447,11 @@ public class GraphsCard extends BaseCard implements OnUpdateInfoListener {
@Override
public BarData getChartData() {
GpxUiHelper.setupHorizontalGPXChart(app, customGraphAdapter.getChart(), 5, 9, 24, true, nightMode);
BarData data = null;
if (!Algorithms.isEmpty(statistics.elements)) {
data = GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(),
return GpxUiHelper.buildStatisticChart(app, customGraphAdapter.getChart(),
statistics, analysis, true, nightMode);
}
return data;
return new BarData();
}
}
}

View file

@ -10,11 +10,11 @@ import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.Metadata;
import net.osmand.GPXUtilities.Route;
import net.osmand.GPXUtilities.Track;
import net.osmand.GPXUtilities.TrkSegment;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.GPXUtilities.Metadata;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.Version;
@ -104,6 +104,10 @@ class SaveGpxRouteAsyncTask extends AsyncTask<Void, Void, Exception> {
MeasurementToolFragment.showGpxOnMap(app, gpx, false);
}
}
if (res == null) {
savedGpxFile.addGeneralTrack();
}
return res;
}

View file

@ -143,6 +143,12 @@ public class SaveGPXBottomSheetFragment extends MenuBottomSheetDialogFragment {
return UiUtilities.DialogButtonType.SECONDARY;
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_close;
}
@Override
protected int getRightBottomButtonTextId() {
return R.string.shared_string_open_track;

View file

@ -192,9 +192,9 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
}
private BaseBottomSheetItem createCopyToMarkersItem(final GPXFile gpxFile) {
final MapMarkersGroup markersGroup = getOrCreateMarkersGroup(gpxFile);
final Set<String> categories = markersGroup.getWptCategories();
final boolean synced = categories != null && categories.contains(group.getName());
MapMarkersGroup markersGroup = mapMarkersHelper.getMarkersGroup(gpxFile);
final boolean synced = markersGroup != null && (Algorithms.isEmpty(markersGroup.getWptCategories())
|| markersGroup.getWptCategories().contains(group.getName()));
return new SimpleBottomSheetItem.Builder()
.setIcon(getContentIcon(synced ? R.drawable.ic_action_delete_dark : R.drawable.ic_action_copy))
@ -203,18 +203,25 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
updateGroupWptCategory(gpxFile, markersGroup, categories, synced);
updateGroupWptCategory(gpxFile, synced);
dismiss();
}
})
.create();
}
private void updateGroupWptCategory(GPXFile gpxFile, MapMarkersGroup markersGroup, Set<String> categories, boolean synced) {
private void updateGroupWptCategory(GPXFile gpxFile, boolean synced) {
SelectedGpxFile selectedGpxFile = selectedGpxHelper.getSelectedFileByPath(gpxFile.path);
if (selectedGpxFile == null) {
selectedGpxHelper.selectGpxFile(gpxFile, true, false, false, false, false);
}
boolean groupCreated = false;
MapMarkersGroup markersGroup = mapMarkersHelper.getMarkersGroup(gpxFile);
if (markersGroup == null) {
groupCreated = true;
markersGroup = mapMarkersHelper.addOrEnableGroup(gpxFile);
}
Set<String> categories = markersGroup.getWptCategories();
Set<String> selectedCategories = new HashSet<>();
if (categories != null) {
selectedCategories.addAll(categories);
@ -224,16 +231,14 @@ public class EditTrackGroupDialogFragment extends MenuBottomSheetDialogFragment
} else {
selectedCategories.add(group.getName());
}
mapMarkersHelper.updateGroupWptCategories(markersGroup, selectedCategories);
mapMarkersHelper.runSynchronization(markersGroup);
}
private MapMarkersGroup getOrCreateMarkersGroup(GPXFile gpxFile) {
MapMarkersGroup markersGroup = mapMarkersHelper.getMarkersGroup(gpxFile);
if (markersGroup == null) {
markersGroup = mapMarkersHelper.addOrEnableGroup(gpxFile);
if (Algorithms.isEmpty(selectedCategories)) {
mapMarkersHelper.removeMarkersGroup(markersGroup);
} else {
mapMarkersHelper.updateGroupWptCategories(markersGroup, selectedCategories);
if (!groupCreated) {
mapMarkersHelper.runSynchronization(markersGroup);
}
}
return markersGroup;
}
private BaseBottomSheetItem createCopyToFavoritesItem() {

View file

@ -1,12 +1,16 @@
package net.osmand.plus.mapcontextmenu.builders.cards;
package net.osmand.plus.openplacereviews;
import android.view.View;
import androidx.core.content.ContextCompat;
import net.osmand.PlatformUtil;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.json.JSONException;
import org.json.JSONObject;
@ -16,16 +20,17 @@ public class IPFSImageCard extends ImageCard {
public IPFSImageCard(MapActivity mapActivity, JSONObject imageObject) {
super(mapActivity, imageObject);
String cid = "";
try {
cid = (String) imageObject.get("cid");
String calcImageUrl = mapActivity.getString(R.string.opr_base_url) + "api/ipfs/image?";
calcImageUrl += "cid=" + (String) imageObject.getString("cid");
calcImageUrl += "&hash=" + (String) imageObject.getString("hash");
calcImageUrl += "&ext=" + (String) imageObject.getString("extension");
url = calcImageUrl;
imageHiresUrl = url;
imageUrl = url;
} catch (JSONException e) {
LOG.error(e);
}
String BASE_URL = mapActivity.getString(R.string.opr_base_url) + "api/ipfs/image-ipfs?cid=";
url = BASE_URL + cid;
imageHiresUrl = BASE_URL + cid;
imageUrl = BASE_URL + cid;
icon = ContextCompat.getDrawable(getMyApplication(), R.drawable.ic_logo_openplacereview);
if (!Algorithms.isEmpty(getUrl())) {
View.OnClickListener onClickListener = new View.OnClickListener() {

View file

@ -1,9 +1,9 @@
package net.osmand.plus.openplacereviews;
import android.content.Context;
import androidx.annotation.NonNull;
import net.osmand.plus.R;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.osmedit.opr.OpenDBAPI;
public class OPRConstants {
@ -11,28 +11,27 @@ public class OPRConstants {
private static final String PURPOSE = OpenDBAPI.PURPOSE;
private static final String CALLBACK_URL = OPR_OAUTH_PREFIX + "://osmand_opr_auth";
public static String getBaseUrl(Context ctx) {
return ctx.getString(R.string.opr_base_url);
public static String getBaseUrl(@NonNull OsmandApplication app) {
return app.getSettings().getOprUrl();
}
public static String getLoginUrl(Context ctx) {
return getBaseUrl(ctx) + "login" + getQueryString(ctx);
public static String getLoginUrl(@NonNull OsmandApplication app) {
return getBaseUrl(app) + "login" + getQueryString();
}
public static String getRegisterUrl(Context ctx) {
return getBaseUrl(ctx) + "signup" + getQueryString(ctx);
public static String getRegisterUrl(@NonNull OsmandApplication app) {
return getBaseUrl(app) + "signup" + getQueryString();
}
public static String getQueryString(Context ctx) {
return "?" + getPurposeParam(ctx) + "&" + getCallbackParam(ctx);
public static String getQueryString() {
return "?" + getPurposeParam() + "&" + getCallbackParam();
}
public static String getPurposeParam(Context ctx) {
public static String getPurposeParam() {
return "purpose=" + PURPOSE;
}
public static String getCallbackParam(Context ctx) {
public static String getCallbackParam() {
return "callback=" + CALLBACK_URL;
}
}

View file

@ -0,0 +1,199 @@
package net.osmand.plus.openplacereviews;
import android.app.Activity;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import net.osmand.AndroidNetworkUtils;
import net.osmand.PlatformUtil;
import net.osmand.data.Amenity;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask.GetImageCardsListener;
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
public class OpenPlaceReviewsPlugin extends OsmandPlugin {
private static final Log LOG = PlatformUtil.getLog(OpenPlaceReviewsPlugin.class);
public static final String ID = "osmand.openplacereviews";
private MapActivity mapActivity;
public OpenPlaceReviewsPlugin(OsmandApplication app) {
super(app);
}
@Override
public String getId() {
return ID;
}
@Override
public String getName() {
return app.getString(R.string.open_place_reviews);
}
@Override
public CharSequence getDescription() {
return app.getString(R.string.open_place_reviews_plugin_description);
}
@Override
public SettingsScreenType getSettingsScreenType() {
return SettingsScreenType.OPEN_PLACE_REVIEWS;
}
@Override
public int getLogoResourceId() {
return R.drawable.ic_img_logo_openplacereview;
}
@Override
public Drawable getAssetResourceImage() {
return app.getUIUtilities().getIcon(R.drawable.img_plugin_openplacereviews);
}
@Override
public void mapActivityResume(MapActivity activity) {
this.mapActivity = activity;
}
@Override
public void mapActivityResumeOnTop(MapActivity activity) {
this.mapActivity = activity;
}
@Override
public void mapActivityPause(MapActivity activity) {
this.mapActivity = null;
}
@Override
protected List<ImageCard> getContextMenuImageCards(@NonNull Map<String, String> params,
@Nullable Map<String, String> additionalParams,
@Nullable GetImageCardsListener listener) {
List<ImageCard> imageCards = new ArrayList<>();
if (mapActivity != null) {
Object object = mapActivity.getMapLayers().getContextMenuLayer().getSelectedObject();
if (object instanceof Amenity) {
Amenity am = (Amenity) object;
long amenityId = am.getId() >> 1;
String baseUrl = OPRConstants.getBaseUrl(app);
String url = baseUrl + "api/objects-by-index?type=opr.place&index=osmid&key=" + amenityId;
String response = AndroidNetworkUtils.sendRequest(app, url, Collections.<String, String>emptyMap(),
"Requesting location images...", false, false);
if (response != null) {
getPicturesForPlace(imageCards, response);
if (listener != null) {
listener.onPlaceIdAcquired(getIdFromResponse(response));
}
}
}
}
return imageCards;
}
@Override
protected ImageCard createContextMenuImageCard(@NonNull JSONObject imageObject) {
ImageCard imageCard = null;
if (mapActivity != null && imageObject != JSONObject.NULL) {
imageCard = createCardOpr(mapActivity, imageObject);
}
return imageCard;
}
private void getPicturesForPlace(List<ImageCard> result, String response) {
try {
if (!Algorithms.isEmpty(response)) {
JSONArray obj = new JSONObject(response).getJSONArray("objects");
JSONObject imagesWrapper = ((JSONObject) ((JSONObject) obj.get(0)).get("images"));
Iterator<String> it = imagesWrapper.keys();
while (it.hasNext()) {
JSONArray images = imagesWrapper.getJSONArray(it.next());
if (images.length() > 0) {
for (int i = 0; i < images.length(); i++) {
try {
JSONObject imageObject = (JSONObject) images.get(i);
if (imageObject != JSONObject.NULL) {
ImageCard imageCard = createCardOpr(mapActivity, imageObject);
if (imageCard != null) {
result.add(imageCard);
}
}
} catch (JSONException e) {
LOG.error(e);
}
}
}
}
}
} catch (Exception e) {
LOG.error(e);
}
}
public static ImageCard createCardOpr(MapActivity mapActivity, JSONObject imageObject) {
ImageCard imageCard = null;
if (imageObject.has("cid")) {
imageCard = new IPFSImageCard(mapActivity, imageObject);
}
return imageCard;
}
private static String[] getIdFromResponse(String response) {
try {
JSONArray obj = new JSONObject(response).getJSONArray("objects");
JSONArray images = (JSONArray) ((JSONObject) obj.get(0)).get("id");
return toStringArray(images);
} catch (JSONException e) {
e.printStackTrace();
}
return new String[0];
}
private static String[] toStringArray(JSONArray array) {
if (array == null)
return null;
String[] arr = new String[array.length()];
for (int i = 0; i < arr.length; i++) {
arr[i] = array.optString(i);
}
return arr;
}
@Override
public boolean init(@NonNull OsmandApplication app, Activity activity) {
if (activity instanceof MapActivity) {
mapActivity = (MapActivity) activity;
}
return true;
}
@Override
public void disable(OsmandApplication app) {
if (app.getSettings().OPR_USE_DEV_URL.get()) {
app.getSettings().OPR_USE_DEV_URL.set(false);
app.getOprAuthHelper().resetAuthorization();
}
super.disable(app);
}
}

View file

@ -0,0 +1,95 @@
package net.osmand.plus.openplacereviews;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.osmedit.opr.OpenDBAPI;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms;
import java.util.HashSet;
import java.util.Set;
public class OprAuthHelper {
private final OsmandApplication app;
private final OsmandSettings settings;
private final Set<OprAuthorizationListener> listeners = new HashSet<>();
public OprAuthHelper(@NonNull OsmandApplication app) {
this.app = app;
settings = app.getSettings();
}
public void addListener(OprAuthorizationListener listener) {
listeners.add(listener);
}
public void removeListener(OprAuthorizationListener listener) {
listeners.remove(listener);
}
public void resetAuthorization() {
if (isLoginExists()) {
settings.OPR_USERNAME.resetToDefault();
settings.OPR_ACCESS_TOKEN.resetToDefault();
settings.OPR_BLOCKCHAIN_NAME.resetToDefault();
}
}
public boolean isLoginExists() {
return !Algorithms.isEmpty(settings.OPR_USERNAME.get())
&& !Algorithms.isEmpty(settings.OPR_BLOCKCHAIN_NAME.get())
&& !Algorithms.isEmpty(settings.OPR_ACCESS_TOKEN.get());
}
private void notifyAndRemoveListeners() {
for (OprAuthorizationListener listener : listeners) {
listener.authorizationCompleted();
}
listeners.clear();
}
public void authorize(final String token, final String username) {
CheckOprAuthTask checkOprAuthTask = new CheckOprAuthTask(app, token, username);
checkOprAuthTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
private static class CheckOprAuthTask extends AsyncTask<Void, Void, Boolean> {
private final OsmandApplication app;
private final OpenDBAPI openDBAPI = new OpenDBAPI();
private final String token;
private final String username;
private CheckOprAuthTask(@NonNull OsmandApplication app, String token, String username) {
this.app = app;
this.token = token;
this.username = username;
}
@Override
protected Boolean doInBackground(Void... params) {
String baseUrl = OPRConstants.getBaseUrl(app);
return openDBAPI.checkPrivateKeyValid(app, baseUrl, username, token);
}
@Override
protected void onPostExecute(Boolean result) {
if (result) {
app.getSettings().OPR_ACCESS_TOKEN.set(token);
app.getSettings().OPR_USERNAME.set(username);
} else {
app.getOprAuthHelper().resetAuthorization();
}
app.getOprAuthHelper().notifyAndRemoveListeners();
}
}
public interface OprAuthorizationListener {
void authorizationCompleted();
}
}

View file

@ -0,0 +1,119 @@
package net.osmand.plus.openplacereviews;
import android.os.Bundle;
import androidx.activity.OnBackPressedCallback;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.preference.Preference;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.openplacereviews.OprAuthHelper.OprAuthorizationListener;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.fragments.OnPreferenceChanged;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
public class OprSettingsFragment extends BaseSettingsFragment implements OnPreferenceChanged, OprAuthorizationListener {
private static final String OPR_LOGOUT = "opr_logout";
public static final String OPR_LOGIN_DATA = "opr_login_data";
private OprAuthHelper authHelper;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
authHelper = app.getOprAuthHelper();
FragmentActivity activity = requireMyActivity();
activity.getOnBackPressedDispatcher().addCallback(this, new OnBackPressedCallback(true) {
public void handleOnBackPressed() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
mapActivity.launchPrevActivityIntent();
}
dismiss();
}
});
}
@Override
protected void setupPreferences() {
Preference oprSettingsInfo = findPreference("opr_settings_info");
oprSettingsInfo.setIconSpaceReserved(false);
setupLoginPref();
setupLogoutPref();
setupUseDevUrlPref();
}
private void setupLoginPref() {
Preference nameAndPasswordPref = findPreference(OPR_LOGIN_DATA);
nameAndPasswordPref.setVisible(!authHelper.isLoginExists());
nameAndPasswordPref.setIcon(getContentIcon(R.drawable.ic_action_user_account));
}
private void setupLogoutPref() {
Preference nameAndPasswordPref = findPreference(OPR_LOGOUT);
nameAndPasswordPref.setVisible(authHelper.isLoginExists());
nameAndPasswordPref.setSummary(settings.OPR_USERNAME.get());
nameAndPasswordPref.setIcon(getContentIcon(R.drawable.ic_action_user_account));
}
private void setupUseDevUrlPref() {
SwitchPreferenceEx useDevUrlPref = findPreference(settings.OPR_USE_DEV_URL.getId());
useDevUrlPref.setVisible(OsmandPlugin.isDevelopment());
useDevUrlPref.setIcon(getPersistentPrefIcon(R.drawable.ic_plugin_developer));
}
@Override
public boolean onPreferenceClick(Preference preference) {
String prefId = preference.getKey();
if (OPR_LOGIN_DATA.equals(prefId)) {
FragmentManager fragmentManager = getFragmentManager();
if (fragmentManager != null) {
OprStartFragment.showInstance(fragmentManager);
return true;
}
} else if (OPR_LOGOUT.equals(prefId)) {
oprLogout();
return true;
}
return super.onPreferenceClick(preference);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String prefId = preference.getKey();
if (settings.OPR_USE_DEV_URL.getId().equals(prefId) && newValue instanceof Boolean) {
settings.OPR_USE_DEV_URL.set((Boolean) newValue);
oprLogout();
return true;
}
return super.onPreferenceChange(preference, newValue);
}
public void oprLogout() {
authHelper.resetAuthorization();
app.showShortToastMessage(R.string.osm_edit_logout_success);
updateAllSettings();
}
@Override
public void onPreferenceChanged(String prefId) {
if (settings.OPR_USE_DEV_URL.getId().equals(prefId)) {
oprLogout();
}
updateAllSettings();
}
@Override
public void authorizationCompleted() {
if (getContext() != null) {
updateAllSettings();
}
}
}

View file

@ -16,18 +16,21 @@ import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import net.osmand.AndroidUtils;
import net.osmand.PlatformUtil;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.base.BaseOsmAndFragment;
import net.osmand.plus.openplacereviews.OprAuthHelper.OprAuthorizationListener;
import org.apache.commons.logging.Log;
public class OprStartFragment extends BaseOsmAndFragment {
public class OprStartFragment extends BaseOsmAndFragment implements OprAuthorizationListener {
private static final String TAG = OprStartFragment.class.getSimpleName();
private static final Log LOG = PlatformUtil.getLog(OprStartFragment.class);
private static final String openPlaceReviewsUrl = "OpenPlaceReviews.org";
@ -36,18 +39,22 @@ public class OprStartFragment extends BaseOsmAndFragment {
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
nightMode = getMyApplication().getDaynightHelper().isNightModeForMapControls();
View v = UiUtilities.getInflater(requireMyActivity(), nightMode).inflate(R.layout.fragment_opr_login, container,
false);
View createAccount = v.findViewById(R.id.register_opr_create_account);
v.findViewById(R.id.back_button).setOnClickListener(new View.OnClickListener() {
View v = UiUtilities.getInflater(requireMyActivity(), nightMode).inflate(R.layout.fragment_opr_login, container, false);
AndroidUtils.addStatusBarPadding21v(requireMyActivity(), v);
Toolbar toolbar = (Toolbar) v.findViewById(R.id.toolbar);
int icBackResId = AndroidUtils.getNavigationIconResId(v.getContext());
toolbar.setNavigationIcon(getContentIcon(icBackResId));
toolbar.setNavigationContentDescription(R.string.access_shared_string_navigate_up);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
FragmentActivity activity = getActivity();
if (activity != null) {
activity.getSupportFragmentManager().popBackStack();
}
public void onClick(View v) {
dismiss();
}
});
View createAccount = v.findViewById(R.id.register_opr_create_account);
UiUtilities.setupDialogButton(nightMode, createAccount, UiUtilities.DialogButtonType.PRIMARY,
R.string.register_opr_create_new_account);
createAccount.setOnClickListener(new View.OnClickListener() {
@ -70,14 +77,14 @@ public class OprStartFragment extends BaseOsmAndFragment {
}
private void handleHaveAccount() {
String url = OPRConstants.getLoginUrl(requireContext());
String url = OPRConstants.getLoginUrl(requireMyApplication());
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(requireContext(), Uri.parse(url));
}
private void handleCreateAccount() {
String url = OPRConstants.getRegisterUrl(requireContext());
String url = OPRConstants.getRegisterUrl(requireMyApplication());
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(requireContext(), Uri.parse(url));
@ -114,6 +121,17 @@ public class OprStartFragment extends BaseOsmAndFragment {
}
}
@Override
public void authorizationCompleted() {
dismiss();
}
protected void dismiss() {
FragmentActivity activity = getActivity();
if (activity != null) {
activity.getSupportFragmentManager().popBackStack();
}
}
public static void showInstance(@NonNull FragmentManager fm) {
try {

View file

@ -52,8 +52,8 @@ public class EditPOIMenuController extends MenuController {
OsmandSettings settings = app.getSettings();
OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(app);
boolean isLogged = client.isValidToken()
|| !Algorithms.isEmpty(settings.USER_NAME.get())
&& !Algorithms.isEmpty(settings.USER_PASSWORD.get());
|| !Algorithms.isEmpty(settings.OSM_USER_NAME.get())
&& !Algorithms.isEmpty(settings.OSM_USER_PASSWORD.get());
FragmentManager fragmentManager = activity.getSupportFragmentManager();
if (point instanceof OpenstreetmapPoint) {

View file

@ -542,6 +542,7 @@ public class EditPoiDialogFragment extends BaseOsmAndDialogFragment {
mapActivity.getContextMenu().showOrUpdate(
new LatLon(point.getLatitude(), point.getLongitude()),
plugin.getOsmEditsLayer(mapActivity).getObjectName(point), point);
mapActivity.getMapLayers().getContextMenuLayer().updateContextMenu();
}
}
@ -869,6 +870,7 @@ public class EditPoiDialogFragment extends BaseOsmAndDialogFragment {
mapActivity.getContextMenu().showOrUpdate(
new LatLon(point.getLatitude(), point.getLongitude()),
plugin.getOsmEditsLayer(mapActivity).getObjectName(point), point);
mapActivity.getMapLayers().getContextMenuLayer().updateContextMenu();
}
} else {
Toast.makeText(activity, R.string.poi_remove_success, Toast.LENGTH_LONG)

View file

@ -84,7 +84,7 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
additionalData.put("tags", tagstring);
additionalData.put("visibility", visibility);
return NetworkUtils.uploadFile(url, f,
settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(),
settings.OSM_USER_NAME.get() + ":" + settings.OSM_USER_PASSWORD.get(),
adapter.getClient(),
"file",
true, additionalData);
@ -138,7 +138,7 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
connection.setRequestMethod(requestMethod);
connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx)); //$NON-NLS-1$
StringBuilder responseBody = new StringBuilder();
String token = settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(); //$NON-NLS-1$
String token = settings.OSM_USER_NAME.get() + ":" + settings.OSM_USER_PASSWORD.get(); //$NON-NLS-1$
connection.addRequestProperty("Authorization", "Basic " + Base64.encode(token.getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
connection.setDoInput(true);
if (requestMethod.equals("PUT") || requestMethod.equals("POST") || requestMethod.equals("DELETE")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
@ -322,9 +322,9 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
ser.attribute(null, "version", "0.6"); //$NON-NLS-1$ //$NON-NLS-2$
ser.attribute(null, "generator", Version.getAppName(ctx)); //$NON-NLS-1$
if (n instanceof Node) {
writeNode((Node) n, info, ser, changeSetId, settings.USER_NAME.get());
writeNode((Node) n, info, ser, changeSetId, settings.OSM_USER_NAME.get());
} else if (n instanceof Way) {
writeWay((Way) n, info, ser, changeSetId, settings.USER_NAME.get());
writeWay((Way) n, info, ser, changeSetId, settings.OSM_USER_NAME.get());
}
ser.endTag(null, OsmPoint.stringAction.get(action));
ser.endTag(null, "osmChange"); //$NON-NLS-1$

View file

@ -387,6 +387,7 @@ public class OsmBugsLayer extends OsmandMapLayer implements IContextMenuProvider
PointDescription pd = new PointDescription(PointDescription.POINT_TYPE_OSM_BUG, obj.local.getText());
activity.getContextMenu().show(new LatLon(obj.local.getLatitude(), obj.local.getLongitude()),
pd, obj.local);
activity.getMapLayers().getContextMenuLayer().updateContextMenu();
}
} else {
if (action == Action.REOPEN) {

View file

@ -141,7 +141,7 @@ public class OsmBugsRemoteUtil implements OsmBugsUtil {
connection.setRequestMethod(requestMethod);
connection.setRequestProperty("User-Agent", Version.getFullVersion(app));
if (!anonymous) {
String token = settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get();
String token = settings.OSM_USER_NAME.get() + ":" + settings.OSM_USER_PASSWORD.get();
connection.addRequestProperty("Authorization", "Basic " + Base64.encode(token.getBytes(StandardCharsets.UTF_8)));
}
connection.setDoInput(true);

View file

@ -112,7 +112,7 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
boolean validToken = isValidToken();
Preference nameAndPasswordPref = findPreference(OSM_LOGOUT);
if (validToken || isLoginExists()) {
String userName = validToken ? settings.USER_DISPLAY_NAME.get() : settings.USER_NAME.get();
String userName = validToken ? settings.OSM_USER_DISPLAY_NAME.get() : settings.OSM_USER_NAME.get();
nameAndPasswordPref.setVisible(true);
nameAndPasswordPref.setSummary(userName);
nameAndPasswordPref.setIcon(getContentIcon(R.drawable.ic_action_user_account));
@ -126,7 +126,7 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
}
private boolean isLoginExists() {
return !Algorithms.isEmpty(settings.USER_NAME.get()) && !Algorithms.isEmpty(settings.USER_PASSWORD.get());
return !Algorithms.isEmpty(settings.OSM_USER_NAME.get()) && !Algorithms.isEmpty(settings.OSM_USER_PASSWORD.get());
}
private void setupOfflineEditingPref() {
@ -140,7 +140,7 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
}
private void setupUseDevUrlPref() {
SwitchPreferenceEx useDevUrlPref = findPreference(settings.USE_DEV_URL.getId());
SwitchPreferenceEx useDevUrlPref = findPreference(settings.OSM_USE_DEV_URL.getId());
if (OsmandPlugin.isDevelopment()) {
Drawable icon = getPersistentPrefIcon(R.drawable.ic_action_laptop);
useDevUrlPref.setDescription(getString(R.string.use_dev_url_descr));
@ -176,8 +176,8 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
String prefId = preference.getKey();
if (settings.USE_DEV_URL.getId().equals(prefId) && newValue instanceof Boolean) {
settings.USE_DEV_URL.set((Boolean) newValue);
if (settings.OSM_USE_DEV_URL.getId().equals(prefId) && newValue instanceof Boolean) {
settings.OSM_USE_DEV_URL.set((Boolean) newValue);
osmLogout();
return true;
}
@ -220,7 +220,7 @@ public class OsmEditingFragment extends BaseSettingsFragment implements OnPrefer
@Override
public void onPreferenceChanged(String prefId) {
if (settings.USE_DEV_URL.getId().equals(prefId)) {
if (settings.OSM_USE_DEV_URL.getId().equals(prefId)) {
osmLogout();
}
updateAllSettings();

View file

@ -457,9 +457,9 @@ public class OsmEditingPlugin extends OsmandPlugin {
}
public boolean sendGPXFiles(final FragmentActivity activity, Fragment fragment, final GpxInfo... info) {
String name = settings.USER_NAME.get();
String pwd = settings.USER_PASSWORD.get();
String authToken = settings.USER_ACCESS_TOKEN.get();
String name = settings.OSM_USER_NAME.get();
String pwd = settings.OSM_USER_PASSWORD.get();
String authToken = settings.OSM_USER_ACCESS_TOKEN.get();
if ((Algorithms.isEmpty(name) || Algorithms.isEmpty(pwd)) && Algorithms.isEmpty(authToken)) {
LoginBottomSheetFragment.showInstance(activity.getSupportFragmentManager(), fragment);
return false;

View file

@ -30,8 +30,8 @@ public class ValidateOsmLoginDetailsTask extends AsyncTask<Void, Void, OsmBugRes
@Override
protected void onPostExecute(OsmBugResult osmBugResult) {
if (osmBugResult.warning != null) {
app.getSettings().USER_NAME.resetToDefault();
app.getSettings().USER_PASSWORD.resetToDefault();
app.getSettings().OSM_USER_NAME.resetToDefault();
app.getSettings().OSM_USER_PASSWORD.resetToDefault();
app.showToastMessage(osmBugResult.warning);
} else {
app.showToastMessage(R.string.osm_authorization_success);

View file

@ -69,10 +69,10 @@ public class SendGpxBottomSheetFragment extends MenuBottomSheetDialogFragment {
messageField = sendGpxView.findViewById(R.id.message_field);
TextView accountName = sendGpxView.findViewById(R.id.user_name);
if (!Algorithms.isEmpty(settings.USER_DISPLAY_NAME.get())) {
accountName.setText(settings.USER_DISPLAY_NAME.get());
if (!Algorithms.isEmpty(settings.OSM_USER_DISPLAY_NAME.get())) {
accountName.setText(settings.OSM_USER_DISPLAY_NAME.get());
} else {
accountName.setText(settings.USER_NAME.get());
accountName.setText(settings.OSM_USER_NAME.get());
}
String fileName = gpxInfos[0].getFileName();

View file

@ -61,7 +61,7 @@ public class SendOsmNoteBottomSheetFragment extends MenuBottomSheetDialogFragmen
private EditText noteText;
private boolean isLoginOAuth() {
return !Algorithms.isEmpty(settings.USER_DISPLAY_NAME.get());
return !Algorithms.isEmpty(settings.OSM_USER_DISPLAY_NAME.get());
}
@Override
@ -150,8 +150,8 @@ public class SendOsmNoteBottomSheetFragment extends MenuBottomSheetDialogFragmen
}
private void updateAccountName() {
String userNameOAuth = settings.USER_DISPLAY_NAME.get();
String userNameOpenID = settings.USER_NAME.get();
String userNameOAuth = settings.OSM_USER_DISPLAY_NAME.get();
String userNameOpenID = settings.OSM_USER_NAME.get();
String userName = isLoginOAuth() ? userNameOAuth : userNameOpenID;
accountName.setText(userName);
updateSignIn(uploadAnonymously.isChecked());
@ -230,7 +230,7 @@ public class SendOsmNoteBottomSheetFragment extends MenuBottomSheetDialogFragmen
private boolean isLogged() {
OsmOAuthAuthorizationAdapter adapter = app.getOsmOAuthHelper().getAuthorizationAdapter();
return adapter.isValidToken()
|| !Algorithms.isEmpty(settings.USER_NAME.get())
&& !Algorithms.isEmpty(settings.USER_PASSWORD.get());
|| !Algorithms.isEmpty(settings.OSM_USER_NAME.get())
&& !Algorithms.isEmpty(settings.OSM_USER_PASSWORD.get());
}
}

View file

@ -47,7 +47,7 @@ public class SendPoiBottomSheetFragment extends MenuBottomSheetDialogFragment {
private boolean isLoginOAuth(OsmandSettings settings) {
return !Algorithms.isEmpty(settings.USER_DISPLAY_NAME.get());
return !Algorithms.isEmpty(settings.OSM_USER_DISPLAY_NAME.get());
}
@Override
@ -68,8 +68,8 @@ public class SendPoiBottomSheetFragment extends MenuBottomSheetDialogFragment {
messageEditText.setSelection(messageEditText.getText().length());
final TextView accountName = sendOsmPoiView.findViewById(R.id.user_name);
OsmandSettings settings = app.getSettings();
String userNameOAuth = settings.USER_DISPLAY_NAME.get();
String userNameOpenID = settings.USER_NAME.get();
String userNameOAuth = settings.OSM_USER_DISPLAY_NAME.get();
String userNameOpenID = settings.OSM_USER_NAME.get();
String userName = isLoginOAuth(settings) ? userNameOAuth : userNameOpenID;
accountName.setText(userName);
final int paddingSmall = app.getResources().getDimensionPixelSize(R.dimen.content_padding_small);

View file

@ -7,6 +7,7 @@ import android.os.AsyncTask;
import android.view.ViewGroup;
import com.github.scribejava.core.builder.api.DefaultApi10a;
import com.github.scribejava.core.exceptions.OAuthException;
import com.github.scribejava.core.model.OAuth1AccessToken;
import com.github.scribejava.core.model.OAuth1RequestToken;
import com.github.scribejava.core.model.OAuthAsyncRequestCallback;
@ -42,7 +43,7 @@ public class OsmOAuthAuthorizationAdapter {
DefaultApi10a api10a;
String key;
String secret;
if (app.getSettings().USE_DEV_URL.get()) {
if (app.getSettings().OSM_USE_DEV_URL.get()) {
api10a = new OsmOAuthAuthorizationClient.OsmDevApi();
key = app.getString(R.string.osm_oauth_developer_key);
secret = app.getString(R.string.osm_oauth_developer_secret);
@ -68,8 +69,8 @@ public class OsmOAuthAuthorizationAdapter {
}
public void restoreToken() {
String token = app.getSettings().USER_ACCESS_TOKEN.get();
String tokenSecret = app.getSettings().USER_ACCESS_TOKEN_SECRET.get();
String token = app.getSettings().OSM_USER_ACCESS_TOKEN.get();
String tokenSecret = app.getSettings().OSM_USER_ACCESS_TOKEN_SECRET.get();
if (!(token.isEmpty() || tokenSecret.isEmpty())) {
client.setAccessToken(new OAuth1AccessToken(token, tokenSecret));
} else {
@ -83,8 +84,8 @@ public class OsmOAuthAuthorizationAdapter {
private void saveToken() {
OAuth1AccessToken accessToken = client.getAccessToken();
app.getSettings().USER_ACCESS_TOKEN.set(accessToken.getToken());
app.getSettings().USER_ACCESS_TOKEN_SECRET.set(accessToken.getTokenSecret());
app.getSettings().OSM_USER_ACCESS_TOKEN.set(accessToken.getToken());
app.getSettings().OSM_USER_ACCESS_TOKEN_SECRET.set(accessToken.getTokenSecret());
}
private void loadWebView(ViewGroup root, boolean nightMode, String url) {
@ -171,8 +172,10 @@ public class OsmOAuthAuthorizationAdapter {
log.error(e);
} catch (XmlPullParserException e) {
log.error(e);
} catch (OAuthException e) {
log.error(e);
}
app.getSettings().USER_DISPLAY_NAME.set(userName);
app.getSettings().OSM_USER_DISPLAY_NAME.set(userName);
}
public String getUserName() throws InterruptedException, ExecutionException, IOException, XmlPullParserException {

View file

@ -54,18 +54,18 @@ public class OsmOAuthHelper {
public void resetAuthorization() {
if (isValidToken()) {
settings.USER_ACCESS_TOKEN.resetToDefault();
settings.USER_ACCESS_TOKEN_SECRET.resetToDefault();
settings.OSM_USER_ACCESS_TOKEN.resetToDefault();
settings.OSM_USER_ACCESS_TOKEN_SECRET.resetToDefault();
authorizationAdapter.resetToken();
} else if (isLoginExists()) {
settings.USER_NAME.resetToDefault();
settings.USER_PASSWORD.resetToDefault();
settings.OSM_USER_NAME.resetToDefault();
settings.OSM_USER_PASSWORD.resetToDefault();
}
updateAdapter();
}
private boolean isLoginExists() {
return !Algorithms.isEmpty(settings.USER_NAME.get()) && !Algorithms.isEmpty(settings.USER_PASSWORD.get());
return !Algorithms.isEmpty(settings.OSM_USER_NAME.get()) && !Algorithms.isEmpty(settings.OSM_USER_PASSWORD.get());
}
public void notifyAndRemoveListeners() {

View file

@ -663,17 +663,19 @@ public class PoiFiltersHelper {
private SQLiteConnection openConnection(boolean readonly) {
conn = context.getSQLiteAPI().getOrCreateDatabase(DATABASE_NAME, readonly);
if (conn.getVersion() < DATABASE_VERSION) {
if (conn != null && conn.getVersion() < DATABASE_VERSION) {
if (readonly) {
conn.close();
conn = context.getSQLiteAPI().getOrCreateDatabase(DATABASE_NAME, false);
}
int version = conn.getVersion();
conn.setVersion(DATABASE_VERSION);
if (version == 0) {
onCreate(conn);
} else {
onUpgrade(conn, version, DATABASE_VERSION);
if (conn != null) {
int version = conn.getVersion();
conn.setVersion(DATABASE_VERSION);
if (version == 0) {
onCreate(conn);
} else {
onUpgrade(conn, version, DATABASE_VERSION);
}
}
}
return conn;

View file

@ -27,10 +27,14 @@ public abstract class AppModesBottomSheetDialogFragment<T extends AbstractProfil
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setDismissButtonTextId(R.string.shared_string_close);
getData();
}
@Override
protected int getDismissButtonTextId() {
return R.string.shared_string_close;
}
@Override
public void onDismiss(DialogInterface dialog) {
super.onDismiss(dialog);

View file

@ -48,6 +48,7 @@ import net.osmand.plus.helpers.enums.TracksSortByMode;
import net.osmand.plus.mapillary.MapillaryPlugin;
import net.osmand.plus.mapmarkers.CoordinateInputFormats.Format;
import net.osmand.plus.mapmarkers.MapMarkersMode;
import net.osmand.plus.openplacereviews.OpenPlaceReviewsPlugin;
import net.osmand.plus.profiles.LocationIcon;
import net.osmand.plus.profiles.NavigationIcon;
import net.osmand.plus.profiles.ProfileIconColors;
@ -653,7 +654,7 @@ public class OsmandSettings {
public static final String NUMBER_OF_FREE_DOWNLOADS_ID = "free_downloads_v3";
// this value string is synchronized with settings_pref.xml preference name
private final OsmandPreference<String> PLUGINS = new StringPreference(this, "enabled_plugins", MapillaryPlugin.ID).makeGlobal().makeShared();
private final OsmandPreference<String> PLUGINS = new StringPreference(this, "enabled_plugins", "").makeGlobal().makeShared();
public Set<String> getEnabledPlugins() {
String plugs = PLUGINS.get();
@ -1121,8 +1122,8 @@ public class OsmandSettings {
}
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<String> USER_NAME = new StringPreference(this, "user_name", "").makeGlobal().makeShared();
public final OsmandPreference<String> USER_DISPLAY_NAME = new StringPreference(this, "user_display_name", "").makeGlobal().makeShared();
public final OsmandPreference<String> OSM_USER_NAME = new StringPreference(this, "user_name", "").makeGlobal().makeShared();
public final OsmandPreference<String> OSM_USER_DISPLAY_NAME = new StringPreference(this, "user_display_name", "").makeGlobal().makeShared();
public static final String BILLING_USER_DONATION_WORLD_PARAMETER = "";
public static final String BILLING_USER_DONATION_NONE_PARAMETER = "none";
@ -1156,13 +1157,13 @@ public class OsmandSettings {
new StringPreference(this, "user_osm_bug_name", "NoName/OsmAnd").makeGlobal().makeShared();
// this value string is synchronized with settings_pref.xml preference name
public final OsmandPreference<String> USER_PASSWORD =
public final OsmandPreference<String> OSM_USER_PASSWORD =
new StringPreference(this, "user_password", "").makeGlobal().makeShared();
public final OsmandPreference<String> USER_ACCESS_TOKEN =
public final OsmandPreference<String> OSM_USER_ACCESS_TOKEN =
new StringPreference(this, "user_access_token", "").makeGlobal();
public final OsmandPreference<String> USER_ACCESS_TOKEN_SECRET =
public final OsmandPreference<String> OSM_USER_ACCESS_TOKEN_SECRET =
new StringPreference(this, "user_access_token_secret", "").makeGlobal();
public final OsmandPreference<String> OPR_ACCESS_TOKEN =
@ -1174,13 +1175,15 @@ public class OsmandSettings {
public final OsmandPreference<String> OPR_BLOCKCHAIN_NAME =
new StringPreference(this, "opr_blockchain_name", "").makeGlobal();
public final OsmandPreference<Boolean> OPR_USE_DEV_URL = new BooleanPreference(this, "opr_use_dev_url", false).makeGlobal().makeShared();
// this value boolean is synchronized with settings_pref.xml preference offline POI/Bugs edition
public final OsmandPreference<Boolean> OFFLINE_EDITION = new BooleanPreference(this, "offline_osm_editing", true).makeGlobal().makeShared();
public final OsmandPreference<Boolean> USE_DEV_URL = new BooleanPreference(this, "use_dev_url", false).makeGlobal().makeShared();
public final OsmandPreference<Boolean> OSM_USE_DEV_URL = new BooleanPreference(this, "use_dev_url", false).makeGlobal().makeShared();
public String getOsmUrl() {
String osmUrl;
if (USE_DEV_URL.get()) {
if (OSM_USE_DEV_URL.get()) {
osmUrl = "https://master.apis.dev.openstreetmap.org/";
} else {
osmUrl = "https://api.openstreetmap.org/";
@ -1188,6 +1191,10 @@ public class OsmandSettings {
return osmUrl;
}
public String getOprUrl() {
return ctx.getString(OPR_USE_DEV_URL.get() ? R.string.dev_opr_base_url : R.string.opr_base_url);
}
// this value string is synchronized with settings_pref.xml preference name
public final CommonPreference<DayNightMode> DAYNIGHT_MODE =
new EnumStringPreference<DayNightMode>(this, "daynight_mode", DayNightMode.DAY, DayNightMode.values());

View file

@ -6,7 +6,6 @@ import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.ScrollView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -49,8 +48,8 @@ public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet {
userNameEditText = view.findViewById(R.id.name_edit_text);
passwordEditText = view.findViewById(R.id.password_edit_text);
String name = app.getSettings().USER_NAME.get();
String password = app.getSettings().USER_PASSWORD.get();
String name = app.getSettings().OSM_USER_NAME.get();
String password = app.getSettings().OSM_USER_PASSWORD.get();
if (savedInstanceState != null) {
name = savedInstanceState.getString(USER_NAME_KEY, null);
@ -96,8 +95,8 @@ public class OsmLoginDataBottomSheet extends BasePreferenceBottomSheet {
protected void onRightBottomButtonClick() {
OsmandApplication app = requiredMyApplication();
app.getSettings().USER_NAME.set(userNameEditText.getText().toString());
app.getSettings().USER_PASSWORD.set(passwordEditText.getText().toString());
app.getSettings().OSM_USER_NAME.set(userNameEditText.getText().toString());
app.getSettings().OSM_USER_PASSWORD.set(passwordEditText.getText().toString());
Fragment targetFragment = getTargetFragment();
if (targetFragment instanceof ValidateOsmLoginListener) {

View file

@ -61,6 +61,7 @@ import net.osmand.plus.activities.OsmandInAppPurchaseActivity;
import net.osmand.plus.audionotes.MultimediaNotesFragment;
import net.osmand.plus.development.DevelopmentSettingsFragment;
import net.osmand.plus.monitoring.MonitoringSettingsFragment;
import net.osmand.plus.openplacereviews.OprSettingsFragment;
import net.osmand.plus.osmedit.OsmEditingFragment;
import net.osmand.plus.profiles.SelectAppModesBottomSheetDialogFragment;
import net.osmand.plus.profiles.SelectAppModesBottomSheetDialogFragment.AppModeChangedListener;
@ -133,6 +134,7 @@ public abstract class BaseSettingsFragment extends PreferenceFragmentCompat impl
MONITORING_SETTINGS(MonitoringSettingsFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.monitoring_settings, R.layout.profile_preference_toolbar),
LIVE_MONITORING(LiveMonitoringFragment.class.getName(), false, ApplyQueryType.SNACK_BAR, R.xml.live_monitoring, R.layout.global_preferences_toolbar_with_switch),
ACCESSIBILITY_SETTINGS(AccessibilitySettingsFragment.class.getName(), true, ApplyQueryType.SNACK_BAR, R.xml.accessibility_settings, R.layout.profile_preference_toolbar),
OPEN_PLACE_REVIEWS(OprSettingsFragment.class.getName(), false, null, R.xml.open_place_reviews, R.layout.global_preference_toolbar),
DEVELOPMENT_SETTINGS(DevelopmentSettingsFragment.class.getName(), false, null, R.xml.development_settings, R.layout.global_preference_toolbar);
public final String fragmentName;

View file

@ -1,7 +1,6 @@
package net.osmand.plus.track;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -87,7 +86,6 @@ public class GpxBlockStatisticsBuilder {
updatingStats = new Runnable() {
@Override
public void run() {
Log.d("BlockStatisticsBuilder", "run: working");
if (bsAdapter != null) {
initItems();
bsAdapter.setItems(items);
@ -168,7 +166,6 @@ public class GpxBlockStatisticsBuilder {
}
public class StatBlock {
private final String title;
private final String value;
private final int imageResId;

View file

@ -2,73 +2,46 @@ package net.osmand.plus.track;
import android.annotation.SuppressLint;
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import net.osmand.AndroidUtils;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayGroup;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItem;
import net.osmand.plus.GpxSelectionHelper.GpxDisplayItemType;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.helpers.GpxUiHelper.GPXDataSetType;
import net.osmand.plus.myplaces.SegmentActionsListener;
import net.osmand.plus.routepreparationmenu.cards.BaseCard;
import net.osmand.plus.widgets.TextViewEx;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
import java.util.List;
import static net.osmand.plus.myplaces.TrackActivityFragmentAdapter.isGpxFileSelected;
import static net.osmand.plus.track.OptionsCard.APPEARANCE_BUTTON_INDEX;
import static net.osmand.plus.track.OptionsCard.DIRECTIONS_BUTTON_INDEX;
import static net.osmand.plus.track.OptionsCard.EDIT_BUTTON_INDEX;
import static net.osmand.plus.track.OptionsCard.SHOW_ON_MAP_BUTTON_INDEX;
import static net.osmand.plus.track.OverviewCard.StatBlock.ItemType.*;
public class OverviewCard extends BaseCard {
private RecyclerView rvOverview;
private View showButton;
private View appearanceButton;
private View editButton;
private View directionsButton;
private final TrackDisplayHelper displayHelper;
private final GPXFile gpxFile;
private final GpxDisplayItemType[] filterTypes = {GpxDisplayItemType.TRACK_SEGMENT};
private final SegmentActionsListener listener;
private boolean gpxFileSelected;
private GpxDisplayItem gpxItem;
private final SegmentActionsListener actionsListener;
private final SelectedGpxFile selectedGpxFile;
private final GpxBlockStatisticsBuilder blockStatisticsBuilder;
public OverviewCard(@NonNull MapActivity mapActivity, @NonNull TrackDisplayHelper displayHelper,
@NonNull SegmentActionsListener listener) {
@NonNull SegmentActionsListener actionsListener, SelectedGpxFile selectedGpxFile) {
super(mapActivity);
this.displayHelper = displayHelper;
this.listener = listener;
gpxFile = displayHelper.getGpx();
gpxFileSelected = isGpxFileSelected(app, gpxFile);
List<GpxDisplayGroup> groups = displayHelper.getOriginalGroups(filterTypes);
if (!Algorithms.isEmpty(groups)) {
gpxItem = TrackDisplayHelper.flatten(displayHelper.getOriginalGroups(filterTypes)).get(0);
}
this.actionsListener = actionsListener;
this.selectedGpxFile = selectedGpxFile;
blockStatisticsBuilder = new GpxBlockStatisticsBuilder(app, selectedGpxFile, displayHelper);
}
@Override
@ -80,13 +53,15 @@ public class OverviewCard extends BaseCard {
protected void updateContent() {
int iconColorDef = nightMode ? R.color.icon_color_active_dark : R.color.icon_color_active_light;
int iconColorPres = R.color.active_buttons_and_links_text_dark;
GPXFile gpxFile = getGPXFile();
boolean fileAvailable = gpxFile.path != null && !gpxFile.showCurrentTrack;
showButton = view.findViewById(R.id.show_button);
appearanceButton = view.findViewById(R.id.appearance_button);
editButton = view.findViewById(R.id.edit_button);
directionsButton = view.findViewById(R.id.directions_button);
rvOverview = view.findViewById(R.id.recycler_overview);
RecyclerView blocksView = view.findViewById(R.id.recycler_overview);
blockStatisticsBuilder.setBlocksView(blocksView);
initShowButton(iconColorDef, iconColorPres);
initAppearanceButton(iconColorDef, iconColorPres);
@ -94,51 +69,16 @@ public class OverviewCard extends BaseCard {
initEditButton(iconColorDef, iconColorPres);
initDirectionsButton(iconColorDef, iconColorPres);
}
initStatBlocks();
blockStatisticsBuilder.initStatBlocks(actionsListener, getActiveColor(), nightMode);
}
void initStatBlocks() {
if (gpxItem != null) {
GPXTrackAnalysis analysis = gpxItem.analysis;
boolean joinSegments = displayHelper.isJoinSegments();
float totalDistance = !joinSegments && gpxItem.isGeneralTrack() ? analysis.totalDistanceWithoutGaps : analysis.totalDistance;
float timeSpan = !joinSegments && gpxItem.isGeneralTrack() ? analysis.timeSpanWithoutGaps : analysis.timeSpan;
String asc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationUp, app);
String desc = OsmAndFormatter.getFormattedAlt(analysis.diffElevationDown, app);
String avg = OsmAndFormatter.getFormattedSpeed(analysis.avgSpeed, app);
String max = OsmAndFormatter.getFormattedSpeed(analysis.maxSpeed, app);
List<StatBlock> items = new ArrayList<>();
StatBlock.prepareData(analysis, items, app.getString(R.string.distance), OsmAndFormatter.getFormattedDistance(totalDistance, app),
R.drawable.ic_action_track_16, R.color.icon_color_default_light, GPXDataSetType.ALTITUDE, GPXDataSetType.SPEED, ITEM_DISTANCE);
StatBlock.prepareData(analysis, items, app.getString(R.string.altitude_ascent), asc,
R.drawable.ic_action_arrow_up_16, R.color.gpx_chart_red, GPXDataSetType.SLOPE, null, ITEM_ALTITUDE);
StatBlock.prepareData(analysis, items, app.getString(R.string.altitude_descent), desc,
R.drawable.ic_action_arrow_down_16, R.color.gpx_pale_green, GPXDataSetType.ALTITUDE, GPXDataSetType.SLOPE, ITEM_ALTITUDE);
StatBlock.prepareData(analysis, items, app.getString(R.string.average_speed), avg,
R.drawable.ic_action_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ITEM_SPEED);
StatBlock.prepareData(analysis, items, app.getString(R.string.max_speed), max,
R.drawable.ic_action_max_speed_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ITEM_SPEED);
StatBlock.prepareData(analysis, items, app.getString(R.string.shared_string_time_span),
Algorithms.formatDuration((int) (timeSpan / 1000), app.accessibilityEnabled()),
R.drawable.ic_action_time_span_16, R.color.icon_color_default_light, GPXDataSetType.SPEED, null, ITEM_TIME);
if (Algorithms.isEmpty(items)) {
AndroidUiHelper.updateVisibility(rvOverview, false);
} else {
final StatBlockAdapter sbAdapter = new StatBlockAdapter(items);
rvOverview.setLayoutManager(new LinearLayoutManager(app, LinearLayoutManager.HORIZONTAL, false));
rvOverview.setAdapter(sbAdapter);
}
} else {
AndroidUiHelper.updateVisibility(rvOverview, false);
}
private GPXFile getGPXFile() {
return selectedGpxFile.getGpxFile();
}
@DrawableRes
private int getActiveShowHideIcon() {
gpxFileSelected = isGpxFileSelected(app, gpxFile);
return gpxFileSelected ? R.drawable.ic_action_view : R.drawable.ic_action_hide;
return isGpxFileSelected(app, getGPXFile()) ? R.drawable.ic_action_view : R.drawable.ic_action_hide;
}
private void initShowButton(final int iconColorDef, final int iconColorPres) {
@ -207,135 +147,4 @@ public class OverviewCard extends BaseCard {
}
});
}
private class StatBlockAdapter extends RecyclerView.Adapter<StatBlockViewHolder> {
private final List<StatBlock> statBlocks;
public StatBlockAdapter(List<StatBlock> StatBlocks) {
this.statBlocks = StatBlocks;
}
@Override
public int getItemCount() {
return statBlocks.size();
}
@NonNull
@Override
public StatBlockViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.item_gpx_stat_block, parent, false);
return new StatBlockViewHolder(itemView);
}
@Override
public void onBindViewHolder(StatBlockViewHolder holder, int position) {
final StatBlock item = statBlocks.get(position);
holder.valueText.setText(item.value);
holder.titleText.setText(item.title);
holder.valueText.setTextColor(getActiveColor());
holder.titleText.setTextColor(app.getResources().getColor(R.color.text_color_secondary_light));
holder.itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (gpxItem != null && gpxItem.analysis != null) {
ArrayList<GPXDataSetType> list = new ArrayList<>();
if (gpxItem.analysis.hasElevationData || gpxItem.analysis.isSpeedSpecified() || gpxItem.analysis.hasSpeedData) {
if (item.firstType != null) {
list.add(item.firstType);
}
if (item.secondType != null) {
list.add(item.secondType);
}
}
gpxItem.chartTypes = list.size() > 0 ? list.toArray(new GPXDataSetType[0]) : null;
gpxItem.locationOnMap = gpxItem.locationStart;
listener.openAnalyzeOnMap(gpxItem);
}
}
});
setImageDrawable(holder.imageView, item.imageResId, item.imageColorId);
AndroidUtils.setBackgroundColor(view.getContext(), holder.divider, nightMode, R.color.divider_color_light, R.color.divider_color_dark);
AndroidUiHelper.updateVisibility(holder.divider, position != statBlocks.size() - 1);
}
}
private static class StatBlockViewHolder extends RecyclerView.ViewHolder {
private final TextViewEx valueText;
private final TextView titleText;
private final AppCompatImageView imageView;
private final View divider;
StatBlockViewHolder(View view) {
super(view);
valueText = view.findViewById(R.id.value);
titleText = view.findViewById(R.id.title);
imageView = view.findViewById(R.id.image);
divider = view.findViewById(R.id.divider);
}
}
protected static class StatBlock {
private final String title;
private final String value;
private final int imageResId;
private final int imageColorId;
private final GPXDataSetType firstType;
private final GPXDataSetType secondType;
private final ItemType itemType;
public StatBlock(String title, String value, @DrawableRes int imageResId, @ColorRes int imageColorId,
GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) {
this.title = title;
this.value = value;
this.imageResId = imageResId;
this.imageColorId = imageColorId;
this.firstType = firstType;
this.secondType = secondType;
this.itemType = itemType;
}
public static void prepareData(GPXTrackAnalysis analysis, List<StatBlock> listItems, String title,
String value, @DrawableRes int imageResId, @ColorRes int imageColorId,
GPXDataSetType firstType, GPXDataSetType secondType, ItemType itemType) {
StatBlock statBlock = new StatBlock(title, value, imageResId, imageColorId, firstType, secondType, itemType);
switch (statBlock.itemType) {
case ITEM_DISTANCE: {
if (analysis.totalDistance != 0f) {
listItems.add(statBlock);
}
break;
}
case ITEM_ALTITUDE: {
if (analysis.hasElevationData) {
listItems.add(statBlock);
}
break;
}
case ITEM_SPEED: {
if (analysis.isSpeedSpecified()) {
listItems.add(statBlock);
}
break;
}
case ITEM_TIME: {
if (analysis.hasSpeedData) {
listItems.add(statBlock);
}
break;
}
}
}
public enum ItemType {
ITEM_DISTANCE,
ITEM_ALTITUDE,
ITEM_SPEED,
ITEM_TIME;
}
}
}

View file

@ -312,7 +312,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
}
headerContainer.addView(overviewCard.getView());
} else {
overviewCard = new OverviewCard(getMapActivity(), displayHelper, this);
overviewCard = new OverviewCard(getMapActivity(), displayHelper, this, selectedGpxFile);
overviewCard.setListener(this);
headerContainer.addView(overviewCard.build(getMapActivity()));
}
@ -890,8 +890,6 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
private void updateMenuState() {
if (menuType == TrackMenuType.OPTIONS) {
openMenuFullScreen();
} else if (menuType == TrackMenuType.OVERVIEW) {
openMenuHeaderOnly();
} else {
openMenuHalfScreen();
}
@ -899,6 +897,9 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
@Override
public void updateContent() {
if (overviewCard != null) {
overviewCard.updateContent();
}
if (segmentsCard != null) {
segmentsCard.updateContent();
}
@ -1098,7 +1099,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
boolean currentRecording = file == null;
String path = file != null ? file.getAbsolutePath() : null;
if (context instanceof MapActivity) {
TrackMenuFragment.showInstance((MapActivity) context, path, currentRecording);
TrackMenuFragment.showInstance((MapActivity) context, path, currentRecording, null);
} else {
Bundle bundle = new Bundle();
bundle.putString(TRACK_FILE_NAME, path);
@ -1108,7 +1109,8 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
}
}
public static void showInstance(@NonNull final MapActivity mapActivity, @Nullable String path, boolean showCurrentTrack) {
public static void showInstance(@NonNull final MapActivity mapActivity, @Nullable String path,
boolean showCurrentTrack, @Nullable final LatLon latLon) {
OsmandApplication app = mapActivity.getMyApplication();
SelectedGpxFile selectedGpxFile;
if (showCurrentTrack) {
@ -1117,7 +1119,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
selectedGpxFile = app.getSelectedGpxHelper().getSelectedFileByPath(path);
}
if (selectedGpxFile != null) {
showInstance(mapActivity, selectedGpxFile, null);
showInstance(mapActivity, selectedGpxFile, latLon);
} else if (!Algorithms.isEmpty(path)) {
String title = app.getString(R.string.loading_smth, "");
final ProgressDialog progress = ProgressDialog.show(mapActivity, title, app.getString(R.string.loading_data));
@ -1130,7 +1132,9 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
if (mapActivity != null) {
OsmandApplication app = mapActivity.getMyApplication();
SelectedGpxFile selectedGpxFile = app.getSelectedGpxHelper().selectGpxFile(result, true, false);
showInstance(mapActivity, selectedGpxFile, null);
if (selectedGpxFile != null) {
showInstance(mapActivity, selectedGpxFile, latLon);
}
}
if (progress != null && AndroidUtils.isActivityNotDestroyed(mapActivity)) {
progress.dismiss();
@ -1142,7 +1146,7 @@ public class TrackMenuFragment extends ContextMenuScrollFragment implements Card
}
}
public static boolean showInstance(@NonNull MapActivity mapActivity, SelectedGpxFile selectedGpxFile, @Nullable LatLon latLon) {
public static boolean showInstance(@NonNull MapActivity mapActivity, @NonNull SelectedGpxFile selectedGpxFile, @Nullable LatLon latLon) {
try {
Bundle args = new Bundle();
args.putInt(ContextMenuFragment.MENU_STATE_KEY, MenuState.HEADER_ONLY);

View file

@ -17,26 +17,28 @@ import net.osmand.data.QuadTree;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.FavouritesDbHelper.FavoriteGroup;
import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.base.PointImageDrawable;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkersHelper;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.ContextMenuLayer.ApplyMovedObjectCallback;
import net.osmand.plus.views.layers.ContextMenuLayer.IContextMenuProvider;
import net.osmand.plus.views.layers.ContextMenuLayer.IMoveObjectProvider;
import net.osmand.plus.views.layers.MapTextLayer.MapTextProvider;
import java.util.ArrayList;
import java.util.List;
public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.IContextMenuProvider,
ContextMenuLayer.IMoveObjectProvider, MapTextProvider<FavouritePoint> {
public class FavouritesLayer extends OsmandMapLayer implements IContextMenuProvider, IMoveObjectProvider,
MapTextProvider<FavouritePoint> {
protected int startZoom = 6;
protected OsmandMapTileView view;
private FavouritesDbHelper favorites;
private FavouritesDbHelper favouritesDbHelper;
private MapMarkersHelper mapMarkersHelper;
protected List<FavouritePoint> cache = new ArrayList<>();
private MapTextLayer textLayer;
@ -54,7 +56,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
public void initLayer(OsmandMapTileView view) {
this.view = view;
settings = view.getApplication().getSettings();
favorites = view.getApplication().getFavorites();
favouritesDbHelper = view.getApplication().getFavorites();
mapMarkersHelper = view.getApplication().getMapMarkersHelper();
textLayer = view.getLayerByClass(MapTextLayer.class);
defaultColor = ContextCompat.getColor(view.getContext(), R.color.color_favorite);
@ -92,7 +94,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
@Override
public void onPrepareBufferImage(Canvas canvas, RotatedTileBox tileBox, DrawSettings settings) {
cache.clear();
if (this.settings.SHOW_FAVORITES.get() && favorites.isFavoritesLoaded()) {
if (this.settings.SHOW_FAVORITES.get() && favouritesDbHelper.isFavoritesLoaded()) {
if (tileBox.getZoom() >= startZoom) {
float textScale = this.settings.TEXT_SCALE.get();
float iconSize = getIconSize(view.getApplication());
@ -102,7 +104,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
final QuadRect latLonBounds = tileBox.getLatLonBounds();
List<LatLon> fullObjectsLatLon = new ArrayList<>();
List<LatLon> smallObjectsLatLon = new ArrayList<>();
for (FavoriteGroup group : favorites.getFavoriteGroups()) {
for (FavoriteGroup group : favouritesDbHelper.getFavoriteGroups()) {
List<Pair<FavouritePoint, MapMarker>> fullObjects = new ArrayList<>();
boolean synced = mapMarkersHelper.getMarkersGroup(group) != null;
for (FavouritePoint favoritePoint : group.getPoints()) {
@ -127,7 +129,7 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
if (marker != null && marker.history) {
color = grayColor;
} else {
color = favorites.getColorWithCategory(favoritePoint,defaultColor);
color = favouritesDbHelper.getColorWithCategory(favoritePoint,defaultColor);
}
PointImageDrawable pointImageDrawable = PointImageDrawable.getFromFavorite(
view.getContext(), color,true, favoritePoint);
@ -162,11 +164,11 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
boolean history = false;
if (marker != null) {
pointImageDrawable = PointImageDrawable.getOrCreateSyncedIcon(view.getContext(),
favorites.getColorWithCategory(favoritePoint,defaultColor), favoritePoint);
favouritesDbHelper.getColorWithCategory(favoritePoint,defaultColor), favoritePoint);
history = marker.history;
} else {
pointImageDrawable = PointImageDrawable.getFromFavorite(view.getContext(),
favorites.getColorWithCategory(favoritePoint, defaultColor),true, favoritePoint);
favouritesDbHelper.getColorWithCategory(favoritePoint, defaultColor),true, favoritePoint);
}
pointImageDrawable.drawPoint(canvas, x, y, textScale, history);
}
@ -180,7 +182,8 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
int r = getScaledTouchRadius(view.getApplication(), getDefaultRadiusPoi(tb));
int ex = (int) point.x;
int ey = (int) point.y;
for (FavouritePoint n : favorites.getFavouritePoints()) {
List<FavouritePoint> favouritePoints = new ArrayList<>(favouritesDbHelper.getFavouritePoints());
for (FavouritePoint n : favouritePoints) {
getFavFromPoint(tb, res, r, ex, ey, n);
}
}
@ -275,8 +278,8 @@ public class FavouritesLayer extends OsmandMapLayer implements ContextMenuLayer.
@Nullable ApplyMovedObjectCallback callback) {
boolean result = false;
if (o instanceof FavouritePoint) {
favorites.editFavourite((FavouritePoint) o, position.getLatitude(), position.getLongitude());
favorites.lookupAddress((FavouritePoint) o);
favouritesDbHelper.editFavourite((FavouritePoint) o, position.getLatitude(), position.getLongitude());
favouritesDbHelper.lookupAddress((FavouritePoint) o);
result = true;
}
if (callback != null) {

View file

@ -3,9 +3,11 @@ package net.osmand.plus.views.layers;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.graphics.drawable.Drawable;
import android.text.util.Linkify;
import android.util.Base64;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
@ -41,6 +43,7 @@ import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.OsmandMapLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.MapTextLayer.MapTextProvider;
import net.osmand.plus.widgets.WebViewEx;
import net.osmand.util.Algorithms;
import java.util.ArrayList;
@ -272,7 +275,39 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
}
public static void showDescriptionDialog(Context ctx, OsmandApplication app, String text, String title) {
showText(ctx, app, text, title);
final TextView textView = new TextView(ctx);
LinearLayout.LayoutParams llTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int textMargin = dpToPx(app, 10f);
boolean light = app.getSettings().isLightContent();
textView.setLayoutParams(llTextParams);
textView.setPadding(textMargin, textMargin, textMargin, textMargin);
textView.setTextSize(16);
textView.setTextColor(ContextCompat.getColor(app, light ? R.color.text_color_primary_light : R.color.text_color_primary_dark));
textView.setAutoLinkMask(Linkify.ALL);
textView.setLinksClickable(true);
textView.setText(text);
showText(ctx, app, textView, title);
}
public static void showHtmlDescriptionDialog(Context ctx, OsmandApplication app, String html, String title) {
final WebViewEx webView = new WebViewEx(ctx);
LinearLayout.LayoutParams llTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
webView.setLayoutParams(llTextParams);
int margin = dpToPx(app, 10f);
webView.setPadding(margin, margin, margin, margin);
webView.setScrollbarFadingEnabled(true);
webView.setVerticalScrollBarEnabled(false);
webView.setBackgroundColor(Color.TRANSPARENT);
webView.getSettings().setTextZoom((int) (app.getResources().getConfiguration().fontScale * 100f));
boolean light = app.getSettings().isLightContent();
int textColor = ContextCompat.getColor(app, light ? R.color.text_color_primary_light : R.color.text_color_primary_dark);
String rgbHex = Algorithms.colorToString(textColor);
html = "<body style=\"color:" + rgbHex + ";\">" + html + "</body>";
String encoded = Base64.encodeToString(html.getBytes(), Base64.NO_PADDING);
webView.loadData(encoded, "text/html", "base64");
showText(ctx, app, webView, title);
}
static int getResIdFromAttribute(final Context ctx, final int attr) {
@ -284,7 +319,7 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
return typedvalueattr.resourceId;
}
private static void showText(final Context ctx, final OsmandApplication app, final String text, String title) {
private static void showText(final Context ctx, final OsmandApplication app, final View view, String title) {
final Dialog dialog = new Dialog(ctx,
app.getSettings().isLightContent() ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
@ -306,24 +341,12 @@ public class POIMapLayer extends OsmandMapLayer implements ContextMenuLayer.ICon
}
});
final TextView textView = new TextView(ctx);
LinearLayout.LayoutParams llTextParams = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int textMargin = dpToPx(app, 10f);
boolean light = app.getSettings().isLightContent();
textView.setLayoutParams(llTextParams);
textView.setPadding(textMargin, textMargin, textMargin, textMargin);
textView.setTextSize(16);
textView.setTextColor(ContextCompat.getColor(app, light ? R.color.text_color_primary_light : R.color.text_color_primary_dark));
textView.setAutoLinkMask(Linkify.ALL);
textView.setLinksClickable(true);
textView.setText(text);
ScrollView scrollView = new ScrollView(ctx);
ll.addView(topBar);
LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, 0);
lp.weight = 1;
ll.addView(scrollView, lp);
scrollView.addView(textView);
scrollView.addView(view);
dialog.setContentView(ll);
dialog.setCancelable(true);

View file

@ -130,7 +130,9 @@ public class PointLocationLayer extends OsmandMapLayer implements ContextMenuLay
canvas.restore();
}
// Issue 5538: Some devices return positives for hasBearing() at rest, hence add 0.0 check:
boolean isBearing = lastKnownLocation.hasBearing() && (lastKnownLocation.getBearing() != 0.0);
boolean isBearing = lastKnownLocation.hasBearing() && (lastKnownLocation.getBearing() != 0.0)
&& (!lastKnownLocation.hasSpeed() || lastKnownLocation.getSpeed() > 0.1);
if (!locationOutdated && isBearing) {
float bearing = lastKnownLocation.getBearing();
canvas.rotate(bearing - 90, locationX, locationY);

View file

@ -90,9 +90,12 @@ public class JSMediaCommandPlayerImpl extends MediaCommandPlayerImpl {
if (voiceDir.getName().contains("tts")) {
return false;
}
for (File f : voiceDir.listFiles()) {
if (f.getName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) {
return true;
File[] files = voiceDir.listFiles();
if (files != null) {
for (File f : files) {
if (f.getName().endsWith(IndexConstants.TTSVOICE_INDEX_EXT_JS)) {
return true;
}
}
}
return false;

View file

@ -1,10 +1,12 @@
package net.osmand.plus.wikipedia;
import android.app.Activity;
import android.content.Intent;
import android.view.View;
import android.widget.ArrayAdapter;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import net.osmand.AndroidUtils;
@ -24,6 +26,8 @@ import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.download.DownloadActivityType;
import net.osmand.plus.download.DownloadIndexesThread;
import net.osmand.plus.download.DownloadResources;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard;
import net.osmand.plus.mapcontextmenu.builders.cards.ImageCard.GetImageCardsTask.GetImageCardsListener;
import net.osmand.plus.poi.PoiFiltersHelper;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.search.QuickSearchDialogFragment;
@ -32,8 +36,9 @@ import net.osmand.plus.search.listitems.QuickSearchBannerListItem;
import net.osmand.plus.search.listitems.QuickSearchFreeBannerListItem;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.views.layers.DownloadedRegionsLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.plus.views.layers.DownloadedRegionsLayer;
import net.osmand.plus.wikimedia.WikiImageHelper;
import net.osmand.search.core.ObjectType;
import net.osmand.search.core.SearchPhrase;
import net.osmand.util.Algorithms;
@ -42,6 +47,7 @@ import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static net.osmand.aidlapi.OsmAndCustomizationConstants.WIKIPEDIA_ID;
@ -91,11 +97,24 @@ public class WikipediaPlugin extends OsmandPlugin {
this.mapActivity = activity;
}
@Override
public void mapActivityResumeOnTop(MapActivity activity) {
this.mapActivity = activity;
}
@Override
public void mapActivityPause(MapActivity activity) {
this.mapActivity = null;
}
@Override
public boolean init(@NonNull OsmandApplication app, Activity activity) {
if (activity instanceof MapActivity) {
mapActivity = (MapActivity) activity;
}
return true;
}
@Override
protected void registerLayerContextMenuActions(OsmandMapTileView mapView,
ContextMenuAdapter adapter,
@ -435,4 +454,25 @@ public class WikipediaPlugin extends OsmandPlugin {
}
return false;
}
@Override
protected List<ImageCard> getContextMenuImageCards(@NonNull Map<String, String> params, @Nullable Map<String, String> additionalParams, @Nullable GetImageCardsListener listener) {
List<ImageCard> imageCards = new ArrayList<>();
if (mapActivity != null) {
if (additionalParams != null) {
String wikidataId = additionalParams.get(Amenity.WIKIDATA);
if (wikidataId != null) {
additionalParams.remove(Amenity.WIKIDATA);
WikiImageHelper.addWikidataImageCards(mapActivity, wikidataId, imageCards);
}
String wikimediaContent = additionalParams.get(Amenity.WIKIMEDIA_COMMONS);
if (wikimediaContent != null) {
additionalParams.remove(Amenity.WIKIMEDIA_COMMONS);
WikiImageHelper.addWikimediaImageCards(mapActivity, wikimediaContent, imageCards);
}
params.putAll(additionalParams);
}
}
return imageCards;
}
}

View file

@ -2,8 +2,6 @@ package net.osmand.plus.wikivoyage.menu;
import android.view.View;
import androidx.annotation.NonNull;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
@ -12,6 +10,8 @@ import net.osmand.util.Algorithms;
import java.util.HashMap;
import androidx.annotation.NonNull;
public class WikivoyageWptPtMenuBuilder extends WptPtMenuBuilder {
private final static String KEY_PHONE = "Phone: ";
@ -30,12 +30,13 @@ public class WikivoyageWptPtMenuBuilder extends WptPtMenuBuilder {
@Override
protected void buildDescription(View view) {
final String desc = descTokens.get(KEY_DESCRIPTION);
String desc = descTokens.get(KEY_DESCRIPTION);
if (!Algorithms.isEmpty(desc)) {
buildDescriptionRow(view, app.getString(R.string.shared_string_description), desc, 0, 10, true);
buildDescriptionRow(view, desc);
}
}
@Override
protected void prepareDescription(final WptPt wpt, View view) {
String phones = descTokens.get(KEY_PHONE);