Merge pull request #10760 from osmandapp/master

update test branch
This commit is contained in:
Hardy 2021-02-04 08:12:40 +01:00 committed by GitHub
commit b767cc0941
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
102 changed files with 2475 additions and 1552 deletions

3
.gitignore vendored
View file

@ -16,7 +16,8 @@ OsmAndCore_*.aar
*.iml
.settings
.idea
.project
**/.project
**/.classpath
out/
# Huawei

View file

@ -0,0 +1,218 @@
package net.osmand.osm;
public enum RouteActivityType {
WATER("Water", "yellow"), WINTER("Winter", "yellow"), SNOWMOBILE("Snowmobile", "yellow"), RIDING("Riding", "yellow"), RACING("Racing", "yellow"),
MOUNTAINBIKE("Mountainbike", "blue"), CYCLING("Cycling", "blue"),
HIKING("Hiking", "orange"), RUNNING("Running", "orange"), WALKING("Walking", "orange"),
OFFROAD("Off-road", "yellow"),
MOTORBIKE("Motorbike", "green"), CAR("Car", "green");
// less specific bottom order
String name;
String color;
private RouteActivityType(String nm, String clr) {
this.name = nm;
this.color = clr;
}
public String getName() {
return name;
}
public String getColor() {
return color;
}
public static RouteActivityType getTypeFromTags(String[] tags) {
RouteActivityType activityType = null;
for (String tg : tags) {
RouteActivityType rat = RouteActivityType.convertFromOsmGPXTag(tg);
if (rat != null) {
if (activityType == null || activityType.ordinal() > rat.ordinal()) {
activityType = rat;
}
}
}
return activityType;
}
public static RouteActivityType convertFromOsmGPXTag(String tg) {
String t = tg.toLowerCase();
if ("mountain hiking".equalsIgnoreCase(t)) {
return HIKING;
}
if ("motorcar".equalsIgnoreCase(t)) {
return CAR;
}
if ("laufen".equalsIgnoreCase(t)) {
return RUNNING;
}
if ("pedestrian".equalsIgnoreCase(t)) {
return WALKING;
}
switch (t) {
case "mountainbiking":
case "mtb":
case "mountainbike":
case "mountain bike":
case "mountain biking":
case "mountbarker":
case "mtb-tour":
case "ciclismo-mtb-gravel":
case "vtt":
case "btt":
case "vth":
case "mtb ride":
return MOUNTAINBIKE;
case "hiking":
case "route=hiking":
case "mountain hiking":
case "hiking trail":
case "wandern":
case "hike":
case "randonnée":
case "trekking":
case "climbing":
return HIKING;
case "bike":
case "biking":
case "bicycling":
case "bicycle":
case "cycling":
case "cycle":
case "cycleway":
case "cykel":
case "handcycle":
case "cyclotourisme":
case "route=bicycle":
case "cyclotourism":
case "fietsen":
case "вело":
case "велосипед":
case "rower":
case "trasa rowerem":
case "vélo":
case "velo":
case "radtour":
case "bici":
case "fiets":
case "fahrrad":
case "ncn":
case "icn":
case "lcn":
case "network=ncn":
case "network=icn":
case "network=lcn":
return CYCLING;
case "car":
case "motorcar":
case "by car":
case "auto":
case "автомобиль":
case "automobile":
case "autós":
case "driving":
case "drive":
case "van":
case "авто":
case "на автомобиле":
case "bus":
case "truck":
case "taxi":
return CAR;
case "running":
case "run":
case "rungis":
case "trail running":
case "trailrunning":
case "бег":
case "laufen":
case "langlauf":
case "lauf":
case "course":
case "jogging":
case "fitotrack":
return RUNNING;
case "wanderung":
case "walking":
case "walk":
case "nightwalk":
case "walkway":
case "пешком":
case "пеший":
case "pěšky":
case "marche":
case "pedestrian":
case "foot":
case "footing":
case "on_foot":
case "byfoot":
case "onfoot":
case "sightseeing":
case "geocaching":
case "etnanatura":
case "etna":
case "iwn":
case "lwn":
case "rwn":
case "network=iwn":
case "network=lwn":
case "network=rwn":
return WALKING;
case "ling-moto":
case "motorbiking":
case "motorcycle":
case "motorrad":
case "motorbike":
case "motor bike":
case "FVbike":
case "Motorrad":
return MOTORBIKE;
case "offroad":
case "off-road":
case "off road":
case "4x4":
case "terrain":
case "quad":
case "enduro":
case "feldwege":
case "feldweg":
return OFFROAD;
case "boat":
case "water":
case "boating":
case "kayak":
case "river":
case "lake":
case "lakes":
case "canal":
return WATER;
case "ski":
case "skiing":
case "skating":
case "skitour":
case "winter":
case "wintersports":
case "snowboard":
case "лыжи":
case "лыжня":
case "nordic":
case "piste":
return WINTER;
case "snowmobile=designated":
case "snowmobile=permissive":
case "snowmobile=yes":
case "snowmobile":
return SNOWMOBILE;
case "ride":
case "horse":
case "horse trail":
return RIDING;
case "racing":
return RACING;
}
return null;
}
}

View file

@ -94,6 +94,10 @@ public class OsmOAuthAuthorizationClient {
return accessToken;
}
public OAuth1RequestToken getRequestToken() {
return requestToken;
}
public Response performRequestWithoutAuth(String url, String requestMethod, String requestBody)
throws InterruptedException, ExecutionException, IOException {
Verb verb = parseRequestMethod(requestMethod);

View file

@ -367,8 +367,9 @@ public class RouteStatisticsHelper {
RouteDataObject obj = segment.obj;
for (int type : obj.getTypes()) {
BinaryMapRouteReaderAdapter.RouteTypeRule tp = obj.region.quickGetEncodingRule(type);
if (tp.getTag().equals("highway") || tp.getTag().equals("route") ||
tp.getTag().equals("railway") || tp.getTag().equals("aeroway") || tp.getTag().equals("aerialway")) {
if (tp.getTag().equals("highway") || tp.getTag().equals("route")
|| tp.getTag().equals("railway") || tp.getTag().equals("aeroway")
|| tp.getTag().equals("aerialway") || tp.getTag().equals("piste:type")) {
if (!mainTagAdded) {
req.setStringFilter(rrs.PROPS.R_TAG, tp.getTag());
req.setStringFilter(rrs.PROPS.R_VALUE, tp.getValue());

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -8,7 +8,7 @@
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/tab_title"
android:id="@+id/center_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"

View file

@ -3,12 +3,12 @@
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/custom_radio_buttons"
android:layout_width="match_parent"
android:minHeight="@dimen/dialog_button_height"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/content_padding"
android:layout_marginEnd="@dimen/content_padding"
android:background="?attr/btn_bg_border_inactive"
android:baselineAligned="false"
android:minHeight="@dimen/dialog_button_height"
android:orientation="horizontal"
tools:showIn="@layout/fragment_route_between_points_bottom_sheet_dialog">
@ -22,7 +22,8 @@
layout="@layout/center_button_container"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
android:layout_weight="1"
android:visibility="gone" />
<include
layout="@layout/right_button_container"

View file

@ -9,7 +9,8 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="@dimen/card_row_min_height">
android:layout_height="wrap_content"
android:minHeight="@dimen/card_row_min_height">
<androidx.appcompat.widget.AppCompatImageView
android:id="@android:id/icon"
@ -31,11 +32,15 @@
android:layout_gravity="center_vertical"
android:layout_weight="1"
android:paddingLeft="@dimen/content_padding"
android:paddingStart="@dimen/content_padding"
android:paddingRight="0dp"
android:paddingEnd="0dp"
android:paddingTop="@dimen/content_padding_half"
android:paddingBottom="@dimen/content_padding_half"
android:textColor="?android:textColorPrimary"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_regular"
tools:text="Internal application memory"
android:paddingStart="@dimen/content_padding" />
tools:text="Internal application memory" />
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/memory"

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

@ -8,7 +8,7 @@
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/tab_title"
android:id="@+id/left_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"

View file

@ -61,6 +61,13 @@
android:layout_gravity="center_vertical"
android:text="@string/amenity_type_finance"/>
<LinearLayout
android:id="@+id/context_menu_custom_address_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>

View file

@ -8,7 +8,7 @@
android:layout_weight="1">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/tab_title"
android:id="@+id/right_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?attr/selectableItemBackground"

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

@ -4069,4 +4069,9 @@
<string name="delete_waypoints">حذف نقاط الطريق</string>
<string name="copy_to_map_markers">نسخ لعلامات الخريطة</string>
<string name="copy_to_map_favorites">نسخ للمفضلة</string>
<string name="upload_photo">يتم الرفع</string>
<string name="upload_photo_completed">اكتمال الرفع</string>
<string name="uploading_count">رفع %1$d من %2$d</string>
<string name="uploaded_count">تم رفع %1$d من %2$d</string>
<string name="toast_select_edits_for_upload">تحديد التعديلات للتحميل</string>
</resources>

View file

@ -4008,4 +4008,9 @@
<string name="delete_waypoints">Wegpunkte löschen</string>
<string name="copy_to_map_favorites">In Favoriten kopieren</string>
<string name="copy_to_map_markers">In Kartenmarkierungen kopieren</string>
</resources>
<string name="upload_photo">Lade hoch</string>
<string name="upload_photo_completed">Hochladen abgeschlossen</string>
<string name="uploading_count">Lade %1$d von %2$d hoch</string>
<string name="uploaded_count">%1$d von %2$d hochgeladen</string>
<string name="toast_select_edits_for_upload">Bearbeitungen zum Hochladen auswählen</string>
</resources>

View file

@ -3948,4 +3948,9 @@
<string name="shared_string_last_used">Viimati kasutatud</string>
<string name="message_server_error">Serveri viga: %1$s</string>
<string name="message_name_is_already_exists">Selline nimi on juba olemas</string>
<string name="toast_select_edits_for_upload">Vali tehtud muudatused üleslaadimiseks</string>
<string name="uploaded_count">Üleslaaditud %1$d/%2$d</string>
<string name="uploading_count">Laadin üles muudatusi %1$d/%2$d</string>
<string name="upload_photo_completed">Sai üleslaaditud</string>
<string name="upload_photo">Laadin üles</string>
</resources>

View file

@ -2739,4 +2739,15 @@ Jos pidät OsmAndista ja OSMsta ja haluat tukea niitä, on tämä täydellinen t
<string name="routing_engine_vehicle_type_foot">Kävely</string>
<string name="routing_engine_vehicle_type_bike">Polkupyörä</string>
<string name="routing_engine_vehicle_type_car">Auto</string>
<string name="message_server_error">Palvelimen virhe: %1$s</string>
<string name="message_name_is_already_exists">Nimi on jo käytössä</string>
<string name="context_menu_read_full">Lue kaikki</string>
<string name="context_menu_edit_descr">Muokkaa kuvausta</string>
<string name="copy_to_map_markers">Kopioi karttamerkkeihin</string>
<string name="copy_to_map_favorites">Kopioi suosikkeihin</string>
<string name="upload_photo">Lähetetään</string>
<string name="upload_photo_completed">Lähetys valmis</string>
<string name="uploading_count">Lähetetty %1$d muutosta %2$d muutoksesta</string>
<string name="uploaded_count">Lähetettiin %1$d muutosta %2$d muutoksesta</string>
<string name="toast_select_edits_for_upload">Valitse lähetettävät muutokset</string>
</resources>

View file

@ -708,7 +708,7 @@
<string name="poi_recycling_cars">Autó</string>
<string name="poi_recycling_bicycles">Kerékpár</string>
<string name="poi_landfill_waste_nuclear">Radioaktívhulladék-lerakó</string>
<string name="poi_basin">Vízgyűjtő</string>
<string name="poi_basin">Vízgyűjtő medence</string>
<string name="poi_monitoring_station">Megfigyelőállomás</string>
<string name="poi_crane">Daru</string>
<string name="poi_construction">Építkezés</string>
@ -2633,7 +2633,7 @@
<string name="poi_lottery">Lottózó</string>
<string name="poi_gambling">Szerencsejáték-helyszín</string>
<string name="poi_gambling_type">Típus</string>
<string name="poi_gambling_lottery">Lottó</string>
<string name="poi_gambling_lottery">Lottó</string>
<string name="poi_gambling_slot_machines">Játékgépek</string>
<string name="poi_gambling_betting">Fogadás</string>
<string name="poi_e_cigarette">E-cigaretta-bolt</string>
@ -3446,7 +3446,7 @@
<string name="poi_service_vehicle_motor_yes">Motorszerelés</string>
<string name="poi_service_vehicle_insurance_yes">Biztosítás</string>
<string name="poi_service_vehicle_tyres_yes">Gumiszerelés</string>
<string name="poi_aerialway_zip_line">Kötélpálya</string>
<string name="poi_aerialway_zip_line">Csúszópálya</string>
<string name="poi_climbing_adventure">Kalandpark</string>
<string name="poi_via_ferrata">Via ferrata (vasalt út)</string>
<string name="poi_cable_number">Sodronyok száma</string>
@ -3524,7 +3524,7 @@
<string name="poi_books_academic">akadémiai</string>
<string name="poi_books_children">gyermekkönyv</string>
<string name="poi_atoll">Atoll</string>
<string name="poi_toll_gantry">Útdíjellenőrző kapu</string>
<string name="poi_toll_gantry">Automatikus útdíjbeszedő kapu</string>
<string name="poi_childcare">Gyermekgondozás (bölcsőde)</string>
<string name="poi_denotation_natural_monument">Természeti emlék</string>
<string name="poi_denotation_landmark">Tájékozódási pont</string>

View file

@ -931,7 +931,7 @@
<string name="files_limit">%1$d resterende bestanden</string>
<string name="available_downloads_left">%1$d resterende bestanden nog te downloaden</string>
<string name="install_paid">Volledige versie</string>
<string name="cancel_route">Annuleer route</string>
<string name="cancel_route">Annuleer route \?</string>
<string name="cancel_navigation">Stop navigatie</string>
<string name="clear_destination">Bestemming wissen</string>
<string name="use_magnetic_sensor_descr">Gebruik magnetische sensor in plaats van oriëntatiesensor voor het kompas.</string>
@ -3726,31 +3726,31 @@
<string name="plan_a_route">Plan een route</string>
<string name="use_two_phase_routing">Gebruik de twee-fase A* route berekening methode</string>
<string name="shared_string_graph">Grafiek</string>
<string name="message_graph_will_be_available_after_recalculation">Wacht op de herberekening van de route.
\nDe grafiek is beschikbaar na herberekening.</string>
<string name="message_graph_will_be_available_after_recalculation">Wacht totdat route herberekend is.
\nNa herberekening is de grafiek zichtbaar.</string>
<string name="ltr_or_rtl_combine_via_dash">%1$s — %2$s</string>
<string name="import_track_descr">Kies een trackbestand om te volgen of importeer het, vanaf uw apparaat.</string>
<string name="app_mode_gap">Onderbreking</string>
<string name="shared_string_custom">Aangepast</string>
<string name="perform_oauth_authorization_description">Voer een OAuth-login uit om osm edit functies te gebruiken</string>
<string name="release_3_5">"• Bijgewerkte app- en profielinstellingen: instellingen zijn nu gerangschikt op type. Elk profiel kan afzonderlijk worden aangepast.
<string name="release_3_5">• Bijgewerkte app- en profielinstellingen: instellingen zijn nu gerangschikt op type. Elk profiel kan afzonderlijk worden aangepast.
\n
\n • Nieuw dialoogvenster voor het downloaden van kaarten waarin wordt voorgesteld een kaart te downloaden tijdens het browsen
\n • Nieuw dialoogvenster voor het downloaden van kaarten waarin wordt voorgesteld een kaart te downloaden tijdens het browsen
\n
\n • Donkere thema-fixes
\n • Donkere thema-fixes
\n
\n • Verschillende routeringsproblemen over de hele wereld opgelost
\n • Verschillende routeringsproblemen over de hele wereld opgelost
\n
\n • Bijgewerkte basiskaart met meer gedetailleerd wegennet
\n • Bijgewerkte basiskaart met meer gedetailleerd wegennet
\n
\n • Vaste overstroomde gebieden over de hele wereld
\n • Vaste overstroomde gebieden over de hele wereld
\n
\n • Skirouting: hoogteprofiel en routecomplexiteit toegevoegd aan de routedetails
\n • Skirouting: hoogteprofiel en routecomplexiteit toegevoegd aan de routedetails
\n
\n • Andere bugs opgelost
\n • Andere bugs opgelost
\n
\n"</string>
<string name="release_3_6">"• Profielen: nu kunt u de volgorde wijzigen, het pictogram voor de kaart instellen, alle instellingen voor basisprofielen wijzigen en ze terugzetten naar de standaardinstellingen
\n</string>
<string name="release_3_6">• Profielen: nu kunt u de volgorde wijzigen, het pictogram voor de kaart instellen, alle instellingen voor basisprofielen wijzigen en ze terugzetten naar de standaardinstellingen
\n
\n • Exitnummer toegevoegd in de navigatie
\n
@ -3758,23 +3758,23 @@
\n
\n • Herwerkt instellingenscherm voor snelle toegang tot alle profielen
\n
\n • Optie toegevoegd om instellingen van een ander profiel te kopiëren
\n • Optie toegevoegd om instellingen van een ander profiel te kopiëren
\n
\n • Mogelijkheid toegevoegd om een volgorde te wijzigen of POI-categorieën in Zoeken te verbergen
\n • Mogelijkheid toegevoegd om een volgorde te wijzigen of POI-categorieën in Zoeken te verbergen
\n
\n • Correct uitgelijnde POI-pictogrammen op de kaart
\n • Correct uitgelijnde POI-pictogrammen op de kaart
\n
\n • Zonsondergang / zonsopganggegevens toegevoegd om de kaart te configureren
\n • Zonsondergang / zonsopganggegevens toegevoegd om de kaart te configureren
\n
\n • Thuis/werk-pictogrammen toegevoegd op de kaart
\n • Thuis/werk-pictogrammen toegevoegd op de kaart
\n
\n • Ondersteuning toegevoegd voor meerdere regels beschrijving bij Instellingen
\n • Ondersteuning toegevoegd voor meerdere regels beschrijving bij Instellingen
\n
\n • Correcte transliteratie toegevoegd aan de kaart van Japan
\n
\n • Antarctica-kaart toegevoegd
\n • Antarctica-kaart toegevoegd
\n
\n"</string>
\n</string>
<string name="what_is_new">Wat is er nieuw</string>
<string name="snowmobile_render_descr">Voor sneeuwscooter, rijden met speciale wegen en tracks.</string>
<string name="set_working_days_to_continue">Stel aantal werkdagen in om door te gaan</string>
@ -3837,7 +3837,7 @@
<string name="osm_edit_logout_success">Uitloggen gelukt</string>
<string name="file_already_imported">Bestand is reeds geïmporteerd in OsmAnd</string>
<string name="shared_string_local_maps">Lokale kaarten</string>
<string name="icon_group_amenity">Aangenaam</string>
<string name="icon_group_amenity">Voorziening</string>
<string name="icon_group_special">Speciaal</string>
<string name="icon_group_transport">Transport</string>
<string name="icon_group_service">Onderhoud</string>
@ -3856,7 +3856,7 @@
<string name="open_street_map_login_mode">U moet inloggen om wijzigingen te uploaden.
\n
\nU kunt inloggen met de veilige OAuth-methode of uw loginnaam en wachtwoord gebruiken.</string>
<string name="use_login_password">Inloggen met gebruikersnaam en wachtwoord.</string>
<string name="use_login_password">Inloggen met gebruikersnaam en wachtwoord</string>
<string name="login_account">Account</string>
<string name="user_login">Gebruikersnaam</string>
<string name="manage_subscription">Abonnement beheren</string>
@ -3993,4 +3993,9 @@
<string name="delete_waypoints">Waypoints verwijderen</string>
<string name="copy_to_map_markers">Kopiëren naar Markeervlaggetjes</string>
<string name="copy_to_map_favorites">Kopiëren naar Favorieten</string>
<string name="upload_photo">Opladen</string>
<string name="upload_photo_completed">Opladen voltooid</string>
<string name="uploading_count">Aan het opladen %1$d van %2$d</string>
<string name="uploaded_count">Opgeladen %1$d van %2$d</string>
<string name="toast_select_edits_for_upload">Selecteer de op te laden wijzigingen</string>
</resources>

View file

@ -3986,4 +3986,10 @@
<string name="context_menu_read_full">Читать полностью</string>
<string name="context_menu_edit_descr">Редактировать описание</string>
<string name="delete_waypoints">Удалить путевые точки</string>
<string name="routing_engine_vehicle_type_hgv">HGV</string>
<string name="upload_photo">Отправка</string>
<string name="upload_photo_completed">Отправка завершена</string>
<string name="uploading_count">Отправка %1$d из %2$d</string>
<string name="uploaded_count">Отправлено %1$d из %2$d</string>
<string name="toast_select_edits_for_upload">Выберите правки для отправки</string>
</resources>

View file

@ -3275,14 +3275,14 @@
<string name="select_folder">Izberi mapo</string>
<string name="select_folder_descr">Izberi mapo ali dodaj novo</string>
<string name="shared_string_empty">Prazno</string>
<string name="analyze_by_intervals">Analiziraj po intervalih (razdelitveni interval)</string>
<string name="analyze_by_intervals">Preuči po intervalih (razdelitveni interval)</string>
<string name="upload_to_openstreetmap">Naloži v OpenStreetMap</string>
<string name="edit_track">Uredi sled</string>
<string name="rename_track">Preimenuj sled</string>
<string name="change_folder">Spremeni mapo</string>
<string name="shared_string_sec">sek</string>
<string name="announcement_time_approach">Pristop</string>
<string name="announcement_time_prepare">Pripravi se</string>
<string name="announcement_time_prepare">Pripravljanje</string>
<string name="announcement_time_off_route">Izven poti</string>
<string name="announcement_time_arrive">Prihod na cilj</string>
<string name="shared_string_turn">Zavoj</string>
@ -3296,7 +3296,7 @@
<string name="routing_engine_vehicle_type_cycling_electric">Električno kolesarjenje</string>
<string name="routing_engine_vehicle_type_cycling_mountain">Gorsko kolesarjenje</string>
<string name="routing_engine_vehicle_type_cycling_road">Cestno kolesarjenje</string>
<string name="routing_engine_vehicle_type_cycling_regular">Redno kolesarjenje</string>
<string name="routing_engine_vehicle_type_cycling_regular">Mestno kolesarjenje</string>
<string name="routing_engine_vehicle_type_hgv">Težko tovorno vozilo</string>
<string name="routing_engine_vehicle_type_small_truck">Majhno tovorno vozilo</string>
<string name="routing_engine_vehicle_type_truck">Tovorno vozilo</string>
@ -3309,4 +3309,51 @@
<string name="context_menu_edit_descr">Uredi opis</string>
<string name="delete_waypoints">Brisanje točk</string>
<string name="copy_to_map_markers">Kopiraj na oznake na zemljevidu</string>
<string name="export_not_enough_space">Na napravi ni dovolj prostora.</string>
<string name="select_groups_for_import">Izbor skupin za uvoz.</string>
<string name="select_items_for_import">Izbor predmetov za uvoz.</string>
<string name="add_to_mapillary">Dodaj na Mapillary</string>
<string name="add_to_opr">Dodaj na OpenPlaceReviews</string>
<string name="use_dev_url_descr">Za preizkušanje pošiljanja sporočil, točk in sledi GPX preklopi iz openstreetmap.org na preizkusni dev.openstreetmap.org.</string>
<string name="use_dev_url">Uporabi dev.openstreetmap.org</string>
<string name="add_photos_descr">Program podpira prikaz fotografij različnih virov:
\nOpenPlaceReviews fotografije točk POI;
\nMapillary ulična fotografija;
\nSplet / Wikimedia fotografije točk POI in OpenStreetMap.</string>
<string name="ltr_or_rtl_combine_via_star">%1$s * %2$s</string>
<string name="plan_route_add_new_segment">Dodaj nov del poti</string>
<string name="app_mode_light_aircraft">Lahko letalo</string>
<string name="plan_route_join_segments">Združi dele poti</string>
<string name="plan_route_split_before">Razdeli pred</string>
<string name="plan_route_split_after">Razdeli po</string>
<string name="profile_type_osmand_string">Profil OsmAnd</string>
<string name="profile_type_user_string">Uporabniški profil</string>
<string name="reverse_all_points">Obrni vse točke</string>
<string name="profile_by_default_description">Izbor profila, ki bo prikazan ob zagonu programa.</string>
<string name="shared_string_last_used">Nazadnje uporabljeno</string>
<string name="shared_string_subtype">Podvrsta</string>
<string name="shared_string_vehicle">Vozilo</string>
<string name="shared_string_api_key">Ključ API</string>
<string name="shared_string_server_url">Naslov URL strežnika</string>
<string name="shared_string_enter_param">Vpis parametrov</string>
<string name="online_routing_example_hint">Naslov URL z vsemi parametri bo zapisan kot:</string>
<string name="test_route_calculation">Preizkusi izračun poti</string>
<string name="routing_engine_vehicle_type_driving">Vožnja</string>
<string name="routing_engine_vehicle_type_foot">Hoja</string>
<string name="routing_engine_vehicle_type_bike">Kolo</string>
<string name="routing_engine_vehicle_type_car">Avto</string>
<string name="copy_address">Kopiraj naslov</string>
<string name="announcement_time_prepare_long">Dolgo pripravljanje</string>
<string name="show_track_on_map">Pokaži sled na zemljevidu</string>
<string name="shared_string_zoom_levels">Raven približanja</string>
<string name="shared_string_transparency">Prosojnost</string>
<string name="shared_string_legend">Legenda</string>
<string name="terrain_empty_state_text">Prikaz višinskega senčenja na zemljevidu. Več o tem je mogoče prebrati na spletni strani programa.</string>
<string name="shared_string_hillshade">Senčenje</string>
<string name="copy_to_map_favorites">Kopiraj med priljubljene</string>
<string name="upload_photo">Poteka pošiljanje</string>
<string name="upload_photo_completed">Pošiljanje je končano</string>
<string name="uploading_count">Poteka pošiljanje %1$d od %2$d</string>
<string name="uploaded_count">Poslano %1$d od %2$d</string>
<string name="toast_select_edits_for_upload">Izbor sprememb za pošiljanje</string>
</resources>

View file

@ -1219,7 +1219,7 @@
<string name="display_zoom_level">显示缩放等级:%1$s</string>
<string name="online_map">在线地图</string>
<string name="roads_only">仅道路</string>
<string name="device_memory">设备</string>
<string name="device_memory">设备</string>
<string name="first_usage_item">初次使用</string>
<string name="tips_and_tricks_descr">常见问题、最近修改和其它内容。</string>
<string name="faq_item_description">常见问题</string>

View file

@ -12,6 +12,11 @@
-->
<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>
<string name="uploading_count">Uploading %1$d of %2$d</string>

View file

@ -14,10 +14,10 @@
android:title="@string/shared_string_maps"/>
<Preference
android:key="contour_lines_and_hillshade_memory"
android:key="terrain_memory_used"
android:layout="@layout/data_storage_memory_used_item"
android:icon="@drawable/ic_map"
android:title="@string/contour_lines_and_hillshade"/>
android:title="@string/hillshade_slope_contour_lines"/>
<Preference
android:key="tracks_memory_used"

View file

@ -22,7 +22,7 @@
android:layout="@layout/preference_with_descr"
android:persistent="false"
android:title="@string/application_dir"
app:fragment="net.osmand.plus.settings.fragments.DataStorageFragment"
app:fragment="net.osmand.plus.settings.datastorage.DataStorageFragment"
tools:icon="@drawable/ic_action_folder" />
<Preference

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

@ -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

@ -344,8 +344,8 @@ public class OsmAndFormatter {
if (minperkm >= 10) {
return ((int) Math.round(minperkm)) + " " + mc.toShortString(ctx);
} else {
int mph10 = (int) Math.round(minperkm * 10f);
return (mph10 / 10f) + " " + mc.toShortString(ctx);
int seconds = Math.round(minperkm * 60);
return Algorithms.formatDuration(seconds, false) + " " + mc.toShortString(ctx);
}
} else if (mc == SpeedConstants.MINUTES_PER_MILE) {
if (metersperseconds < 0.111111111) {

View file

@ -24,6 +24,8 @@ import android.view.View;
import android.view.accessibility.AccessibilityManager;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatDelegate;
import androidx.multidex.MultiDex;
@ -68,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;
@ -159,6 +162,7 @@ public class OsmandApplication extends MultiDexApplication {
GpxDbHelper gpxDbHelper;
QuickActionRegistry quickActionRegistry;
OsmOAuthHelper osmOAuthHelper;
OprAuthHelper oprAuthHelper;
MeasurementEditingContext measurementEditingContext;
OnlineRoutingHelper onlineRoutingHelper;
@ -394,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);
@ -910,6 +918,7 @@ public class OsmandApplication extends MultiDexApplication {
return customRoutingConfigs.get(key);
}
@NonNull
public RoutingConfiguration.Builder getRoutingConfigForMode(ApplicationMode mode) {
RoutingConfiguration.Builder builder = null;
String routingProfileKey = mode.getRoutingProfile();
@ -923,11 +932,13 @@ public class OsmandApplication extends MultiDexApplication {
return builder != null ? builder : getDefaultRoutingConfig();
}
@Nullable
public GeneralRouter getRouter(ApplicationMode mode) {
Builder builder = getRoutingConfigForMode(mode);
return getRouter(builder, mode);
}
@Nullable
public GeneralRouter getRouter(Builder builder, ApplicationMode am) {
GeneralRouter router = builder.getRouter(am.getRoutingProfile());
if (router == null && am.getParent() != null) {

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

@ -51,6 +51,7 @@ import net.osmand.AndroidUtils;
import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.data.LatLon;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.views.DirectionDrawable;
import net.osmand.plus.widgets.TextViewEx;
@ -468,8 +469,8 @@ public class UiUtilities {
} else {
background.setCornerRadii(new float[]{radius, radius, 0, 0, 0, 0, radius, radius});
}
TextView startButtonText = startButtonContainer.findViewById(R.id.tab_title);
TextView endButtonText = endButtonContainer.findViewById(R.id.tab_title);
TextView startButtonText = startButtonContainer.findViewById(R.id.left_button);
TextView endButtonText = endButtonContainer.findViewById(R.id.right_button);
endButtonContainer.setBackgroundColor(Color.TRANSPARENT);
endButtonText.setTextColor(activeColor);
@ -477,23 +478,25 @@ public class UiUtilities {
startButtonText.setTextColor(textColor);
if (centerButtonContainer != null) {
TextView centerButtonText = centerButtonContainer.findViewById(R.id.tab_title);
TextView centerButtonText = centerButtonContainer.findViewById(R.id.center_button);
centerButtonText.setTextColor(activeColor);
centerButtonContainer.setBackgroundColor(Color.TRANSPARENT);
}
} else if (buttonType == CustomRadioButtonType.CENTER) {
background.setCornerRadii(new float[] {0, 0, 0, 0, 0, 0, 0, 0});
centerButtonContainer.setBackgroundDrawable(background);
TextView centerButtonText = centerButtonContainer.findViewById(R.id.tab_title);
AndroidUiHelper.updateVisibility(centerButtonContainer, true);
TextView centerButtonText = centerButtonContainer.findViewById(R.id.center_button);
centerButtonText.setTextColor(textColor);
if (endButtonContainer != null) {
TextView endButtonText = endButtonContainer.findViewById(R.id.tab_title);
TextView endButtonText = endButtonContainer.findViewById(R.id.right_button);
endButtonText.setTextColor(activeColor);
endButtonContainer.setBackgroundColor(Color.TRANSPARENT);
}
if (startButtonContainer != null) {
TextView startButtonText = startButtonContainer.findViewById(R.id.tab_title);
TextView startButtonText = startButtonContainer.findViewById(R.id.left_button);
startButtonText.setTextColor(activeColor);
startButtonContainer.setBackgroundColor(Color.TRANSPARENT);
}
@ -503,8 +506,8 @@ public class UiUtilities {
} else {
background.setCornerRadii(new float[]{0, 0, radius, radius, radius, radius, 0, 0});
}
TextView startButtonText = startButtonContainer.findViewById(R.id.tab_title);
TextView endButtonText = endButtonContainer.findViewById(R.id.tab_title);
TextView startButtonText = startButtonContainer.findViewById(R.id.left_button);
TextView endButtonText = endButtonContainer.findViewById(R.id.right_button);
endButtonContainer.setBackgroundDrawable(background);
endButtonText.setTextColor(textColor);
@ -512,7 +515,7 @@ public class UiUtilities {
startButtonText.setTextColor(activeColor);
if (centerButtonContainer != null) {
TextView centerButtonText = centerButtonContainer.findViewById(R.id.tab_title);
TextView centerButtonText = centerButtonContainer.findViewById(R.id.center_button);
centerButtonText.setTextColor(activeColor);
centerButtonContainer.setBackgroundColor(Color.TRANSPARENT);
}

View file

@ -10,6 +10,7 @@ import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.text.Html;
import android.text.Spanned;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
@ -88,6 +89,8 @@ public class FavoritesTreeFragment extends OsmandExpandableListFragment implemen
public static final int IMPORT_FAVOURITES_ID = 7;
public static final String GROUP_EXPANDED_POSTFIX = "_group_expanded";
private static final int MAX_POINTS_IN_DESCRIPTION = 100;
private FavouritesAdapter favouritesAdapter;
private FavouritesDbHelper helper;
@ -606,29 +609,39 @@ public class FavoritesTreeFragment extends OsmandExpandableListFragment implemen
}
}
private StringBuilder generateHtmlPrint(List<FavoriteGroup> groups) {
private String generateHtmlPrint(List<FavoriteGroup> groups) {
StringBuilder html = new StringBuilder();
html.append("<h1>My Favorites</h1>");
int addedPoints = 0;
for (FavoriteGroup group : groups) {
html.append("<h3>" + group.getDisplayName(app) + "</h3>");
html.append("<h3>").append(group.getDisplayName(app)).append("</h3>");
for (FavouritePoint fp : group.getPoints()) {
String url = "geo:" + ((float) fp.getLatitude()) + "," + ((float) fp.getLongitude()) + "?m=" + fp.getName();
html.append("<p>" + fp.getDisplayName(app) + " - " + "<a href=\"" + url + "\">geo:"
+ ((float) fp.getLatitude()) + "," + ((float) fp.getLongitude()) + "</a><br>");
if (fp.isAddressSpecified()) {
html.append(": " + fp.getAddress());
html.append("<br>");
if (addedPoints >= MAX_POINTS_IN_DESCRIPTION) {
break;
}
if (!Algorithms.isEmpty(fp.getDescription())) {
html.append(": " + fp.getDescription());
}
html.append("</p>");
float lat = (float) fp.getLatitude();
float lon = (float) fp.getLongitude();
String url = "geo:" + lat + "," + lon + "?m=" + fp.getName();
html.append("<p>")
.append(fp.getDisplayName(app))
.append(" - <a href=\"")
.append(url)
.append("\">geo:")
.append(lat).append(",").append(lon)
.append("</a><br></p>");
addedPoints++;
}
if (addedPoints >= MAX_POINTS_IN_DESCRIPTION) {
html.append("<p>...</p>");
break;
}
}
return html;
return html.toString();
}
private void shareFavourites() {
if (favouritesAdapter.isEmpty()) {
Toast.makeText(getActivity(), R.string.no_fav_to_save, Toast.LENGTH_LONG).show();
@ -646,6 +659,7 @@ public class FavoritesTreeFragment extends OsmandExpandableListFragment implemen
File src = null;
File dst = null;
Spanned descriptionOfPoints;
@Override
protected void onPreExecute() {
@ -662,9 +676,15 @@ public class FavoritesTreeFragment extends OsmandExpandableListFragment implemen
@Override
protected Void doInBackground(Void... params) {
List<FavoriteGroup> groups;
if (group != null) {
helper.saveFile(group.getPoints(), dst);
groups = new ArrayList<>();
groups.add(group);
} else {
groups = getMyApplication().getFavorites().getFavoriteGroups();
}
descriptionOfPoints = Html.fromHtml(generateHtmlPrint(groups));
return null;
}
@ -680,19 +700,12 @@ public class FavoritesTreeFragment extends OsmandExpandableListFragment implemen
Algorithms.fileCopy(src, dst);
}
final Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
List<FavoriteGroup> groups;
if (group != null) {
groups = new ArrayList<>();
groups.add(group);
} else {
groups = getMyApplication().getFavorites().getFavoriteGroups();
}
sendIntent.putExtra(Intent.EXTRA_TEXT, Html.fromHtml(generateHtmlPrint(groups).toString()));
sendIntent.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_fav_subject));
sendIntent.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), dst));
sendIntent.setType("text/plain");
sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
sendIntent.setAction(Intent.ACTION_SEND)
.putExtra(Intent.EXTRA_SUBJECT, getString(R.string.share_fav_subject))
.putExtra(Intent.EXTRA_TEXT, descriptionOfPoints)
.putExtra(Intent.EXTRA_STREAM, AndroidUtils.getUriForFile(getMyApplication(), dst))
.setType("text/plain")
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(sendIntent);
} catch (IOException e) {
Toast.makeText(getActivity(), "Error sharing favorites: " + e.getMessage(), Toast.LENGTH_SHORT).show();

View file

@ -139,7 +139,7 @@ import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.fragments.BaseSettingsFragment.SettingsScreenType;
import net.osmand.plus.settings.fragments.ConfigureProfileFragment;
import net.osmand.plus.settings.fragments.DataStorageFragment;
import net.osmand.plus.settings.datastorage.DataStorageFragment;
import net.osmand.plus.track.TrackAppearanceFragment;
import net.osmand.plus.track.TrackMenuFragment;
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;

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;
@ -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

@ -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

@ -58,6 +58,7 @@ import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.LockableScrollView;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.settings.backend.MainContextMenuItemsSettings;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
@ -1674,6 +1675,12 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
line2MeasuredHeight = line2.getMeasuredHeight();
}
int customAddressLineHeight = 0;
View customAddressLine = view.findViewById(R.id.context_menu_custom_address_line);
if (customAddressLine.getVisibility() == View.VISIBLE) {
customAddressLineHeight = customAddressLine.getMeasuredHeight();
}
int line3Height = 0;
View line3Container = view.findViewById(R.id.additional_info_row_container);
if (line3Container.getVisibility() == View.VISIBLE) {
@ -1717,12 +1724,12 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
titleHeight = line1.getMeasuredHeight() + line2MeasuredHeight;
}
newMenuTopViewHeight = menuTopViewHeightExcludingTitle + titleHeight
+ titleButtonHeight + downloadButtonsHeight
+ titleButtonHeight + customAddressLineHeight + downloadButtonsHeight
+ titleBottomButtonHeight + additionalButtonsHeight + titleProgressHeight + line3Height;
dy = Math.max(0, newMenuTopViewHeight - menuTopViewHeight
- (newMenuTopShadowAllHeight - menuTopShadowAllHeight));
} else {
menuTopViewHeightExcludingTitle = newMenuTopViewHeight - line1.getMeasuredHeight() - line2MeasuredHeight
menuTopViewHeightExcludingTitle = newMenuTopViewHeight - line1.getMeasuredHeight() - line2MeasuredHeight - customAddressLineHeight
- titleButtonHeight - downloadButtonsHeight - titleBottomButtonHeight - additionalButtonsHeight - titleProgressHeight - line3Height;
menuTitleTopBottomPadding = (line1.getMeasuredHeight() - line1.getLineCount() * line1.getLineHeight())
+ (line2MeasuredHeight - line2LineCount * line2LineHeight);
@ -1818,12 +1825,16 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
line1.setText(menu.getTitleStr());
toolbarTextView.setText(menu.getTitleStr());
// Text line 2
LinearLayout line2layout = view.findViewById(R.id.context_menu_line2_layout);
TextView line2 = view.findViewById(R.id.context_menu_line2);
LinearLayout customAddressLine = view.findViewById(R.id.context_menu_custom_address_line);
customAddressLine.removeAllViews();
if (menu.hasCustomAddressLine()) {
line2layout.removeAllViews();
menu.buildCustomAddressLine(line2layout);
menu.buildCustomAddressLine(customAddressLine);
AndroidUiHelper.updateVisibility(line2, false);
AndroidUiHelper.updateVisibility(customAddressLine, true);
} else {
AndroidUiHelper.updateVisibility(line2, true);
AndroidUiHelper.updateVisibility(customAddressLine, false);
String typeStr = menu.getTypeStr();
String streetStr = menu.getStreetStr();
StringBuilder line2Str = new StringBuilder();

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;
@ -75,6 +77,10 @@ import net.osmand.plus.widgets.tools.ClickableSpanTouchListener;
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 +93,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 +138,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 +163,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 +458,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 +493,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));
}
}
}));

View file

@ -13,14 +13,11 @@ 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,7 +33,6 @@ 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> {
@ -47,22 +43,17 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
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,8 +94,8 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
@Override
protected void onPostExecute(Void aVoid) {
if (listener != null) {
listener.uploadPhotosFinished();
if (progressListener != null) {
progressListener.uploadPhotosFinished();
}
}
@ -156,13 +147,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 {
@ -193,7 +180,9 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
private byte[] compressImageToJpeg(InputStream image) {
BufferedInputStream bufferedInputStream = new BufferedInputStream(image);
Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream);
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 4;
Bitmap bmp = BitmapFactory.decodeStream(bufferedInputStream, null, opts);
ByteArrayOutputStream os = new ByteArrayOutputStream();
int h = bmp.getHeight();
int w = bmp.getWidth();
@ -215,12 +204,17 @@ public class UploadPhotosAsyncTask extends AsyncTask<Void, Integer, Void> {
return os.toByteArray();
}
public interface UploadPhotosListener {
public interface UploadPhotosProgressListener {
void uploadPhotosProgressUpdate(int progress);
void uploadPhotosFinished();
}
public interface UploadPhotosListener {
void uploadPhotosSuccess(String response);
}
}

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

@ -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

@ -573,8 +573,12 @@ public class GPXItemPagerAdapter extends PagerAdapter implements CustomTabProvid
} else {
layoutId = tripleTabsLayoutIds[position];
}
View tab = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);
ViewGroup tab = (ViewGroup) UiUtilities.getInflater(parent.getContext(), nightMode).inflate(layoutId, parent, false);
tab.setTag(tabTypes[position].name());
TextView title = (TextView) tab.getChildAt(0);
if (title != null) {
title.setText(getPageTitle(position));
}
return tab;
}

View file

@ -9,6 +9,7 @@ import net.osmand.osm.io.NetworkUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.Version;
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine;
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.util.Algorithms;

View file

@ -1,24 +0,0 @@
package net.osmand.plus.onlinerouting;
import net.osmand.Location;
import net.osmand.plus.routing.RouteDirectionInfo;
import java.util.List;
public class OnlineRoutingResponse {
private List<Location> route;
private List<RouteDirectionInfo> directions;
public OnlineRoutingResponse(List<Location> route, List<RouteDirectionInfo> directions) {
this.route = route;
this.directions = directions;
}
public List<Location> getRoute() {
return route;
}
public List<RouteDirectionInfo> getDirections() {
return directions;
}
}

View file

@ -8,7 +8,6 @@ import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.onlinerouting.EngineParameter;
import net.osmand.plus.onlinerouting.OnlineRoutingResponse;
import net.osmand.plus.onlinerouting.VehicleType;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.router.TurnType;
@ -84,12 +83,9 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
@Nullable
@Override
public OnlineRoutingResponse parseServerResponse(@NonNull String content,
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
@NonNull OsmandApplication app,
boolean leftSideNavigation) throws JSONException {
JSONObject obj = new JSONObject(content);
JSONObject root = obj.getJSONArray("paths").getJSONObject(0);
String encoded = root.getString("points");
List<LatLon> points = GeoPolylineParserUtil.parse(encoded, GeoPolylineParserUtil.PRECISION_5);
if (isEmpty(points)) return null;
@ -216,14 +212,15 @@ public class GraphhopperEngine extends OnlineRoutingEngine {
return id != null ? TurnType.valueOf(id, leftSide) : null;
}
@NonNull
@Override
public boolean parseServerMessage(@NonNull StringBuilder sb,
@NonNull String content) throws JSONException {
JSONObject obj = new JSONObject(content);
if (obj.has("message")) {
String message = obj.getString("message");
sb.append(message);
}
return obj.has("paths");
protected String getErrorMessageKey() {
return "message";
}
@NonNull
@Override
protected String getRootArrayKey() {
return "paths";
}
}

View file

@ -12,12 +12,14 @@ import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.onlinerouting.EngineParameter;
import net.osmand.plus.onlinerouting.OnlineRoutingFactory;
import net.osmand.plus.onlinerouting.OnlineRoutingResponse;
import net.osmand.plus.onlinerouting.VehicleType;
import net.osmand.plus.routing.RouteDirectionInfo;
import net.osmand.plus.routing.RouteProvider;
import net.osmand.util.Algorithms;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
@ -98,10 +100,31 @@ public abstract class OnlineRoutingEngine implements Cloneable {
@NonNull
public abstract String getStandardUrl();
public OnlineRoutingResponse parseServerResponse(@NonNull String content,
@NonNull OsmandApplication app,
boolean leftSideNavigation) throws JSONException {
JSONObject root = parseRootResponseObject(content);
return root != null ? parseServerResponse(root, app, leftSideNavigation) : null;
}
@Nullable
public abstract OnlineRoutingResponse parseServerResponse(@NonNull String content,
@NonNull OsmandApplication app,
boolean leftSideNavigation) throws JSONException;
protected abstract OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
@NonNull OsmandApplication app,
boolean leftSideNavigation) throws JSONException;
@Nullable
protected JSONObject parseRootResponseObject(@NonNull String content) throws JSONException {
JSONObject fullJSON = new JSONObject(content);
String responseArrayKey = getRootArrayKey();
JSONArray array = null;
if (fullJSON.has(responseArrayKey)) {
array = fullJSON.getJSONArray(responseArrayKey);
}
return array != null && array.length() > 0 ? array.getJSONObject(0) : null;
}
@NonNull
protected abstract String getRootArrayKey();
@NonNull
protected List<Location> convertRouteToLocationsList(@NonNull List<LatLon> route) {
@ -161,7 +184,7 @@ public abstract class OnlineRoutingEngine implements Cloneable {
return allowedParameters.contains(key);
}
protected void allowParameters(@NonNull EngineParameter ... allowedParams) {
protected void allowParameters(@NonNull EngineParameter... allowedParams) {
allowedParameters.addAll(Arrays.asList(allowedParams));
}
@ -193,8 +216,19 @@ public abstract class OnlineRoutingEngine implements Cloneable {
return CUSTOM_VEHICLE;
}
public abstract boolean parseServerMessage(@NonNull StringBuilder sb,
@NonNull String content) throws JSONException;
public boolean checkServerResponse(@NonNull StringBuilder errorMessage,
@NonNull String content) throws JSONException {
JSONObject obj = new JSONObject(content);
String messageKey = getErrorMessageKey();
if (obj.has(messageKey)) {
String message = obj.getString(messageKey);
errorMessage.append(message);
}
return obj.has(getRootArrayKey());
}
@NonNull
protected abstract String getErrorMessageKey();
@NonNull
@Override
@ -202,11 +236,6 @@ public abstract class OnlineRoutingEngine implements Cloneable {
return OnlineRoutingFactory.createEngine(getType(), getParams());
}
@NonNull
public static String generateKey() {
return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis();
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
@ -216,4 +245,27 @@ public abstract class OnlineRoutingEngine implements Cloneable {
if (getType() != engine.getType()) return false;
return Algorithms.objectEquals(getParams(), engine.getParams());
}
@NonNull
public static String generateKey() {
return ONLINE_ROUTING_ENGINE_PREFIX + System.currentTimeMillis();
}
public static class OnlineRoutingResponse {
private List<Location> route;
private List<RouteDirectionInfo> directions;
public OnlineRoutingResponse(List<Location> route, List<RouteDirectionInfo> directions) {
this.route = route;
this.directions = directions;
}
public List<Location> getRoute() {
return route;
}
public List<RouteDirectionInfo> getDirections() {
return directions;
}
}
}

View file

@ -8,7 +8,6 @@ import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.onlinerouting.EngineParameter;
import net.osmand.plus.onlinerouting.OnlineRoutingResponse;
import net.osmand.plus.onlinerouting.VehicleType;
import org.json.JSONArray;
@ -81,12 +80,10 @@ public class OrsEngine extends OnlineRoutingEngine {
@Nullable
@Override
public OnlineRoutingResponse parseServerResponse(@NonNull String content,
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
@NonNull OsmandApplication app,
boolean leftSideNavigation) throws JSONException {
JSONObject obj = new JSONObject(content);
JSONArray array = obj.getJSONArray("features").getJSONObject(0)
.getJSONObject("geometry").getJSONArray("coordinates");
JSONArray array = root.getJSONObject("geometry").getJSONArray("coordinates");
List<LatLon> points = new ArrayList<>();
for (int i = 0; i < array.length(); i++) {
JSONArray point = array.getJSONArray(i);
@ -101,14 +98,15 @@ public class OrsEngine extends OnlineRoutingEngine {
return null;
}
@NonNull
@Override
public boolean parseServerMessage(@NonNull StringBuilder sb,
@NonNull String content) throws JSONException {
JSONObject obj = new JSONObject(content);
if (obj.has("error")) {
String message = obj.getString("error");
sb.append(message);
}
return obj.has("features");
protected String getErrorMessageKey() {
return "error";
}
@NonNull
@Override
protected String getRootArrayKey() {
return "features";
}
}

View file

@ -8,7 +8,6 @@ import net.osmand.data.LatLon;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.onlinerouting.EngineParameter;
import net.osmand.plus.onlinerouting.OnlineRoutingResponse;
import net.osmand.plus.onlinerouting.VehicleType;
import net.osmand.plus.routing.RouteCalculationResult;
import net.osmand.plus.routing.RouteDirectionInfo;
@ -77,19 +76,17 @@ public class OsrmEngine extends OnlineRoutingEngine {
@Nullable
@Override
public OnlineRoutingResponse parseServerResponse(@NonNull String content,
public OnlineRoutingResponse parseServerResponse(@NonNull JSONObject root,
@NonNull OsmandApplication app,
boolean leftSideNavigation) throws JSONException {
JSONObject obj = new JSONObject(content);
JSONObject routeInfo = obj.getJSONArray("routes").getJSONObject(0);
String encodedPoints = routeInfo.getString("geometry");
String encodedPoints = root.getString("geometry");
List<LatLon> points = GeoPolylineParserUtil.parse(encodedPoints, GeoPolylineParserUtil.PRECISION_5);
if (isEmpty(points)) return null;
List<Location> route = convertRouteToLocationsList(points);
List<RouteDirectionInfo> directions = new ArrayList<>();
int startSearchingId = 0;
JSONArray legs = routeInfo.getJSONArray("legs");
JSONArray legs = root.getJSONArray("legs");
for (int i = 0; i < legs.length(); i++) {
JSONObject leg = legs.getJSONObject(i);
if (!leg.has("steps")) continue;
@ -226,14 +223,15 @@ public class OsrmEngine extends OnlineRoutingEngine {
return id != null ? TurnType.valueOf(id, leftSide) : null;
}
@NonNull
@Override
public boolean parseServerMessage(@NonNull StringBuilder sb,
@NonNull String content) throws JSONException {
JSONObject obj = new JSONObject(content);
if (obj.has("message")) {
String message = obj.getString("message");
sb.append(message);
}
return obj.has("routes");
protected String getErrorMessageKey() {
return "message";
}
@NonNull
@Override
protected String getRootArrayKey() {
return "routes";
}
}

View file

@ -458,15 +458,15 @@ public class OnlineRoutingEngineFragment extends BaseOsmAndFragment {
new Thread(new Runnable() {
@Override
public void run() {
StringBuilder message = new StringBuilder();
StringBuilder errorMessage = new StringBuilder();
boolean resultOk = false;
try {
String response = helper.makeRequest(exampleCard.getEditedText());
resultOk = requestedEngine.parseServerMessage(message, response);
resultOk = requestedEngine.checkServerResponse(errorMessage, response);
} catch (IOException | JSONException e) {
message.append(e.toString());
errorMessage.append(e.toString());
}
showTestResults(resultOk, message.toString(), location);
showTestResults(resultOk, errorMessage.toString(), location);
}
}).start();
}

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

@ -28,7 +28,7 @@ import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import static net.osmand.plus.osmedit.oauth.OsmOAuthHelper.*;
import static net.osmand.plus.osmedit.oauth.OsmOAuthHelper.OsmAuthorizationListener;
/**
* Created by Denis
@ -149,7 +149,9 @@ public class DashOsmEditsFragment extends DashBaseFragment
@Override
public void authorizationCompleted() {
SendPoiBottomSheetFragment.showInstance(getChildFragmentManager(), new OsmPoint[]{selectedPoint});
if (selectedPoint != null) {
SendPoiBottomSheetFragment.showInstance(getChildFragmentManager(), new OsmPoint[] {selectedPoint});
}
}
@Override

View file

@ -5,6 +5,7 @@ import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.fragment.app.FragmentManager;
import net.osmand.data.PointDescription;
import net.osmand.osm.PoiType;
@ -51,19 +52,18 @@ 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) {
if (isLogged) {
SendPoiBottomSheetFragment.showInstance(activity.getSupportFragmentManager(),
new OsmPoint[]{getOsmPoint()});
SendPoiBottomSheetFragment.showInstance(fragmentManager, new OsmPoint[] {point});
} else {
LoginBottomSheetFragment.showInstance(activity.getSupportFragmentManager(), null);
LoginBottomSheetFragment.showInstance(fragmentManager, null);
}
} else if (point instanceof OsmNotesPoint) {
SendOsmNoteBottomSheetFragment.showInstance(activity.getSupportFragmentManager(),
new OsmPoint[]{getOsmPoint()});
SendOsmNoteBottomSheetFragment.showInstance(fragmentManager, new OsmPoint[] {point});
}
}
}

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

@ -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

@ -1,19 +1,10 @@
package net.osmand.plus.osmedit.oauth;
import android.content.Context;
import android.content.Intent;
import android.net.TrafficStats;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import androidx.browser.customtabs.CustomTabsIntent;
import androidx.core.content.ContextCompat;
import com.github.scribejava.core.builder.api.DefaultApi10a;
import com.github.scribejava.core.model.OAuth1AccessToken;
@ -24,7 +15,6 @@ import com.github.scribejava.core.model.Verb;
import net.osmand.PlatformUtil;
import net.osmand.osm.oauth.OsmOAuthAuthorizationClient;
import net.osmand.plus.OsmAndConstants;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.R;
import net.osmand.plus.wikipedia.WikipediaDialogFragment;
@ -52,7 +42,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);
@ -78,8 +68,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 {
@ -93,8 +83,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) {
@ -137,7 +127,7 @@ public class OsmOAuthAuthorizationAdapter {
}
@Override
protected void onPostExecute(@NonNull OAuth1RequestToken requestToken) {
protected void onPostExecute(OAuth1RequestToken requestToken) {
if (requestToken != null) {
loadWebView(rootLayout, nightMode, client.getService().getAuthorizationUrl(requestToken));
} else {
@ -156,9 +146,11 @@ public class OsmOAuthAuthorizationAdapter {
@Override
protected Void doInBackground(String... oauthVerifier) {
client.authorize(oauthVerifier[0]);
saveToken();
updateUserName();
if (client.getRequestToken() != null) {
client.authorize(oauthVerifier[0]);
saveToken();
updateUserName();
}
return null;
}
@ -180,7 +172,7 @@ public class OsmOAuthAuthorizationAdapter {
} catch (XmlPullParserException 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

@ -1,7 +1,11 @@
package net.osmand.plus.profiles;
import net.osmand.plus.settings.backend.ApplicationMode;
import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
import net.osmand.plus.R;
import net.osmand.plus.profiles.ConfigureProfileMenuAdapter.ProfileSelectedListener;
import net.osmand.plus.settings.backend.ApplicationMode;
import java.util.ArrayList;
import java.util.HashSet;
@ -9,8 +13,8 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
public class ConfigureAppModesBottomSheetDialogFragment extends AppModesBottomSheetDialogFragment<ConfigureProfileMenuAdapter>
implements ConfigureProfileMenuAdapter.ProfileSelectedListener {
public class ConfigureAppModesBottomSheetDialogFragment extends AppModesBottomSheetDialogFragment<ConfigureProfileMenuAdapter>
implements ProfileSelectedListener {
public static final String TAG = "ConfigureAppModesBottomSheetDialogFragment";
@ -56,4 +60,15 @@ public class ConfigureAppModesBottomSheetDialogFragment extends AppModesBottomSh
}
ApplicationMode.changeProfileAvailability(item, isChecked, getMyApplication());
}
public static void showInstance(@NonNull FragmentManager fragmentManager, boolean usedOnMap, UpdateMapRouteMenuListener listener) {
if (fragmentManager.findFragmentByTag(TAG) == null) {
ConfigureAppModesBottomSheetDialogFragment fragment = new ConfigureAppModesBottomSheetDialogFragment();
fragment.setUsedOnMap(usedOnMap);
fragment.setUpdateMapRouteMenuListener(listener);
fragmentManager.beginTransaction()
.add(fragment, TAG)
.commitAllowingStateLoss();
}
}
}

View file

@ -29,6 +29,8 @@ import androidx.appcompat.content.res.AppCompatResources;
import androidx.appcompat.widget.AppCompatImageView;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
import androidx.fragment.app.FragmentManager;
import androidx.transition.AutoTransition;
import androidx.transition.Scene;
import androidx.transition.Transition;
@ -71,7 +73,7 @@ import net.osmand.plus.mapcontextmenu.other.TrackDetailsMenuFragment;
import net.osmand.plus.mapmarkers.MapMarker;
import net.osmand.plus.mapmarkers.MapMarkerSelectionFragment;
import net.osmand.plus.poi.PoiUIFilter;
import net.osmand.plus.profiles.AppModesBottomSheetDialogFragment;
import net.osmand.plus.profiles.AppModesBottomSheetDialogFragment.UpdateMapRouteMenuListener;
import net.osmand.plus.profiles.ConfigureAppModesBottomSheetDialogFragment;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.AvoidPTTypesRoutingParameter;
import net.osmand.plus.routepreparationmenu.RoutingOptionsHelper.AvoidRoadsRoutingParameter;
@ -870,16 +872,16 @@ public class MapRouteInfoMenu implements IRouteInformationListener, CardListener
}
private void showProfileBottomSheetDialog() {
final AppModesBottomSheetDialogFragment fragment = new ConfigureAppModesBottomSheetDialogFragment();
fragment.setUsedOnMap(true);
fragment.setUpdateMapRouteMenuListener(new AppModesBottomSheetDialogFragment.UpdateMapRouteMenuListener() {
@Override
public void updateAppModeMenu() {
updateApplicationModes();
}
});
getMapActivity().getSupportFragmentManager().beginTransaction()
.add(fragment, ConfigureAppModesBottomSheetDialogFragment.TAG).commitAllowingStateLoss();
FragmentActivity activity = getMapActivity();
if (activity != null) {
FragmentManager manager = activity.getSupportFragmentManager();
ConfigureAppModesBottomSheetDialogFragment.showInstance(manager, true, new UpdateMapRouteMenuListener() {
@Override
public void updateAppModeMenu() {
updateApplicationModes();
}
});
}
}
private void updateApplicationMode(ApplicationMode mode, ApplicationMode next) {

View file

@ -625,11 +625,14 @@ public class RouteOptionsBottomSheet extends MenuBottomSheetDialogFragment {
private List<RoutingParameter> getReliefParameters() {
List<RoutingParameter> reliefFactorParameters = new ArrayList<>();
Map<String, RoutingParameter> parameters = app.getRouter(applicationMode).getParameters();
for (Map.Entry<String, RoutingParameter> entry : parameters.entrySet()) {
RoutingParameter routingParameter = entry.getValue();
if (RELIEF_SMOOTHNESS_FACTOR.equals(routingParameter.getGroup())) {
reliefFactorParameters.add(routingParameter);
GeneralRouter router = app.getRouter(applicationMode);
if (router != null) {
Map<String, RoutingParameter> parameters = router.getParameters();
for (Map.Entry<String, RoutingParameter> entry : parameters.entrySet()) {
RoutingParameter routingParameter = entry.getValue();
if (RELIEF_SMOOTHNESS_FACTOR.equals(routingParameter.getGroup())) {
reliefFactorParameters.add(routingParameter);
}
}
}
return reliefFactorParameters;

View file

@ -21,7 +21,7 @@ import net.osmand.data.LocationPoint;
import net.osmand.data.WptLocationPoint;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.onlinerouting.OnlineRoutingHelper;
import net.osmand.plus.onlinerouting.OnlineRoutingResponse;
import net.osmand.plus.onlinerouting.engine.OnlineRoutingEngine.OnlineRoutingResponse;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.backend.CommonPreference;
import net.osmand.plus.R;

View file

@ -301,7 +301,12 @@ public class ApplicationMode {
}
public boolean isCustomProfile() {
return !defaultValues.contains(this);
for (ApplicationMode mode : defaultValues) {
if (Algorithms.stringsEqual(mode.getStringKey(), getStringKey())) {
return false;
}
}
return true;
}
public boolean isDerivedRoutingFrom(ApplicationMode mode) {

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

@ -124,7 +124,7 @@ public class ProfileSettingsItem extends OsmandSettingsItem {
if (Algorithms.isEmpty(modeBean.userProfileName)) {
ApplicationMode appMode = ApplicationMode.valueOfStringKey(modeBean.stringKey, null);
if (appMode != null) {
modeBean.userProfileName = app.getString(appMode.getNameKeyResource());
modeBean.userProfileName = appMode.toHumanString();
}
}
int number = 0;

View file

@ -19,13 +19,13 @@ import net.osmand.plus.base.bottomsheetmenu.BaseBottomSheetItem;
import net.osmand.plus.base.bottomsheetmenu.BottomSheetItemWithDescription;
import net.osmand.plus.base.bottomsheetmenu.simpleitems.TitleItem;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import net.osmand.plus.settings.fragments.DataStorageMenuItem;
import net.osmand.plus.settings.datastorage.item.StorageItem;
import org.apache.commons.logging.Log;
import java.io.File;
import static net.osmand.plus.settings.fragments.DataStorageHelper.MANUALLY_SPECIFIED;
import static net.osmand.plus.settings.datastorage.DataStorageHelper.MANUALLY_SPECIFIED;
public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
@ -39,8 +39,8 @@ public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
public final static String MOVE_DATA = "move_data";
public final static String CHOSEN_DIRECTORY = "chosen_storage";
private DataStorageMenuItem currentDirectory;
private DataStorageMenuItem newDirectory;
private StorageItem currentDirectory;
private StorageItem newDirectory;
@Override
public void createMenuItems(Bundle savedInstanceState) {
@ -126,11 +126,11 @@ public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
items.add(baseItem);
}
public void setCurrentDirectory(DataStorageMenuItem currentDirectory) {
public void setCurrentDirectory(StorageItem currentDirectory) {
this.currentDirectory = currentDirectory;
}
public void setNewDirectory(DataStorageMenuItem newDirectory) {
public void setNewDirectory(StorageItem newDirectory) {
this.newDirectory = newDirectory;
}
@ -158,8 +158,8 @@ public class ChangeDataStorageBottomSheet extends BasePreferenceBottomSheet {
return true;
}
public static boolean showInstance(FragmentManager fm, String prefId, DataStorageMenuItem currentDirectory,
DataStorageMenuItem newDirectory, Fragment target, boolean usedOnMap) {
public static boolean showInstance(FragmentManager fm, String prefId, StorageItem currentDirectory,
StorageItem newDirectory, Fragment target, boolean usedOnMap) {
try {
if (fm.findFragmentByTag(TAG) == null) {
Bundle args = new Bundle();

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

@ -1,8 +1,7 @@
package net.osmand.plus.settings.fragments;
package net.osmand.plus.settings.datastorage;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Drawable;
@ -26,7 +25,6 @@ import net.osmand.AndroidUtils;
import net.osmand.FileUtils;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.ProgressImplementation;
import net.osmand.plus.R;
import net.osmand.plus.UiUtilities;
import net.osmand.plus.activities.MapActivity;
@ -34,20 +32,21 @@ import net.osmand.plus.activities.OsmandActionBarActivity;
import net.osmand.plus.download.DownloadActivity;
import net.osmand.plus.settings.bottomsheets.ChangeDataStorageBottomSheet;
import net.osmand.plus.settings.bottomsheets.SelectFolderBottomSheet;
import net.osmand.util.Algorithms;
import net.osmand.plus.settings.datastorage.item.MemoryItem;
import net.osmand.plus.settings.datastorage.item.StorageItem;
import net.osmand.plus.settings.datastorage.task.MoveFilesTask;
import net.osmand.plus.settings.datastorage.task.RefreshUsedMemoryTask;
import net.osmand.plus.settings.datastorage.task.ReloadDataTask;
import net.osmand.plus.settings.fragments.BaseSettingsFragment;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.text.DecimalFormat;
import java.util.ArrayList;
import static net.osmand.plus.settings.fragments.DataStorageHelper.INTERNAL_STORAGE;
import static net.osmand.plus.settings.fragments.DataStorageHelper.MANUALLY_SPECIFIED;
import static net.osmand.plus.settings.fragments.DataStorageHelper.OTHER_MEMORY;
import static net.osmand.plus.settings.fragments.DataStorageHelper.TILES_MEMORY;
import static net.osmand.plus.settings.datastorage.DataStorageHelper.INTERNAL_STORAGE;
import static net.osmand.plus.settings.datastorage.DataStorageHelper.MANUALLY_SPECIFIED;
import static net.osmand.plus.settings.datastorage.DataStorageHelper.OTHER_MEMORY;
import static net.osmand.plus.settings.datastorage.DataStorageHelper.TILES_MEMORY;
import static net.osmand.plus.settings.bottomsheets.ChangeDataStorageBottomSheet.CHOSEN_DIRECTORY;
import static net.osmand.plus.settings.bottomsheets.ChangeDataStorageBottomSheet.MOVE_DATA;
import static net.osmand.plus.settings.bottomsheets.SelectFolderBottomSheet.NEW_PATH;
@ -60,17 +59,17 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
private final static String CHANGE_DIRECTORY_BUTTON = "change_directory";
private final static String OSMAND_USAGE = "osmand_usage";
private ArrayList<DataStorageMenuItem> menuItems;
private ArrayList<DataStorageMemoryItem> memoryItems;
private ArrayList<StorageItem> storageItems;
private ArrayList<MemoryItem> memoryItems;
private ArrayList<CheckBoxPreference> dataStorageRadioButtonsGroup;
private Preference changeButton;
private DataStorageMenuItem currentDataStorage;
private StorageItem currentDataStorage;
private String tmpManuallySpecifiedPath;
private DataStorageHelper dataStorageHelper;
private boolean calculateTilesBtnPressed;
private DataStorageHelper.RefreshMemoryUsedInfo calculateMemoryTask;
private DataStorageHelper.RefreshMemoryUsedInfo calculateTilesMemoryTask;
private RefreshUsedMemoryTask calculateMemoryTask;
private RefreshUsedMemoryTask calculateTilesMemoryTask;
private OsmandApplication app;
private OsmandActionBarActivity activity;
@ -95,11 +94,11 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
return;
}
menuItems = dataStorageHelper.getStorageItems();
storageItems = dataStorageHelper.getStorageItems();
memoryItems = dataStorageHelper.getMemoryInfoItems();
dataStorageRadioButtonsGroup = new ArrayList<>();
for (DataStorageMenuItem item : menuItems) {
for (StorageItem item : storageItems) {
CheckBoxPreference preference = new CheckBoxPreference(activity);
preference.setKey(item.getKey());
preference.setTitle(item.getTitle());
@ -136,7 +135,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
Bundle resultData = (Bundle) newValue;
if (resultData.containsKey(ChangeDataStorageBottomSheet.TAG)) {
boolean moveMaps = resultData.getBoolean(MOVE_DATA);
DataStorageMenuItem newDataStorage = resultData.getParcelable(CHOSEN_DIRECTORY);
StorageItem newDataStorage = resultData.getParcelable(CHOSEN_DIRECTORY);
if (newDataStorage != null) {
if (tmpManuallySpecifiedPath != null) {
String directory = tmpManuallySpecifiedPath;
@ -154,9 +153,9 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
if (pathChanged) {
tmpManuallySpecifiedPath = resultData.getString(NEW_PATH);
if (tmpManuallySpecifiedPath != null) {
DataStorageMenuItem manuallySpecified = null;
StorageItem manuallySpecified = null;
try {
manuallySpecified = (DataStorageMenuItem) dataStorageHelper.getManuallySpecified().clone();
manuallySpecified = (StorageItem) dataStorageHelper.getManuallySpecified().clone();
manuallySpecified.setDirectory(tmpManuallySpecifiedPath);
} catch (CloneNotSupportedException e) {
return false;
@ -170,7 +169,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
//show necessary dialog
String key = preference.getKey();
if (key != null) {
DataStorageMenuItem newDataStorage = dataStorageHelper.getStorage(key);
StorageItem newDataStorage = dataStorageHelper.getStorage(key);
if (newDataStorage != null) {
if (!currentDataStorage.getKey().equals(newDataStorage.getKey())) {
if (newDataStorage.getType() == OsmandSettings.EXTERNAL_STORAGE_TYPE_DEFAULT
@ -212,7 +211,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
final View itemView = holder.itemView;
if (preference instanceof CheckBoxPreference) {
DataStorageMenuItem item = dataStorageHelper.getStorage(key);
StorageItem item = dataStorageHelper.getStorage(key);
if (item != null) {
TextView tvTitle = itemView.findViewById(android.R.id.title);
TextView tvSummary = itemView.findViewById(R.id.summary);
@ -267,7 +266,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
TextView tvSummary = itemView.findViewById(R.id.summary);
tvSummary.setText(DataStorageHelper.getFormattedMemoryInfo(totalUsageBytes, memoryUnitsFormats));
} else {
for (DataStorageMemoryItem mi : memoryItems) {
for (MemoryItem mi : memoryItems) {
if (key.equals(mi.getKey())) {
TextView tvMemory = itemView.findViewById(R.id.memory);
String summary = "";
@ -326,7 +325,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
}
private void showFolderSelectionDialog() {
DataStorageMenuItem manuallySpecified = dataStorageHelper.getManuallySpecified();
StorageItem manuallySpecified = dataStorageHelper.getManuallySpecified();
if (manuallySpecified != null) {
SelectFolderBottomSheet.showInstance(getFragmentManager(), manuallySpecified.getKey(),
manuallySpecified.getDirectory(), DataStorageFragment.this,
@ -335,11 +334,11 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
}
}
private void moveData(final DataStorageMenuItem currentStorage, final DataStorageMenuItem newStorage) {
private void moveData(final StorageItem currentStorage, final StorageItem newStorage) {
File fromDirectory = new File(currentStorage.getDirectory());
File toDirectory = new File(newStorage.getDirectory());
@SuppressLint("StaticFieldLeak")
MoveFilesToDifferentDirectory task = new MoveFilesToDifferentDirectory(activity, fromDirectory, toDirectory) {
MoveFilesTask task = new MoveFilesTask(activity, fromDirectory, toDirectory) {
@NonNull
@ -405,7 +404,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
private void confirm(OsmandApplication app, OsmandActionBarActivity activity, DataStorageMenuItem newStorageDirectory, boolean silentRestart) {
private void confirm(OsmandApplication app, OsmandActionBarActivity activity, StorageItem newStorageDirectory, boolean silentRestart) {
String newDirectory = newStorageDirectory.getDirectory();
int type = newStorageDirectory.getType();
File newDirectoryFile = new File(newDirectory);
@ -454,7 +453,7 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
}
protected void reloadData() {
new ReloadData(activity, app).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
new ReloadDataTask(activity, app).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void) null);
}
@Override
@ -463,204 +462,10 @@ public class DataStorageFragment extends BaseSettingsFragment implements DataSto
}
@Override
public void onFinishUpdating(String taskKey) {
public void onFinishUpdating(String tag) {
updateAllSettings();
if (taskKey != null && taskKey.equals(TILES_MEMORY)) {
if (tag != null && tag.equals(TILES_MEMORY)) {
app.getSettings().OSMAND_USAGE_SPACE.set(dataStorageHelper.getTotalUsedBytes());
}
}
public static class MoveFilesToDifferentDirectory extends AsyncTask<Void, Void, Boolean> {
protected WeakReference<OsmandActionBarActivity> activity;
private WeakReference<Context> context;
private File from;
private File to;
protected ProgressImplementation progress;
private Runnable runOnSuccess;
private int movedCount;
private long movedSize;
private int copiedCount;
private long copiedSize;
private int failedCount;
private long failedSize;
private String exceptionMessage;
public MoveFilesToDifferentDirectory(OsmandActionBarActivity activity, File from, File to) {
this.activity = new WeakReference<>(activity);
this.context = new WeakReference<>((Context) activity);
this.from = from;
this.to = to;
}
public void setRunOnSuccess(Runnable runOnSuccess) {
this.runOnSuccess = runOnSuccess;
}
public int getMovedCount() {
return movedCount;
}
public int getCopiedCount() {
return copiedCount;
}
public int getFailedCount() {
return failedCount;
}
public long getMovedSize() {
return movedSize;
}
public long getCopiedSize() {
return copiedSize;
}
public long getFailedSize() {
return failedSize;
}
@Override
protected void onPreExecute() {
Context ctx = context.get();
if (context == null) {
return;
}
movedCount = 0;
copiedCount = 0;
failedCount = 0;
progress = ProgressImplementation.createProgressDialog(
ctx, ctx.getString(R.string.copying_osmand_files),
ctx.getString(R.string.copying_osmand_files_descr, to.getPath()),
ProgressDialog.STYLE_HORIZONTAL);
}
@Override
protected void onPostExecute(Boolean result) {
Context ctx = context.get();
if (ctx == null) {
return;
}
if (result != null) {
if (result.booleanValue() && runOnSuccess != null) {
runOnSuccess.run();
} else if (!result.booleanValue()) {
Toast.makeText(ctx, ctx.getString(R.string.shared_string_io_error) + ": " + exceptionMessage, Toast.LENGTH_LONG).show();
}
}
try {
if (progress.getDialog().isShowing()) {
progress.getDialog().dismiss();
}
} catch (Exception e) {
//ignored
}
}
private void movingFiles(File f, File t, int depth) throws IOException {
Context ctx = context.get();
if (ctx == null) {
return;
}
if (depth <= 2) {
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), -1);
}
if (f.isDirectory()) {
t.mkdirs();
File[] lf = f.listFiles();
if (lf != null) {
for (int i = 0; i < lf.length; i++) {
if (lf[i] != null) {
movingFiles(lf[i], new File(t, lf[i].getName()), depth + 1);
}
}
}
f.delete();
} else if (f.isFile()) {
if (t.exists()) {
Algorithms.removeAllFiles(t);
}
boolean rnm = false;
long fileSize = f.length();
try {
rnm = f.renameTo(t);
movedCount++;
movedSize += fileSize;
} catch (RuntimeException e) {
}
if (!rnm) {
FileInputStream fin = new FileInputStream(f);
FileOutputStream fout = new FileOutputStream(t);
try {
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), (int) (f.length() / 1024));
Algorithms.streamCopy(fin, fout, progress, 1024);
copiedCount++;
copiedSize += fileSize;
} catch (IOException e) {
failedCount++;
failedSize += fileSize;
} finally {
fin.close();
fout.close();
}
f.delete();
}
}
if (depth <= 2) {
progress.finishTask();
}
}
@Override
protected Boolean doInBackground(Void... params) {
to.mkdirs();
try {
movingFiles(from, to, 0);
} catch (IOException e) {
exceptionMessage = e.getMessage();
return false;
}
return true;
}
}
public static class ReloadData extends AsyncTask<Void, Void, Boolean> {
private WeakReference<Context> ctx;
protected ProgressImplementation progress;
private OsmandApplication app;
public ReloadData(Context ctx, OsmandApplication app) {
this.ctx = new WeakReference<>(ctx);
this.app = app;
}
@Override
protected void onPreExecute() {
Context c = ctx.get();
if (c == null) {
return;
}
progress = ProgressImplementation.createProgressDialog(c, c.getString(R.string.loading_data),
c.getString(R.string.loading_data), ProgressDialog.STYLE_HORIZONTAL);
}
@Override
protected void onPostExecute(Boolean result) {
try {
if (progress.getDialog().isShowing()) {
progress.getDialog().dismiss();
}
} catch (Exception e) {
//ignored
}
}
@Override
protected Boolean doInBackground(Void... params) {
app.getResourceManager().reloadIndexes(progress, new ArrayList<String>());
return true;
}
}
}

View file

@ -0,0 +1,321 @@
package net.osmand.plus.settings.datastorage;
import android.os.Build;
import androidx.annotation.NonNull;
import net.osmand.IndexConstants;
import net.osmand.ValueHolder;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.settings.datastorage.item.DirectoryItem;
import net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType;
import net.osmand.plus.settings.datastorage.item.MemoryItem;
import net.osmand.plus.settings.datastorage.item.StorageItem;
import net.osmand.plus.settings.datastorage.task.RefreshUsedMemoryTask;
import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import static net.osmand.IndexConstants.AV_INDEX_DIR;
import static net.osmand.IndexConstants.BACKUP_INDEX_DIR;
import static net.osmand.IndexConstants.GPX_INDEX_DIR;
import static net.osmand.IndexConstants.MAPS_PATH;
import static net.osmand.IndexConstants.ROADS_INDEX_DIR;
import static net.osmand.IndexConstants.SRTM_INDEX_DIR;
import static net.osmand.IndexConstants.TILES_INDEX_DIR;
import static net.osmand.IndexConstants.WIKIVOYAGE_INDEX_DIR;
import static net.osmand.IndexConstants.WIKI_INDEX_DIR;
import static net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType.EXTENSIONS;
import static net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType.PREFIX;
public class DataStorageHelper {
public final static String INTERNAL_STORAGE = "internal_storage";
public final static String EXTERNAL_STORAGE = "external_storage";
public final static String SHARED_STORAGE = "shared_storage";
public final static String MULTIUSER_STORAGE = "multiuser_storage";
public final static String MANUALLY_SPECIFIED = "manually_specified";
public final static String MAPS_MEMORY = "maps_memory_used";
public final static String TERRAIN_MEMORY = "terrain_memory_used";
public final static String TRACKS_MEMORY = "tracks_memory_used";
public final static String NOTES_MEMORY = "notes_memory_used";
public final static String TILES_MEMORY = "tiles_memory_used";
public final static String OTHER_MEMORY = "other_memory_used";
private OsmandApplication app;
private ArrayList<StorageItem> storageItems = new ArrayList<>();
private StorageItem currentDataStorage;
private StorageItem manuallySpecified;
private ArrayList<MemoryItem> memoryItems = new ArrayList<>();
private MemoryItem mapsMemory;
private MemoryItem terrainMemory;
private MemoryItem tracksMemory;
private MemoryItem notesMemory;
private MemoryItem tilesMemory;
private MemoryItem otherMemory;
private int currentStorageType;
private String currentStoragePath;
public DataStorageHelper(@NonNull OsmandApplication app) {
this.app = app;
prepareData();
}
private void prepareData() {
initStorageItems();
initUsedMemoryItems();
}
private void initStorageItems() {
OsmandSettings settings = app.getSettings();
if (settings.getExternalStorageDirectoryTypeV19() >= 0) {
currentStorageType = settings.getExternalStorageDirectoryTypeV19();
} else {
ValueHolder<Integer> vh = new ValueHolder<Integer>();
if (vh.value != null && vh.value >= 0) {
currentStorageType = vh.value;
} else {
currentStorageType = 0;
}
}
currentStoragePath = settings.getExternalStorageDirectory().getAbsolutePath();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//internal storage
String path = settings.getInternalAppPath().getAbsolutePath();
File dir = new File(path);
int iconId = R.drawable.ic_action_phone;
StorageItem internalStorageItem = StorageItem.builder()
.setKey(INTERNAL_STORAGE)
.setTitle(app.getString(R.string.storage_directory_internal_app))
.setDirectory(path)
.setDescription(app.getString(R.string.internal_app_storage_description))
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE)
.setIconResId(iconId)
.createItem();
addItem(internalStorageItem);
//shared storage
dir = settings.getDefaultInternalStorage();
path = dir.getAbsolutePath();
iconId = R.drawable.ic_action_phone;
StorageItem sharedStorageItem = StorageItem.builder()
.setKey(SHARED_STORAGE)
.setTitle(app.getString(R.string.storage_directory_shared))
.setDirectory(path)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_DEFAULT)
.setIconResId(iconId)
.createItem();
addItem(sharedStorageItem);
//external storage
File[] externals = app.getExternalFilesDirs(null);
if (externals != null) {
int i = 0;
for (File external : externals) {
if (external != null) {
++i;
dir = external;
path = dir.getAbsolutePath();
iconId = getIconForStorageType(dir);
StorageItem externalStorageItem = StorageItem.builder()
.setKey(EXTERNAL_STORAGE + i)
.setTitle(app.getString(R.string.storage_directory_external) + " " + i)
.setDirectory(path)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_EXTERNAL_FILE)
.setIconResId(iconId)
.createItem();
addItem(externalStorageItem);
}
}
}
//multi user storage
File[] obbDirs = app.getObbDirs();
if (obbDirs != null) {
int i = 0;
for (File obb : obbDirs) {
if (obb != null) {
++i;
dir = obb;
path = dir.getAbsolutePath();
iconId = getIconForStorageType(dir);
StorageItem multiuserStorageItem = StorageItem.builder()
.setKey(MULTIUSER_STORAGE + i)
.setTitle(app.getString(R.string.storage_directory_multiuser) + " " + i)
.setDirectory(path)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_OBB)
.setIconResId(iconId)
.createItem();
addItem(multiuserStorageItem);
}
}
}
}
//manually specified storage
manuallySpecified = StorageItem.builder()
.setKey(MANUALLY_SPECIFIED)
.setTitle(app.getString(R.string.storage_directory_manual))
.setDirectory(currentStoragePath)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED)
.setIconResId(R.drawable.ic_action_folder)
.createItem();
storageItems.add(manuallySpecified);
if (currentDataStorage == null) {
currentDataStorage = manuallySpecified;
}
}
private void initUsedMemoryItems() {
mapsMemory = MemoryItem.builder()
.setKey(MAPS_MEMORY)
.setExtensions(IndexConstants.BINARY_MAP_INDEX_EXT)
.setDirectories(
createDirectory(MAPS_PATH, false, EXTENSIONS, true),
createDirectory(ROADS_INDEX_DIR, true, EXTENSIONS, true),
createDirectory(WIKI_INDEX_DIR, true, EXTENSIONS, true),
createDirectory(WIKIVOYAGE_INDEX_DIR, true, EXTENSIONS, true),
createDirectory(BACKUP_INDEX_DIR, true, EXTENSIONS, true))
.createItem();
memoryItems.add(mapsMemory);
terrainMemory = MemoryItem.builder()
.setKey(TERRAIN_MEMORY)
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
.setDirectories(
createDirectory(SRTM_INDEX_DIR, true, EXTENSIONS, true),
createDirectory(TILES_INDEX_DIR, false, PREFIX, false))
.setPrefixes("Hillshade", "Slope")
.createItem();
memoryItems.add(terrainMemory);
tracksMemory = MemoryItem.builder()
.setKey(TRACKS_MEMORY)
// .setExtensions(IndexConstants.GPX_FILE_EXT, ".gpx.bz2")
.setDirectories(
createDirectory(GPX_INDEX_DIR, true, EXTENSIONS, true))
.createItem();
memoryItems.add(tracksMemory);
notesMemory = MemoryItem.builder()
.setKey(NOTES_MEMORY)
// .setExtensions("")
.setDirectories(
createDirectory(AV_INDEX_DIR, true, EXTENSIONS, true))
.createItem();
memoryItems.add(notesMemory);
tilesMemory = MemoryItem.builder()
.setKey(TILES_MEMORY)
// .setExtensions("")
.setDirectories(
createDirectory(TILES_INDEX_DIR, true, EXTENSIONS, true))
.createItem();
memoryItems.add(tilesMemory);
otherMemory = MemoryItem.builder()
.setKey(OTHER_MEMORY)
.createItem();
memoryItems.add(otherMemory);
}
public ArrayList<StorageItem> getStorageItems() {
return storageItems;
}
private int getIconForStorageType(File dir) {
return R.drawable.ic_action_folder;
}
public StorageItem getCurrentStorage() {
return currentDataStorage;
}
private void addItem(StorageItem item) {
if (currentStorageType == item.getType() && currentStoragePath.equals(item.getDirectory())) {
currentDataStorage = item;
}
storageItems.add(item);
}
public StorageItem getManuallySpecified() {
return manuallySpecified;
}
public StorageItem getStorage(String key) {
if (storageItems != null && key != null) {
for (StorageItem storageItem : storageItems) {
if (key.equals(storageItem.getKey())) {
return storageItem;
}
}
}
return null;
}
public ArrayList<MemoryItem> getMemoryInfoItems() {
return memoryItems;
}
public RefreshUsedMemoryTask calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter uiAdapter) {
File rootDir = new File(currentStoragePath);
RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(uiAdapter, otherMemory, rootDir, null, null, OTHER_MEMORY);
task.execute(mapsMemory, terrainMemory, tracksMemory, notesMemory);
return task;
}
public RefreshUsedMemoryTask calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) {
File rootDir = new File(tilesMemory.getDirectories()[0].getAbsolutePath());
RefreshUsedMemoryTask task = new RefreshUsedMemoryTask(listener, otherMemory, rootDir, null, terrainMemory.getPrefixes(), TILES_MEMORY);
task.execute(tilesMemory);
return task;
}
public long getTotalUsedBytes() {
long total = 0;
if (memoryItems != null && memoryItems.size() > 0) {
for (MemoryItem mi : memoryItems) {
total += mi.getUsedMemoryBytes();
}
return total;
}
return -1;
}
public DirectoryItem createDirectory(@NonNull String relativePath,
boolean processInternalDirectories,
CheckingType checkingType,
boolean addUnmatchedToOtherMemory) {
String path = app.getAppPath(relativePath).getAbsolutePath();
return new DirectoryItem(path, processInternalDirectories, checkingType, addUnmatchedToOtherMemory);
}
public static String getFormattedMemoryInfo(long bytes, String[] formatStrings) {
int type = 0;
double memory = (double) bytes / 1024;
while (memory > 1024 && type < formatStrings.length) {
++type;
memory = memory / 1024;
}
String formattedUsed = new DecimalFormat("#.##").format(memory);
return String.format(formatStrings[type], formattedUsed);
}
public interface UpdateMemoryInfoUIAdapter {
void onMemoryInfoUpdate();
void onFinishUpdating(String tag);
}
}

View file

@ -0,0 +1,40 @@
package net.osmand.plus.settings.datastorage.item;
public class DirectoryItem {
private final String absolutePath;
private final boolean processInternalDirectories;
private final CheckingType checkingType;
private final boolean addUnmatchedToOtherMemory;
public enum CheckingType {
EXTENSIONS,
PREFIX
}
public DirectoryItem(String absolutePath,
boolean processInternalDirectories,
CheckingType checkingType,
boolean addUnmatchedToOtherMemory) {
this.absolutePath = absolutePath;
this.processInternalDirectories = processInternalDirectories;
this.checkingType = checkingType;
this.addUnmatchedToOtherMemory = addUnmatchedToOtherMemory;
}
public String getAbsolutePath() {
return absolutePath;
}
public boolean shouldProcessInternalDirectories() {
return processInternalDirectories;
}
public CheckingType getCheckingType() {
return checkingType;
}
public boolean shouldAddUnmatchedToOtherMemory() {
return addUnmatchedToOtherMemory;
}
}

View file

@ -1,16 +1,18 @@
package net.osmand.plus.settings.fragments;
package net.osmand.plus.settings.datastorage.item;
public class MemoryItem {
public class DataStorageMemoryItem {
public final static int EXTENSIONS = 0;
public final static int PREFIX = 1;
private String key;
private String[] extensions;
private String[] prefixes;
private Directory[] directories;
private final String[] extensions;
private final String[] prefixes;
private final DirectoryItem[] directories;
private long usedMemoryBytes;
private DataStorageMemoryItem(String key, String[] extensions, String[] prefixes, long usedMemoryBytes, Directory[] directories) {
private MemoryItem(String key,
String[] extensions,
String[] prefixes,
long usedMemoryBytes,
DirectoryItem[] directories) {
this.key = key;
this.extensions = extensions;
this.prefixes = prefixes;
@ -42,7 +44,7 @@ public class DataStorageMemoryItem {
return prefixes;
}
public Directory[] getDirectories() {
public DirectoryItem[] getDirectories() {
return directories;
}
@ -54,7 +56,7 @@ public class DataStorageMemoryItem {
private String key;
private String[] extensions;
private String[] prefixes;
private Directory[] directories;
private DirectoryItem[] directories;
private long usedMemoryBytes;
public DataStorageMemoryItemBuilder setKey(String key) {
@ -72,7 +74,7 @@ public class DataStorageMemoryItem {
return this;
}
public DataStorageMemoryItemBuilder setDirectories(Directory ... directories) {
public DataStorageMemoryItemBuilder setDirectories(DirectoryItem... directories) {
this.directories = directories;
return this;
}
@ -82,38 +84,8 @@ public class DataStorageMemoryItem {
return this;
}
public DataStorageMemoryItem createItem() {
return new DataStorageMemoryItem(key, extensions, prefixes, usedMemoryBytes, directories);
}
}
public static class Directory {
private String absolutePath;
private boolean goDeeper;
private int checkingType;
private boolean skipOther;
public Directory(String absolutePath, boolean goDeeper, int checkingType, boolean skipOther) {
this.absolutePath = absolutePath;
this.goDeeper = goDeeper;
this.checkingType = checkingType;
this.skipOther = skipOther;
}
public String getAbsolutePath() {
return absolutePath;
}
public boolean isGoDeeper() {
return goDeeper;
}
public int getCheckingType() {
return checkingType;
}
public boolean isSkipOther() {
return skipOther;
public MemoryItem createItem() {
return new MemoryItem(key, extensions, prefixes, usedMemoryBytes, directories);
}
}
}

View file

@ -1,11 +1,11 @@
package net.osmand.plus.settings.fragments;
package net.osmand.plus.settings.datastorage.item;
import android.os.Parcel;
import android.os.Parcelable;
import androidx.annotation.IdRes;
public class DataStorageMenuItem implements Parcelable, Cloneable {
public class StorageItem implements Parcelable, Cloneable {
private String key;
private int type;
@ -15,8 +15,12 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
@IdRes
private int iconResId;
private DataStorageMenuItem(String key, int type, String title, String description,
String directory, int iconResId) {
private StorageItem(String key,
int type,
String title,
String description,
String directory,
int iconResId) {
this.key = key;
this.type = type;
this.title = title;
@ -25,7 +29,7 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
this.iconResId = iconResId;
}
private DataStorageMenuItem(Parcel in) {
private StorageItem(Parcel in) {
key = in.readString();
type = in.readInt();
title = in.readString();
@ -99,16 +103,16 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
dest.writeString(directory);
}
public static final Parcelable.Creator<DataStorageMenuItem> CREATOR = new Parcelable.Creator<DataStorageMenuItem>() {
public static final Parcelable.Creator<StorageItem> CREATOR = new Parcelable.Creator<StorageItem>() {
@Override
public DataStorageMenuItem createFromParcel(Parcel source) {
return new DataStorageMenuItem(source);
public StorageItem createFromParcel(Parcel source) {
return new StorageItem(source);
}
@Override
public DataStorageMenuItem[] newArray(int size) {
return new DataStorageMenuItem[size];
public StorageItem[] newArray(int size) {
return new StorageItem[size];
}
};
@ -151,14 +155,14 @@ public class DataStorageMenuItem implements Parcelable, Cloneable {
return this;
}
public DataStorageMenuItem createItem() {
return new DataStorageMenuItem(key, type, title, description, directory, iconResId);
public StorageItem createItem() {
return new StorageItem(key, type, title, description, directory, iconResId);
}
}
@Override
public Object clone() throws CloneNotSupportedException {
return DataStorageMenuItem.builder()
return StorageItem.builder()
.setKey(this.key)
.setTitle(this.title)
.setDescription(this.description)

View file

@ -0,0 +1,173 @@
package net.osmand.plus.settings.datastorage.task;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import android.widget.Toast;
import net.osmand.plus.ProgressImplementation;
import net.osmand.plus.R;
import net.osmand.plus.activities.OsmandActionBarActivity;
import net.osmand.util.Algorithms;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.WeakReference;
public class MoveFilesTask extends AsyncTask<Void, Void, Boolean> {
protected WeakReference<OsmandActionBarActivity> activity;
private WeakReference<Context> context;
private File from;
private File to;
protected ProgressImplementation progress;
private Runnable runOnSuccess;
private int movedCount;
private long movedSize;
private int copiedCount;
private long copiedSize;
private int failedCount;
private long failedSize;
private String exceptionMessage;
public MoveFilesTask(OsmandActionBarActivity activity, File from, File to) {
this.activity = new WeakReference<>(activity);
this.context = new WeakReference<>((Context) activity);
this.from = from;
this.to = to;
}
public void setRunOnSuccess(Runnable runOnSuccess) {
this.runOnSuccess = runOnSuccess;
}
public int getMovedCount() {
return movedCount;
}
public int getCopiedCount() {
return copiedCount;
}
public int getFailedCount() {
return failedCount;
}
public long getMovedSize() {
return movedSize;
}
public long getCopiedSize() {
return copiedSize;
}
public long getFailedSize() {
return failedSize;
}
@Override
protected void onPreExecute() {
Context ctx = context.get();
if (context == null) {
return;
}
movedCount = 0;
copiedCount = 0;
failedCount = 0;
progress = ProgressImplementation.createProgressDialog(
ctx, ctx.getString(R.string.copying_osmand_files),
ctx.getString(R.string.copying_osmand_files_descr, to.getPath()),
ProgressDialog.STYLE_HORIZONTAL);
}
@Override
protected void onPostExecute(Boolean result) {
Context ctx = context.get();
if (ctx == null) {
return;
}
if (result != null) {
if (result.booleanValue() && runOnSuccess != null) {
runOnSuccess.run();
} else if (!result.booleanValue()) {
Toast.makeText(ctx, ctx.getString(R.string.shared_string_io_error) + ": " + exceptionMessage, Toast.LENGTH_LONG).show();
}
}
try {
if (progress.getDialog().isShowing()) {
progress.getDialog().dismiss();
}
} catch (Exception e) {
//ignored
}
}
private void movingFiles(File f, File t, int depth) throws IOException {
Context ctx = context.get();
if (ctx == null) {
return;
}
if (depth <= 2) {
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), -1);
}
if (f.isDirectory()) {
t.mkdirs();
File[] lf = f.listFiles();
if (lf != null) {
for (int i = 0; i < lf.length; i++) {
if (lf[i] != null) {
movingFiles(lf[i], new File(t, lf[i].getName()), depth + 1);
}
}
}
f.delete();
} else if (f.isFile()) {
if (t.exists()) {
Algorithms.removeAllFiles(t);
}
boolean rnm = false;
long fileSize = f.length();
try {
rnm = f.renameTo(t);
movedCount++;
movedSize += fileSize;
} catch (RuntimeException e) {
}
if (!rnm) {
FileInputStream fin = new FileInputStream(f);
FileOutputStream fout = new FileOutputStream(t);
try {
progress.startTask(ctx.getString(R.string.copying_osmand_one_file_descr, t.getName()), (int) (f.length() / 1024));
Algorithms.streamCopy(fin, fout, progress, 1024);
copiedCount++;
copiedSize += fileSize;
} catch (IOException e) {
failedCount++;
failedSize += fileSize;
} finally {
fin.close();
fout.close();
}
f.delete();
}
}
if (depth <= 2) {
progress.finishTask();
}
}
@Override
protected Boolean doInBackground(Void... params) {
to.mkdirs();
try {
movingFiles(from, to, 0);
} catch (IOException e) {
exceptionMessage = e.getMessage();
return false;
}
return true;
}
}

View file

@ -0,0 +1,232 @@
package net.osmand.plus.settings.datastorage.task;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import net.osmand.plus.settings.datastorage.DataStorageHelper.UpdateMemoryInfoUIAdapter;
import net.osmand.plus.settings.datastorage.item.DirectoryItem;
import net.osmand.plus.settings.datastorage.item.DirectoryItem.CheckingType;
import net.osmand.plus.settings.datastorage.item.MemoryItem;
import java.io.File;
import static net.osmand.plus.settings.datastorage.DataStorageFragment.UI_REFRESH_TIME_MS;
import static net.osmand.util.Algorithms.objectEquals;
public class RefreshUsedMemoryTask extends AsyncTask<MemoryItem, Void, Void> {
private final UpdateMemoryInfoUIAdapter uiAdapter;
private final File root;
private final MemoryItem otherMemoryItem;
private final String[] directoriesToSkip;
private final String[] filePrefixesToSkip;
private final String tag;
private long lastRefreshTime;
public RefreshUsedMemoryTask(UpdateMemoryInfoUIAdapter uiAdapter,
MemoryItem otherMemoryItem,
File root,
String[] directoriesToSkip,
String[] filePrefixesToSkip,
String tag) {
this.uiAdapter = uiAdapter;
this.otherMemoryItem = otherMemoryItem;
this.root = root;
this.directoriesToSkip = directoriesToSkip;
this.filePrefixesToSkip = filePrefixesToSkip;
this.tag = tag;
}
@Override
protected Void doInBackground(MemoryItem... items) {
lastRefreshTime = System.currentTimeMillis();
if (root.canRead()) {
calculateMultiTypes(root, items);
}
return null;
}
private void calculateMultiTypes(File rootDir,
MemoryItem... items) {
File[] subFiles = rootDir.listFiles();
if (subFiles != null) {
for (File file : subFiles) {
if (isCancelled()) break;
if (file.isDirectory()) {
if (!shouldSkipDirectory(file)) {
processDirectory(file, items);
}
} else if (file.isFile()) {
if (!shouldSkipFile(file)) {
processFile(rootDir, file, items);
}
}
refreshUI();
}
}
}
private boolean shouldSkipDirectory(@NonNull File dir) {
if (directoriesToSkip != null) {
for (String dirToSkipPath : directoriesToSkip) {
String dirPath = dir.getAbsolutePath();
if (objectEquals(dirPath, dirToSkipPath)) {
return true;
}
}
}
return false;
}
private boolean shouldSkipFile(@NonNull File file) {
if (filePrefixesToSkip != null) {
String fileName = file.getName().toLowerCase();
for (String prefixToAvoid : filePrefixesToSkip) {
String prefix = prefixToAvoid.toLowerCase();
if (fileName.startsWith(prefix)) {
return true;
}
}
}
return false;
}
private void processDirectory(@NonNull File directory,
@NonNull MemoryItem... items) {
String directoryPath = directory.getAbsolutePath();
for (MemoryItem memoryItem : items) {
DirectoryItem[] targetDirectories = memoryItem.getDirectories();
if (targetDirectories != null) {
for (DirectoryItem dir : targetDirectories) {
String allowedDirPath = dir.getAbsolutePath();
boolean isPerfectlyMatch = objectEquals(directoryPath, allowedDirPath);
boolean isParentDirectory = !isPerfectlyMatch && (directoryPath.startsWith(allowedDirPath));
boolean isMatchDirectory = isPerfectlyMatch || isParentDirectory;
if (isPerfectlyMatch) {
calculateMultiTypes(directory, items);
return;
} else if (isParentDirectory && dir.shouldProcessInternalDirectories()) {
calculateMultiTypes(directory, items);
return;
} else if (isMatchDirectory && !dir.shouldAddUnmatchedToOtherMemory()) {
return;
}
}
}
}
// Current directory did not match to any type
otherMemoryItem.addBytes(calculateFolderSize(directory));
}
private void processFile(@NonNull File rootDir,
@NonNull File file,
@NonNull MemoryItem... items) {
for (MemoryItem item : items) {
DirectoryItem[] targetDirectories = item.getDirectories();
if (targetDirectories == null) continue;
String rootDirPath = rootDir.getAbsolutePath();
for (DirectoryItem targetDirectory : targetDirectories) {
String allowedDirPath = targetDirectory.getAbsolutePath();
boolean processInternal = targetDirectory.shouldProcessInternalDirectories();
if (objectEquals(rootDirPath, allowedDirPath)
|| (rootDirPath.startsWith(allowedDirPath) && processInternal)) {
CheckingType checkingType = targetDirectory.getCheckingType();
switch (checkingType) {
case EXTENSIONS: {
if (isSuitableExtension(file, item)) {
item.addBytes(file.length());
return;
}
break;
}
case PREFIX: {
if (isSuitablePrefix(file, item)) {
item.addBytes(file.length());
return;
}
break;
}
}
if (!targetDirectory.shouldAddUnmatchedToOtherMemory()) {
return;
}
}
}
}
// Current file did not match any type
otherMemoryItem.addBytes(file.length());
}
private boolean isSuitableExtension(@NonNull File file,
@NonNull MemoryItem item) {
String[] extensions = item.getExtensions();
if (extensions != null) {
for (String extension : extensions) {
if (file.getAbsolutePath().endsWith(extension)) {
return true;
}
}
}
return extensions == null;
}
private boolean isSuitablePrefix(@NonNull File file,
@NonNull MemoryItem item) {
String[] prefixes = item.getPrefixes();
if (prefixes != null) {
for (String prefix : prefixes) {
if (file.getName().toLowerCase().startsWith(prefix.toLowerCase())) {
return true;
}
}
}
return prefixes == null;
}
private long calculateFolderSize(@NonNull File dir) {
long bytes = 0;
if (dir.isDirectory()) {
File[] files = dir.listFiles();
if (files == null) return 0;
for (File file : files) {
if (isCancelled()) {
break;
}
if (file.isDirectory()) {
bytes += calculateFolderSize(file);
} else if (file.isFile()) {
bytes += file.length();
}
}
}
return bytes;
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
if (uiAdapter != null) {
uiAdapter.onMemoryInfoUpdate();
}
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (uiAdapter != null) {
uiAdapter.onFinishUpdating(tag);
}
}
private void refreshUI() {
long currentTime = System.currentTimeMillis();
if ((currentTime - lastRefreshTime) > UI_REFRESH_TIME_MS) {
lastRefreshTime = currentTime;
publishProgress();
}
}
}

View file

@ -0,0 +1,50 @@
package net.osmand.plus.settings.datastorage.task;
import android.app.ProgressDialog;
import android.content.Context;
import android.os.AsyncTask;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.ProgressImplementation;
import net.osmand.plus.R;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
public class ReloadDataTask extends AsyncTask<Void, Void, Boolean> {
private WeakReference<Context> ctx;
protected ProgressImplementation progress;
private OsmandApplication app;
public ReloadDataTask(Context ctx, OsmandApplication app) {
this.ctx = new WeakReference<>(ctx);
this.app = app;
}
@Override
protected void onPreExecute() {
Context c = ctx.get();
if (c == null) {
return;
}
progress = ProgressImplementation.createProgressDialog(c, c.getString(R.string.loading_data),
c.getString(R.string.loading_data), ProgressDialog.STYLE_HORIZONTAL);
}
@Override
protected void onPostExecute(Boolean result) {
try {
if (progress.getDialog().isShowing()) {
progress.getDialog().dismiss();
}
} catch (Exception e) {
//ignored
}
}
@Override
protected Boolean doInBackground(Void... params) {
app.getResourceManager().reloadIndexes(progress, new ArrayList<String>());
return true;
}
}

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;
@ -73,6 +74,7 @@ import net.osmand.plus.settings.bottomsheets.ChangeGeneralProfilesPrefBottomShee
import net.osmand.plus.settings.bottomsheets.EditTextPreferenceBottomSheet;
import net.osmand.plus.settings.bottomsheets.MultiSelectPreferencesBottomSheet;
import net.osmand.plus.settings.bottomsheets.SingleSelectPreferenceBottomSheet;
import net.osmand.plus.settings.datastorage.DataStorageFragment;
import net.osmand.plus.settings.preferences.ListPreferenceEx;
import net.osmand.plus.settings.preferences.MultiSelectBooleanPreference;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
@ -132,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,485 +0,0 @@
package net.osmand.plus.settings.fragments;
import android.os.AsyncTask;
import android.os.Build;
import net.osmand.IndexConstants;
import net.osmand.ValueHolder;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.R;
import java.io.File;
import java.text.DecimalFormat;
import java.util.ArrayList;
import static net.osmand.plus.settings.fragments.DataStorageFragment.UI_REFRESH_TIME_MS;
import static net.osmand.plus.settings.fragments.DataStorageMemoryItem.Directory;
import static net.osmand.plus.settings.fragments.DataStorageMemoryItem.EXTENSIONS;
import static net.osmand.plus.settings.fragments.DataStorageMemoryItem.PREFIX;
public class DataStorageHelper {
public final static String INTERNAL_STORAGE = "internal_storage";
public final static String EXTERNAL_STORAGE = "external_storage";
public final static String SHARED_STORAGE = "shared_storage";
public final static String MULTIUSER_STORAGE = "multiuser_storage";
public final static String MANUALLY_SPECIFIED = "manually_specified";
public final static String MAPS_MEMORY = "maps_memory_used";
public final static String SRTM_AND_HILLSHADE_MEMORY = "contour_lines_and_hillshade_memory";
public final static String TRACKS_MEMORY = "tracks_memory_used";
public final static String NOTES_MEMORY = "notes_memory_used";
public final static String TILES_MEMORY = "tiles_memory_used";
public final static String OTHER_MEMORY = "other_memory_used";
private ArrayList<DataStorageMenuItem> menuItems = new ArrayList<>();
private DataStorageMenuItem currentDataStorage;
private DataStorageMenuItem manuallySpecified;
private ArrayList<DataStorageMemoryItem> memoryItems = new ArrayList<>();
private DataStorageMemoryItem mapsMemory;
private DataStorageMemoryItem srtmAndHillshadeMemory;
private DataStorageMemoryItem tracksMemory;
private DataStorageMemoryItem notesMemory;
private DataStorageMemoryItem tilesMemory;
private DataStorageMemoryItem otherMemory;
private int currentStorageType;
private String currentStoragePath;
public DataStorageHelper(OsmandApplication app) {
prepareData(app);
}
private void prepareData(OsmandApplication app) {
if (app == null) {
return;
}
OsmandSettings settings = app.getSettings();
if (settings.getExternalStorageDirectoryTypeV19() >= 0) {
currentStorageType = settings.getExternalStorageDirectoryTypeV19();
} else {
ValueHolder<Integer> vh = new ValueHolder<Integer>();
if (vh.value != null && vh.value >= 0) {
currentStorageType = vh.value;
} else {
currentStorageType = 0;
}
}
currentStoragePath = settings.getExternalStorageDirectory().getAbsolutePath();
String path;
File dir;
int iconId;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
//internal storage
path = settings.getInternalAppPath().getAbsolutePath();
dir = new File(path);
iconId = R.drawable.ic_action_phone;
DataStorageMenuItem internalStorageItem = DataStorageMenuItem.builder()
.setKey(INTERNAL_STORAGE)
.setTitle(app.getString(R.string.storage_directory_internal_app))
.setDirectory(path)
.setDescription(app.getString(R.string.internal_app_storage_description))
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_INTERNAL_FILE)
.setIconResId(iconId)
.createItem();
addItem(internalStorageItem);
//shared_storage
dir = settings.getDefaultInternalStorage();
path = dir.getAbsolutePath();
iconId = R.drawable.ic_action_phone;
DataStorageMenuItem sharedStorageItem = DataStorageMenuItem.builder()
.setKey(SHARED_STORAGE)
.setTitle(app.getString(R.string.storage_directory_shared))
.setDirectory(path)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_DEFAULT)
.setIconResId(iconId)
.createItem();
addItem(sharedStorageItem);
//external storage
File[] externals = app.getExternalFilesDirs(null);
if (externals != null) {
int i = 0;
for (File external : externals) {
if (external != null) {
++i;
dir = external;
path = dir.getAbsolutePath();
iconId = getIconForStorageType(dir);
DataStorageMenuItem externalStorageItem = DataStorageMenuItem.builder()
.setKey(EXTERNAL_STORAGE + i)
.setTitle(app.getString(R.string.storage_directory_external) + " " + i)
.setDirectory(path)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_EXTERNAL_FILE)
.setIconResId(iconId)
.createItem();
addItem(externalStorageItem);
}
}
}
//multi user storage
File[] obbDirs = app.getObbDirs();
if (obbDirs != null) {
int i = 0;
for (File obb : obbDirs) {
if (obb != null) {
++i;
dir = obb;
path = dir.getAbsolutePath();
iconId = getIconForStorageType(dir);
DataStorageMenuItem multiuserStorageItem = DataStorageMenuItem.builder()
.setKey(MULTIUSER_STORAGE + i)
.setTitle(app.getString(R.string.storage_directory_multiuser) + " " + i)
.setDirectory(path)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_OBB)
.setIconResId(iconId)
.createItem();
addItem(multiuserStorageItem);
}
}
}
}
//manually specified storage
manuallySpecified = DataStorageMenuItem.builder()
.setKey(MANUALLY_SPECIFIED)
.setTitle(app.getString(R.string.storage_directory_manual))
.setDirectory(currentStoragePath)
.setType(OsmandSettings.EXTERNAL_STORAGE_TYPE_SPECIFIED)
.setIconResId(R.drawable.ic_action_folder)
.createItem();
menuItems.add(manuallySpecified);
if (currentDataStorage == null) {
currentDataStorage = manuallySpecified;
}
initMemoryUsed(app);
}
private void initMemoryUsed(OsmandApplication app) {
mapsMemory = DataStorageMemoryItem.builder()
.setKey(MAPS_MEMORY)
.setExtensions(IndexConstants.BINARY_MAP_INDEX_EXT)
.setDirectories(
new Directory(app.getAppPath(IndexConstants.MAPS_PATH).getAbsolutePath(), false, EXTENSIONS, false),
new Directory(app.getAppPath(IndexConstants.ROADS_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
new Directory(app.getAppPath(IndexConstants.WIKI_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
new Directory(app.getAppPath(IndexConstants.WIKIVOYAGE_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
new Directory(app.getAppPath(IndexConstants.BACKUP_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
.createItem();
memoryItems.add(mapsMemory);
srtmAndHillshadeMemory = DataStorageMemoryItem.builder()
.setKey(SRTM_AND_HILLSHADE_MEMORY)
.setExtensions(IndexConstants.BINARY_SRTM_MAP_INDEX_EXT)
.setDirectories(
new Directory(app.getAppPath(IndexConstants.SRTM_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false),
new Directory(app.getAppPath(IndexConstants.TILES_INDEX_DIR).getAbsolutePath(), false, PREFIX, true))
.setPrefixes("Hillshade")
.createItem();
memoryItems.add(srtmAndHillshadeMemory);
tracksMemory = DataStorageMemoryItem.builder()
.setKey(TRACKS_MEMORY)
// .setExtensions(IndexConstants.GPX_FILE_EXT, ".gpx.bz2")
.setDirectories(
new Directory(app.getAppPath(IndexConstants.GPX_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
.createItem();
memoryItems.add(tracksMemory);
notesMemory = DataStorageMemoryItem.builder()
.setKey(NOTES_MEMORY)
// .setExtensions("")
.setDirectories(
new Directory(app.getAppPath(IndexConstants.AV_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
.createItem();
memoryItems.add(notesMemory);
tilesMemory = DataStorageMemoryItem.builder()
.setKey(TILES_MEMORY)
// .setExtensions("")
.setDirectories(
new Directory(app.getAppPath(IndexConstants.TILES_INDEX_DIR).getAbsolutePath(), true, EXTENSIONS, false))
.createItem();
memoryItems.add(tilesMemory);
otherMemory = DataStorageMemoryItem.builder()
.setKey(OTHER_MEMORY)
.createItem();
memoryItems.add(otherMemory);
}
public ArrayList<DataStorageMenuItem> getStorageItems() {
return menuItems;
}
private int getIconForStorageType(File dir) {
return R.drawable.ic_action_folder;
}
public DataStorageMenuItem getCurrentStorage() {
return currentDataStorage;
}
private void addItem(DataStorageMenuItem item) {
if (currentStorageType == item.getType() && currentStoragePath.equals(item.getDirectory())) {
currentDataStorage = item;
}
menuItems.add(item);
}
public DataStorageMenuItem getManuallySpecified() {
return manuallySpecified;
}
public DataStorageMenuItem getStorage(String key) {
if (menuItems != null && key != null) {
for (DataStorageMenuItem menuItem : menuItems) {
if (key.equals(menuItem.getKey())) {
return menuItem;
}
}
}
return null;
}
public int getCurrentType() {
return currentStorageType;
}
public String getCurrentPath() {
return currentStoragePath;
}
public ArrayList<DataStorageMemoryItem> getMemoryInfoItems() {
return memoryItems;
}
public RefreshMemoryUsedInfo calculateMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener) {
File rootDir = new File(currentStoragePath);
RefreshMemoryUsedInfo task = new RefreshMemoryUsedInfo(listener, otherMemory, rootDir, null, null, OTHER_MEMORY);
task.execute(mapsMemory, srtmAndHillshadeMemory, tracksMemory, notesMemory);
return task;
}
public RefreshMemoryUsedInfo calculateTilesMemoryUsed(UpdateMemoryInfoUIAdapter listener) {
File rootDir = new File(tilesMemory.getDirectories()[0].getAbsolutePath());
RefreshMemoryUsedInfo task = new RefreshMemoryUsedInfo(listener, otherMemory, rootDir, null, srtmAndHillshadeMemory.getPrefixes(), TILES_MEMORY);
task.execute(tilesMemory);
return task;
}
public static class RefreshMemoryUsedInfo extends AsyncTask<DataStorageMemoryItem, Void, Void> {
private UpdateMemoryInfoUIAdapter listener;
private File rootDir;
private DataStorageMemoryItem otherMemory;
private String[] directoriesToAvoid;
private String[] prefixesToAvoid;
private String taskKey;
private long lastRefreshTime;
public RefreshMemoryUsedInfo(UpdateMemoryInfoUIAdapter listener, DataStorageMemoryItem otherMemory, File rootDir, String[] directoriesToAvoid, String[] prefixesToAvoid, String taskKey) {
this.listener = listener;
this.otherMemory = otherMemory;
this.rootDir = rootDir;
this.directoriesToAvoid = directoriesToAvoid;
this.prefixesToAvoid = prefixesToAvoid;
this.taskKey = taskKey;
}
@Override
protected Void doInBackground(DataStorageMemoryItem... items) {
lastRefreshTime = System.currentTimeMillis();
if (rootDir.canRead()) {
calculateMultiTypes(rootDir, items);
}
return null;
}
private void calculateMultiTypes(File rootDir, DataStorageMemoryItem... items) {
File[] subFiles = rootDir.listFiles();
for (File file : subFiles) {
if (isCancelled()) {
break;
}
nextFile : {
if (file.isDirectory()) {
//check current directory should be avoid
if (directoriesToAvoid != null) {
for (String directoryToAvoid : directoriesToAvoid) {
if (file.getAbsolutePath().equals(directoryToAvoid)) {
break nextFile;
}
}
}
//check current directory matched items type
for (DataStorageMemoryItem item : items) {
Directory[] directories = item.getDirectories();
if (directories == null) {
continue;
}
for (Directory dir : directories) {
if (file.getAbsolutePath().equals(dir.getAbsolutePath())
|| (file.getAbsolutePath().startsWith(dir.getAbsolutePath()))) {
if (dir.isGoDeeper()) {
calculateMultiTypes(file, items);
break nextFile;
} else if (dir.isSkipOther()) {
break nextFile;
}
}
}
}
//current directory did not match to any type
otherMemory.addBytes(getDirectorySize(file));
} else if (file.isFile()) {
//check current file should be avoid
if (prefixesToAvoid != null) {
for (String prefixToAvoid : prefixesToAvoid) {
if (file.getName().toLowerCase().startsWith(prefixToAvoid.toLowerCase())) {
break nextFile;
}
}
}
//check current file matched items type
for (DataStorageMemoryItem item : items) {
Directory[] directories = item.getDirectories();
if (directories == null) {
continue;
}
for (Directory dir : directories) {
if (rootDir.getAbsolutePath().equals(dir.getAbsolutePath())
|| (rootDir.getAbsolutePath().startsWith(dir.getAbsolutePath()) && dir.isGoDeeper())) {
int checkingType = dir.getCheckingType();
switch (checkingType) {
case EXTENSIONS : {
String[] extensions = item.getExtensions();
if (extensions != null) {
for (String extension : extensions) {
if (file.getAbsolutePath().endsWith(extension)) {
item.addBytes(file.length());
break nextFile;
}
}
} else {
item.addBytes(file.length());
break nextFile;
}
break ;
}
case PREFIX : {
String[] prefixes = item.getPrefixes();
if (prefixes != null) {
for (String prefix : prefixes) {
if (file.getName().toLowerCase().startsWith(prefix.toLowerCase())) {
item.addBytes(file.length());
break nextFile;
}
}
} else {
item.addBytes(file.length());
break nextFile;
}
break ;
}
}
if (dir.isSkipOther()) {
break nextFile;
}
}
}
}
//current file did not match any type
otherMemory.addBytes(file.length());
}
}
refreshUI();
}
}
private long getDirectorySize(File dir) {
long bytes = 0;
if (dir.isDirectory()) {
File[] files = dir.listFiles();
for (File file : files) {
if (isCancelled()) {
break;
}
if (file.isDirectory()) {
bytes += getDirectorySize(file);
} else if (file.isFile()) {
bytes += file.length();
}
}
}
return bytes;
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
if (listener != null) {
listener.onMemoryInfoUpdate();
}
}
@Override
protected void onPostExecute(Void aVoid) {
super.onPostExecute(aVoid);
if (listener != null) {
listener.onFinishUpdating(taskKey);
}
}
private void refreshUI() {
long currentTime = System.currentTimeMillis();
if ((currentTime - lastRefreshTime) > UI_REFRESH_TIME_MS) {
lastRefreshTime = currentTime;
publishProgress();
}
}
}
public long getTotalUsedBytes() {
long total = 0;
if (memoryItems != null && memoryItems.size() > 0) {
for (DataStorageMemoryItem mi : memoryItems) {
total += mi.getUsedMemoryBytes();
}
return total;
}
return -1;
}
public static String getFormattedMemoryInfo(long bytes, String[] formatStrings) {
int type = 0;
double memory = (double) bytes / 1024;
while (memory > 1024 && type < formatStrings.length) {
++type;
memory = memory / 1024;
}
String formattedUsed = new DecimalFormat("#.##").format(memory);
return String.format(formatStrings[type], formattedUsed);
}
public interface UpdateMemoryInfoUIAdapter {
void onMemoryInfoUpdate();
void onFinishUpdating(String taskKey);
}
}

View file

@ -34,6 +34,7 @@ import net.osmand.plus.settings.backend.ApplicationMode.ApplicationModeBean;
import net.osmand.util.Algorithms;
import org.apache.commons.logging.Log;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.List;
@ -91,7 +92,11 @@ public class DuplicatesSettingsAdapter extends RecyclerView.Adapter<RecyclerView
String profileName = modeBean.userProfileName;
if (Algorithms.isEmpty(profileName)) {
ApplicationMode appMode = ApplicationMode.valueOfStringKey(modeBean.stringKey, null);
profileName = app.getString(appMode.getNameKeyResource());
if (appMode != null) {
profileName = appMode.toHumanString();
} else {
profileName = StringUtils.capitalize(modeBean.stringKey);
}
}
itemHolder.title.setText(profileName);
String routingProfile = "";

View file

@ -62,6 +62,7 @@ import net.osmand.util.Algorithms;
import net.osmand.view.ThreeStateCheckbox;
import org.apache.commons.logging.Log;
import org.apache.commons.lang3.StringUtils;
import java.io.File;
import java.util.ArrayList;
@ -279,7 +280,11 @@ public class ExportItemsBottomSheet extends MenuBottomSheetDialogFragment {
String profileName = modeBean.userProfileName;
if (Algorithms.isEmpty(profileName)) {
ApplicationMode appMode = ApplicationMode.valueOfStringKey(modeBean.stringKey, null);
profileName = appMode.toHumanString();
if (appMode != null) {
profileName = appMode.toHumanString();
} else {
profileName = StringUtils.capitalize(modeBean.stringKey);
}
}
builder.setTitle(profileName);

View file

@ -22,6 +22,8 @@ import net.osmand.plus.profiles.SelectProfileBottomSheet.DialogMode;
import net.osmand.plus.profiles.SelectProfileBottomSheet.OnSelectProfileCallback;
import net.osmand.plus.settings.backend.ApplicationMode;
import net.osmand.plus.settings.backend.OsmandSettings;
import net.osmand.plus.settings.datastorage.DataStorageHelper;
import net.osmand.plus.settings.datastorage.item.StorageItem;
import net.osmand.plus.settings.preferences.ListPreferenceEx;
import net.osmand.plus.settings.preferences.SwitchPreferenceEx;
@ -181,7 +183,7 @@ public class GlobalSettingsFragment extends BaseSettingsFragment
externalStorageDir.setIcon(getActiveIcon(R.drawable.ic_action_folder));
DataStorageHelper holder = new DataStorageHelper(app);
DataStorageMenuItem currentStorage = holder.getCurrentStorage();
StorageItem currentStorage = holder.getCurrentStorage();
long totalUsed = app.getSettings().OSMAND_USAGE_SPACE.get();
if (totalUsed > 0) {
String[] usedMemoryFormats = new String[] {

View file

@ -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();
}
@ -1130,7 +1128,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, null);
}
}
if (progress != null && AndroidUtils.isActivityNotDestroyed(mapActivity)) {
progress.dismiss();
@ -1142,7 +1142,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

@ -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

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Osmand-Nautical</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Osmand-ParkingPlugin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

View file

@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.DEPENDENCIES"/>
<classpathentry kind="output" path="bin/classes"/>
</classpath>

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Osmand-SRTMPlugin</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>com.android.ide.eclipse.adt.ResourceManagerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.PreCompilerBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.android.ide.eclipse.adt.ApkBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>com.android.ide.eclipse.adt.AndroidNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>

Some files were not shown because too many files have changed in this diff Show more