diff --git a/OsmAnd-telegram/res/drawable/btn_round_border.xml b/OsmAnd-telegram/res/drawable/btn_round_border.xml
new file mode 100644
index 0000000000..ae932320c8
--- /dev/null
+++ b/OsmAnd-telegram/res/drawable/btn_round_border.xml
@@ -0,0 +1,24 @@
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OsmAnd-telegram/res/layout/fragment_timeline_tab.xml b/OsmAnd-telegram/res/layout/fragment_timeline_tab.xml
new file mode 100644
index 0000000000..957b6db002
--- /dev/null
+++ b/OsmAnd-telegram/res/layout/fragment_timeline_tab.xml
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OsmAnd-telegram/res/layout/fragment_user_gpx_info.xml b/OsmAnd-telegram/res/layout/fragment_user_gpx_info.xml
new file mode 100644
index 0000000000..b10ec52cd8
--- /dev/null
+++ b/OsmAnd-telegram/res/layout/fragment_user_gpx_info.xml
@@ -0,0 +1,509 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/OsmAnd-telegram/res/menu/bottom_navigation_menu.xml b/OsmAnd-telegram/res/menu/bottom_navigation_menu.xml
index ba71c44bc8..d12e0981d5 100644
--- a/OsmAnd-telegram/res/menu/bottom_navigation_menu.xml
+++ b/OsmAnd-telegram/res/menu/bottom_navigation_menu.xml
@@ -9,4 +9,9 @@
android:id="@+id/action_live_now"
android:icon="@drawable/ic_action_live_now"
android:title="@string/live_now"/>
+
+
\ No newline at end of file
diff --git a/OsmAnd-telegram/res/values-ru/strings.xml b/OsmAnd-telegram/res/values-ru/strings.xml
index ce07a813e2..7896e335c8 100644
--- a/OsmAnd-telegram/res/values-ru/strings.xml
+++ b/OsmAnd-telegram/res/values-ru/strings.xml
@@ -1,5 +1,6 @@
+ Включите мониторинг, для сбора данных о перемещении в фоновом режиме.
Последнее обновление в Telegram
Имя устройства
Спрятать
diff --git a/OsmAnd-telegram/res/values/strings.xml b/OsmAnd-telegram/res/values/strings.xml
index 3e134ade9b..c7586500ca 100644
--- a/OsmAnd-telegram/res/values/strings.xml
+++ b/OsmAnd-telegram/res/values/strings.xml
@@ -1,4 +1,13 @@
+ Monitoring is enabled
+ Monitoring is disabled
+ time on the move
+ Average altitude
+ Average speed
+ Open in OsmAnd
+ End date
+ Start date
+ Enable monitoring to collect movement data in the background.
Send location as
Choose how messages with your location will look like.
Map
@@ -176,6 +185,7 @@
OsmAnd Location Sharing lets you share your location and see that of others in the OsmAnd.
The app uses Telegram API and you need a Telegram account.]]>
My location
Live now
+ Timeline
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlCallback.aidl b/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlCallback.aidl
index be010bb062..6f0cb8f65b 100644
--- a/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlCallback.aidl
+++ b/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlCallback.aidl
@@ -1,9 +1,14 @@
package net.osmand.aidl;
import net.osmand.aidl.search.SearchResult;
+import net.osmand.aidl.gpx.AGpxBitmap;
interface IOsmAndAidlCallback {
void onSearchComplete(in List resultSet);
void onUpdate();
+
+ void onAppInitialized();
+
+ void onGpxBitmapCreated(in AGpxBitmap bitmap);
}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlInterface.aidl b/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlInterface.aidl
index d7ebb4492d..59fd213ab6 100644
--- a/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlInterface.aidl
+++ b/OsmAnd-telegram/src/net/osmand/aidl/IOsmAndAidlInterface.aidl
@@ -55,6 +55,9 @@ import net.osmand.aidl.maplayer.point.ShowMapPointParams;
import net.osmand.aidl.navdrawer.SetNavDrawerItemsParams;
+import net.osmand.aidl.navdrawer.NavDrawerFooterParams;
+import net.osmand.aidl.navdrawer.NavDrawerHeaderParams;
+
import net.osmand.aidl.navigation.PauseNavigationParams;
import net.osmand.aidl.navigation.ResumeNavigationParams;
import net.osmand.aidl.navigation.StopNavigationParams;
@@ -67,6 +70,16 @@ import net.osmand.aidl.search.SearchResult;
import net.osmand.aidl.search.SearchParams;
import net.osmand.aidl.navigation.NavigateSearchParams;
+import net.osmand.aidl.customization.SetWidgetsParams;
+import net.osmand.aidl.customization.OsmandSettingsParams;
+
+import net.osmand.aidl.gpx.AGpxFile;
+import net.osmand.aidl.gpx.AGpxFileDetails;
+import net.osmand.aidl.gpx.CreateGpxBitmapParams;
+import net.osmand.aidl.tiles.ASqliteDbFile;
+
+import net.osmand.aidl.plugins.PluginParams;
+
// NOTE: Add new methods at the end of file!!!
interface IOsmAndAidlInterface {
@@ -133,4 +146,34 @@ interface IOsmAndAidlInterface {
long registerForUpdates(in long updateTimeMS, IOsmAndAidlCallback callback);
boolean unregisterFromUpdates(in long callbackId);
+
+ boolean setNavDrawerLogo(in String imageUri);
+
+ boolean setEnabledIds(in List ids);
+ boolean setDisabledIds(in List ids);
+ boolean setEnabledPatterns(in List patterns);
+ boolean setDisabledPatterns(in List patterns);
+
+ boolean regWidgetVisibility(in SetWidgetsParams params);
+ boolean regWidgetAvailability(in SetWidgetsParams params);
+
+ boolean customizeOsmandSettings(in OsmandSettingsParams params);
+
+ boolean getImportedGpx(out List files);
+
+ boolean getSqliteDbFiles(out List files);
+ boolean getActiveSqliteDbFiles(out List files);
+ boolean showSqliteDbFile(String fileName);
+ boolean hideSqliteDbFile(String fileName);
+
+ boolean setNavDrawerLogoWithParams(in NavDrawerHeaderParams params);
+ boolean setNavDrawerFooterWithParams(in NavDrawerFooterParams params);
+
+ boolean restoreOsmand();
+
+ boolean changePluginState(in PluginParams params);
+
+ boolean registerForOsmandInitListener(in IOsmAndAidlCallback callback);
+
+ boolean getBitmapForGpx(in CreateGpxBitmapParams file, IOsmAndAidlCallback callback);
}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/customization/OsmandSettingsParams.aidl b/OsmAnd-telegram/src/net/osmand/aidl/customization/OsmandSettingsParams.aidl
new file mode 100644
index 0000000000..770070bb46
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/customization/OsmandSettingsParams.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.customization;
+
+parcelable OsmandSettingsParams;
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/customization/OsmandSettingsParams.java b/OsmAnd-telegram/src/net/osmand/aidl/customization/OsmandSettingsParams.java
new file mode 100644
index 0000000000..bff8c68018
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/customization/OsmandSettingsParams.java
@@ -0,0 +1,60 @@
+package net.osmand.aidl.customization;
+
+import android.annotation.SuppressLint;
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class OsmandSettingsParams implements Parcelable {
+
+ private String sharedPreferencesName;
+ private Bundle bundle;
+
+ public OsmandSettingsParams(@NonNull String sharedPreferencesName, @Nullable Bundle bundle) {
+ this.sharedPreferencesName = sharedPreferencesName;
+ this.bundle = bundle;
+ }
+
+ public OsmandSettingsParams(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public OsmandSettingsParams createFromParcel(Parcel in) {
+ return new OsmandSettingsParams(in);
+ }
+
+ @Override
+ public OsmandSettingsParams[] newArray(int size) {
+ return new OsmandSettingsParams[size];
+ }
+ };
+
+ public String getSharedPreferencesName() {
+ return sharedPreferencesName;
+ }
+
+ public Bundle getBundle() {
+ return bundle;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(sharedPreferencesName);
+ out.writeBundle(bundle);
+ }
+
+ @SuppressLint("ParcelClassLoader")
+ private void readFromParcel(Parcel in) {
+ sharedPreferencesName = in.readString();
+ bundle = in.readBundle();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/customization/SetWidgetsParams.aidl b/OsmAnd-telegram/src/net/osmand/aidl/customization/SetWidgetsParams.aidl
new file mode 100644
index 0000000000..235a4abe51
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/customization/SetWidgetsParams.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.customization;
+
+parcelable SetWidgetsParams;
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/customization/SetWidgetsParams.java b/OsmAnd-telegram/src/net/osmand/aidl/customization/SetWidgetsParams.java
new file mode 100644
index 0000000000..d9343b920e
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/customization/SetWidgetsParams.java
@@ -0,0 +1,93 @@
+package net.osmand.aidl.customization;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class SetWidgetsParams implements Parcelable {
+
+ private String widgetKey;
+ private List appModesKeys;
+
+ public SetWidgetsParams(String widgetKey, @Nullable List appModesKeys) {
+ this.widgetKey = widgetKey;
+ this.appModesKeys = appModesKeys;
+ }
+
+ public SetWidgetsParams(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public SetWidgetsParams createFromParcel(Parcel in) {
+ return new SetWidgetsParams(in);
+ }
+
+ @Override
+ public SetWidgetsParams[] newArray(int size) {
+ return new SetWidgetsParams[size];
+ }
+ };
+
+ public String getWidgetKey() {
+ return widgetKey;
+ }
+
+ public List getAppModesKeys() {
+ return appModesKeys;
+ }
+
+ @Override
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(widgetKey);
+ writeStringList(out, appModesKeys);
+ }
+
+ private void readFromParcel(Parcel in) {
+ widgetKey = in.readString();
+ appModesKeys = readStringList(in);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ private void writeStringList(Parcel out, List val) {
+ if (val == null) {
+ out.writeInt(-1);
+ return;
+ }
+ int N = val.size();
+ int i = 0;
+ out.writeInt(N);
+ while (i < N) {
+ out.writeString(val.get(i));
+ i++;
+ }
+ }
+
+ private List readStringList(Parcel in) {
+ List list = new ArrayList<>();
+ int M = list.size();
+ int N = in.readInt();
+ if (N == -1) {
+ return null;
+ }
+ int i = 0;
+ for (; i < M && i < N; i++) {
+ list.set(i, in.readString());
+ }
+ for (; i < N; i++) {
+ list.add(in.readString());
+ }
+ for (; i < M; i++) {
+ list.remove(N);
+ }
+ return list;
+ }
+}
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxBitmap.aidl b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxBitmap.aidl
new file mode 100644
index 0000000000..128f5e6b94
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxBitmap.aidl
@@ -0,0 +1,4 @@
+package net.osmand.aidl.gpx;
+
+parcelable AGpxBitmap;
+
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxBitmap.java b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxBitmap.java
new file mode 100644
index 0000000000..2f423e126e
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxBitmap.java
@@ -0,0 +1,50 @@
+package net.osmand.aidl.gpx;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+
+public class AGpxBitmap implements Parcelable {
+
+ private Bitmap bitmap;
+
+ public AGpxBitmap(@NonNull Bitmap bitmap) {
+ this.bitmap = bitmap;
+ }
+
+ public AGpxBitmap(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+
+ public void setBitmap(Bitmap bitmap) {
+ this.bitmap = bitmap;
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public AGpxBitmap createFromParcel(Parcel in) {
+ return new AGpxBitmap(in);
+ }
+
+ public AGpxBitmap[] newArray(int size) {
+ return new AGpxBitmap[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(bitmap, flags);
+ }
+
+ private void readFromParcel(Parcel in) {
+ bitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFile.aidl b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFile.aidl
new file mode 100644
index 0000000000..413d34a571
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFile.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.gpx;
+
+parcelable AGpxFile;
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFile.java b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFile.java
new file mode 100644
index 0000000000..9572057fdc
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFile.java
@@ -0,0 +1,89 @@
+package net.osmand.aidl.gpx;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class AGpxFile implements Parcelable {
+
+ private String fileName;
+ private long modifiedTime;
+ private long fileSize;
+ private boolean active;
+ private AGpxFileDetails details;
+
+ public AGpxFile(@NonNull String fileName, long modifiedTime, long fileSize, boolean active, @Nullable AGpxFileDetails details) {
+ this.fileName = fileName;
+ this.modifiedTime = modifiedTime;
+ this.fileSize = fileSize;
+ this.active = active;
+ this.details = details;
+ }
+
+ public AGpxFile(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public AGpxFile createFromParcel(Parcel in) {
+ return new AGpxFile(in);
+ }
+
+ public AGpxFile[] newArray(int size) {
+ return new AGpxFile[size];
+ }
+ };
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public long getModifiedTime() {
+ return modifiedTime;
+ }
+
+ public long getFileSize() {
+ return fileSize;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public AGpxFileDetails getDetails() {
+ return details;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(fileName);
+ out.writeLong(modifiedTime);
+ out.writeLong(fileSize);
+ out.writeByte((byte) (active ? 1 : 0));
+
+ out.writeByte((byte) (details != null ? 1 : 0));
+ if (details != null) {
+ out.writeParcelable(details, flags);
+ }
+ }
+
+ private void readFromParcel(Parcel in) {
+ fileName = in.readString();
+ modifiedTime = in.readLong();
+ fileSize = in.readLong();
+ active = in.readByte() != 0;
+
+ boolean hasDetails= in.readByte() != 0;
+ if (hasDetails) {
+ details = in.readParcelable(AGpxFileDetails.class.getClassLoader());
+ } else {
+ details = null;
+ }
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
+
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFileDetails.aidl b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFileDetails.aidl
new file mode 100644
index 0000000000..1e2cdec2b1
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFileDetails.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.gpx;
+
+parcelable AGpxFileDetails;
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFileDetails.java b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFileDetails.java
new file mode 100644
index 0000000000..3fe755135e
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/AGpxFileDetails.java
@@ -0,0 +1,196 @@
+package net.osmand.aidl.gpx;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
+public class AGpxFileDetails implements Parcelable {
+
+ private float totalDistance = 0;
+ private int totalTracks = 0;
+ private long startTime = Long.MAX_VALUE;
+ private long endTime = Long.MIN_VALUE;
+ private long timeSpan = 0;
+ private long timeMoving = 0;
+ private float totalDistanceMoving = 0;
+
+ private double diffElevationUp = 0;
+ private double diffElevationDown = 0;
+ private double avgElevation = 0;
+ private double minElevation = 99999;
+ private double maxElevation = -100;
+
+ private float minSpeed = Float.MAX_VALUE;
+ private float maxSpeed = 0;
+ private float avgSpeed;
+
+ private int points;
+ private int wptPoints = 0;
+
+ private List wptCategoryNames = new ArrayList<>();
+
+ public AGpxFileDetails(float totalDistance, int totalTracks,
+ long startTime, long endTime,
+ long timeSpan, long timeMoving, float totalDistanceMoving,
+ double diffElevationUp, double diffElevationDown,
+ double avgElevation, double minElevation, double maxElevation,
+ float minSpeed, float maxSpeed, float avgSpeed,
+ int points, int wptPoints, Set wptCategoryNames) {
+ this.totalDistance = totalDistance;
+ this.totalTracks = totalTracks;
+ this.startTime = startTime;
+ this.endTime = endTime;
+ this.timeSpan = timeSpan;
+ this.timeMoving = timeMoving;
+ this.totalDistanceMoving = totalDistanceMoving;
+ this.diffElevationUp = diffElevationUp;
+ this.diffElevationDown = diffElevationDown;
+ this.avgElevation = avgElevation;
+ this.minElevation = minElevation;
+ this.maxElevation = maxElevation;
+ this.minSpeed = minSpeed;
+ this.maxSpeed = maxSpeed;
+ this.avgSpeed = avgSpeed;
+ this.points = points;
+ this.wptPoints = wptPoints;
+ if (wptCategoryNames != null) {
+ this.wptCategoryNames = new ArrayList<>(wptCategoryNames);
+ }
+ }
+
+ public AGpxFileDetails(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public AGpxFileDetails createFromParcel(Parcel in) {
+ return new AGpxFileDetails(in);
+ }
+
+ public AGpxFileDetails[] newArray(int size) {
+ return new AGpxFileDetails[size];
+ }
+ };
+
+ public float getTotalDistance() {
+ return totalDistance;
+ }
+
+ public int getTotalTracks() {
+ return totalTracks;
+ }
+
+ public long getStartTime() {
+ return startTime;
+ }
+
+ public long getEndTime() {
+ return endTime;
+ }
+
+ public long getTimeSpan() {
+ return timeSpan;
+ }
+
+ public long getTimeMoving() {
+ return timeMoving;
+ }
+
+ public float getTotalDistanceMoving() {
+ return totalDistanceMoving;
+ }
+
+ public double getDiffElevationUp() {
+ return diffElevationUp;
+ }
+
+ public double getDiffElevationDown() {
+ return diffElevationDown;
+ }
+
+ public double getAvgElevation() {
+ return avgElevation;
+ }
+
+ public double getMinElevation() {
+ return minElevation;
+ }
+
+ public double getMaxElevation() {
+ return maxElevation;
+ }
+
+ public float getMinSpeed() {
+ return minSpeed;
+ }
+
+ public float getMaxSpeed() {
+ return maxSpeed;
+ }
+
+ public float getAvgSpeed() {
+ return avgSpeed;
+ }
+
+ public int getPoints() {
+ return points;
+ }
+
+ public int getWptPoints() {
+ return wptPoints;
+ }
+
+ public List getWptCategoryNames() {
+ return wptCategoryNames;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeFloat(totalDistance);
+ out.writeInt(totalTracks);
+ out.writeLong(startTime);
+ out.writeLong(endTime);
+ out.writeLong(timeSpan);
+ out.writeLong(timeMoving);
+ out.writeFloat(totalDistanceMoving);
+ out.writeDouble(diffElevationUp);
+ out.writeDouble(diffElevationDown);
+ out.writeDouble(avgElevation);
+ out.writeDouble(minElevation);
+ out.writeDouble(maxElevation);
+ out.writeFloat(minSpeed);
+ out.writeFloat(maxSpeed);
+ out.writeFloat(avgSpeed);
+ out.writeInt(points);
+ out.writeInt(wptPoints);
+ out.writeStringList(wptCategoryNames);
+ }
+
+ private void readFromParcel(Parcel in) {
+ totalDistance = in.readFloat();
+ totalTracks = in.readInt();
+ startTime = in.readLong();
+ endTime = in.readLong();
+ timeSpan = in.readLong();
+ timeMoving = in.readLong();
+ totalDistanceMoving = in.readFloat();
+ diffElevationUp = in.readDouble();
+ diffElevationDown = in.readDouble();
+ avgElevation = in.readDouble();
+ minElevation = in.readDouble();
+ maxElevation = in.readDouble();
+ minSpeed = in.readFloat();
+ maxSpeed = in.readFloat();
+ avgSpeed = in.readFloat();
+ points = in.readInt();
+ wptPoints = in.readInt();
+ in.readStringList(wptCategoryNames);
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.aidl b/OsmAnd-telegram/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.aidl
new file mode 100644
index 0000000000..b02d5c6e70
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.gpx;
+
+parcelable CreateGpxBitmapParams;
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.java b/OsmAnd-telegram/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.java
new file mode 100644
index 0000000000..b6af1d354c
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.java
@@ -0,0 +1,101 @@
+package net.osmand.aidl.gpx;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.File;
+
+public class CreateGpxBitmapParams implements Parcelable {
+
+ private File gpxFile;
+ private Uri gpxUri;
+ private float density;
+ private int widthPixels;
+ private int heightPixels;
+ private int color; //ARGB color int
+
+ public CreateGpxBitmapParams(File gpxFile, float density, int widthPixels, int heightPixels, int color) {
+ this.gpxFile = gpxFile;
+ this.density = density;
+ this.widthPixels = widthPixels;
+ this.heightPixels = heightPixels;
+ this.color = color;
+ }
+
+ public CreateGpxBitmapParams(Uri gpxUri, float density, int widthPixels, int heightPixels, int color) {
+ this.gpxUri = gpxUri;
+ this.density = density;
+ this.widthPixels = widthPixels;
+ this.heightPixels = heightPixels;
+ this.color = color;
+ }
+
+ public CreateGpxBitmapParams(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public CreateGpxBitmapParams createFromParcel(Parcel in) {
+ return new CreateGpxBitmapParams(in);
+ }
+
+ public CreateGpxBitmapParams[] newArray(int size) {
+ return new CreateGpxBitmapParams[size];
+ }
+ };
+
+ public File getGpxFile() {
+ return gpxFile;
+ }
+
+ public Uri getGpxUri() {
+ return gpxUri;
+ }
+
+ public int getWidthPixels() {
+ return widthPixels;
+ }
+
+ public int getHeightPixels() {
+ return heightPixels;
+ }
+
+ public float getDensity() {
+ return density;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ if (gpxFile != null) {
+ out.writeString(gpxFile.getAbsolutePath());
+ } else {
+ out.writeString(null);
+ }
+ out.writeParcelable(gpxUri, flags);
+ out.writeFloat(density);
+ out.writeInt(widthPixels);
+ out.writeInt(heightPixels);
+ out.writeInt(color);
+ }
+
+ private void readFromParcel(Parcel in) {
+ String gpxAbsolutePath = in.readString();
+ if (gpxAbsolutePath != null) {
+ gpxFile = new File(gpxAbsolutePath);
+ }
+ gpxUri = in.readParcelable(Uri.class.getClassLoader());
+ density = in.readFloat();
+ widthPixels = in.readInt();
+ heightPixels = in.readInt();
+ color = in.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerFooterParams.aidl b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerFooterParams.aidl
new file mode 100644
index 0000000000..fc1271a8ca
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerFooterParams.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.navdrawer;
+
+parcelable NavDrawerFooterParams;
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerFooterParams.java b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerFooterParams.java
new file mode 100644
index 0000000000..9bfd70193f
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerFooterParams.java
@@ -0,0 +1,68 @@
+package net.osmand.aidl.navdrawer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class NavDrawerFooterParams implements Parcelable {
+
+ @NonNull
+ private String packageName;
+ @Nullable
+ private String intent;
+ @Nullable
+ private String appName;
+
+ @NonNull
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @Nullable
+ public String getIntent() {
+ return intent;
+ }
+
+ @Nullable
+ public String getAppName() {
+ return appName;
+ }
+
+ public NavDrawerFooterParams(@NonNull String packageName, @Nullable String intent,
+ @Nullable String appName) {
+ this.packageName = packageName;
+ this.intent = intent;
+ this.appName = appName;
+ }
+
+ protected NavDrawerFooterParams(Parcel in) {
+ packageName = in.readString();
+ intent = in.readString();
+ appName = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(packageName);
+ dest.writeString(intent);
+ dest.writeString(appName);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NavDrawerFooterParams createFromParcel(Parcel in) {
+ return new NavDrawerFooterParams(in);
+ }
+
+ @Override
+ public NavDrawerFooterParams[] newArray(int size) {
+ return new NavDrawerFooterParams[size];
+ }
+ };
+}
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerHeaderParams.aidl b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerHeaderParams.aidl
new file mode 100644
index 0000000000..c230824841
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerHeaderParams.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.navdrawer;
+
+parcelable NavDrawerHeaderParams;
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerHeaderParams.java b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerHeaderParams.java
new file mode 100644
index 0000000000..c88950fd10
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/navdrawer/NavDrawerHeaderParams.java
@@ -0,0 +1,68 @@
+package net.osmand.aidl.navdrawer;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+
+public class NavDrawerHeaderParams implements Parcelable {
+
+ @NonNull
+ private String imageUri;
+ @NonNull
+ private String packageName;
+ @Nullable
+ private String intent;
+
+ @NonNull
+ public String getImageUri() {
+ return imageUri;
+ }
+
+ @NonNull
+ public String getPackageName() {
+ return packageName;
+ }
+
+ @Nullable
+ public String getIntent() {
+ return intent;
+ }
+
+ public NavDrawerHeaderParams(@NonNull String imageUri, @NonNull String packageName,
+ @Nullable String intent) {
+ this.imageUri = imageUri;
+ this.packageName = packageName;
+ this.intent = intent;
+ }
+
+ public NavDrawerHeaderParams(Parcel in) {
+ imageUri = in.readString();
+ packageName = in.readString();
+ intent = in.readString();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(imageUri);
+ dest.writeString(packageName);
+ dest.writeString(intent);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public NavDrawerHeaderParams createFromParcel(Parcel in) {
+ return new NavDrawerHeaderParams(in);
+ }
+
+ @Override
+ public NavDrawerHeaderParams[] newArray(int size) {
+ return new NavDrawerHeaderParams[size];
+ }
+ };
+}
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/plugins/PluginParams.aidl b/OsmAnd-telegram/src/net/osmand/aidl/plugins/PluginParams.aidl
new file mode 100644
index 0000000000..beff693f5a
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/plugins/PluginParams.aidl
@@ -0,0 +1,5 @@
+// PluginParams.aidl
+package net.osmand.aidl.plugins;
+
+parcelable PluginParams;
+
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/plugins/PluginParams.java b/OsmAnd-telegram/src/net/osmand/aidl/plugins/PluginParams.java
new file mode 100644
index 0000000000..028bd8676a
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/plugins/PluginParams.java
@@ -0,0 +1,51 @@
+package net.osmand.aidl.plugins;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class PluginParams implements Parcelable {
+
+ private String pluginId;
+ private int newState; //0- off, 1 - on
+
+ public PluginParams(String pluginId, int newState) {
+ this.pluginId = pluginId;
+ this.newState = newState;
+ }
+
+ public String getPluginId() {
+ return pluginId;
+ }
+
+ public int getNewState() {
+ return newState;
+ }
+
+ protected PluginParams(Parcel in) {
+ pluginId = in.readString();
+ newState = in.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeString(pluginId);
+ dest.writeInt(newState);
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ public static final Creator CREATOR = new Creator() {
+ @Override
+ public PluginParams createFromParcel(Parcel in) {
+ return new PluginParams(in);
+ }
+
+ @Override
+ public PluginParams[] newArray(int size) {
+ return new PluginParams[size];
+ }
+ };
+}
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/tiles/ASqliteDbFile.aidl b/OsmAnd-telegram/src/net/osmand/aidl/tiles/ASqliteDbFile.aidl
new file mode 100644
index 0000000000..319cfd5035
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/tiles/ASqliteDbFile.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.tiles;
+
+parcelable ASqliteDbFile;
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/aidl/tiles/ASqliteDbFile.java b/OsmAnd-telegram/src/net/osmand/aidl/tiles/ASqliteDbFile.java
new file mode 100644
index 0000000000..ac6f5e55d2
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/aidl/tiles/ASqliteDbFile.java
@@ -0,0 +1,69 @@
+package net.osmand.aidl.tiles;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+
+public class ASqliteDbFile implements Parcelable {
+
+ private String fileName;
+ private long modifiedTime;
+ private long fileSize;
+ private boolean active;
+
+ public ASqliteDbFile(@NonNull String fileName, long modifiedTime, long fileSize, boolean active) {
+ this.fileName = fileName;
+ this.modifiedTime = modifiedTime;
+ this.fileSize = fileSize;
+ this.active = active;
+ }
+
+ public ASqliteDbFile(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public ASqliteDbFile createFromParcel(Parcel in) {
+ return new ASqliteDbFile(in);
+ }
+
+ public ASqliteDbFile[] newArray(int size) {
+ return new ASqliteDbFile[size];
+ }
+ };
+
+ public String getFileName() {
+ return fileName;
+ }
+
+ public long getModifiedTime() {
+ return modifiedTime;
+ }
+
+ public long getFileSize() {
+ return fileSize;
+ }
+
+ public boolean isActive() {
+ return active;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeString(fileName);
+ out.writeLong(modifiedTime);
+ out.writeLong(fileSize);
+ out.writeByte((byte) (active ? 1 : 0));
+ }
+
+ private void readFromParcel(Parcel in) {
+ fileName = in.readString();
+ modifiedTime = in.readLong();
+ fileSize = in.readLong();
+ active = in.readByte() != 0;
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
index a08e5763ee..8b9cb02a60 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/TelegramSettings.kt
@@ -79,6 +79,8 @@ private const val SHARE_CHATS_INFO_KEY = "share_chats_info"
private const val BATTERY_OPTIMISATION_ASKED = "battery_optimisation_asked"
+private const val MONITORING_ENABLED = "monitoring_enabled"
+
private const val SHARING_INITIALIZATION_TIME = 60 * 2L // 2 minutes
private const val GPS_UPDATE_EXPIRED_TIME = 60 * 3L // 3 minutes
@@ -111,6 +113,8 @@ class TelegramSettings(private val app: TelegramApplication) {
var batteryOptimisationAsked = false
+ var monitoringEnabled = false
+
init {
updatePrefs()
read()
@@ -435,6 +439,8 @@ class TelegramSettings(private val app: TelegramApplication) {
edit.putBoolean(BATTERY_OPTIMISATION_ASKED, batteryOptimisationAsked)
+ edit.putBoolean(MONITORING_ENABLED, monitoringEnabled)
+
val jArray = convertShareChatsInfoToJson()
if (jArray != null) {
edit.putString(SHARE_CHATS_INFO_KEY, jArray.toString())
@@ -491,6 +497,8 @@ class TelegramSettings(private val app: TelegramApplication) {
)
batteryOptimisationAsked = prefs.getBoolean(BATTERY_OPTIMISATION_ASKED,false)
+
+ monitoringEnabled = prefs.getBoolean(MONITORING_ENABLED,false)
}
private fun convertShareDevicesToJson():JSONObject?{
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt
index edac62b427..621b2cb65f 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/OsmandAidlHelper.kt
@@ -75,6 +75,12 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun onSearchComplete(resultSet: List)
}
+ private var gpxBitmapCreatedListener: GpxBitmapCreatedListener? = null
+
+ interface GpxBitmapCreatedListener {
+ fun onGpxBitmapCreated(bitmap: AGpxBitmap)
+ }
+
private val mIOsmAndAidlCallback = object : IOsmAndAidlCallback.Stub() {
@Throws(RemoteException::class)
@@ -90,12 +96,26 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
mUpdatesListener!!.update()
}
}
+
+ override fun onAppInitialized() {
+
+ }
+
+ override fun onGpxBitmapCreated(bitmap: AGpxBitmap) {
+ if (gpxBitmapCreatedListener != null) {
+ gpxBitmapCreatedListener!!.onGpxBitmapCreated(bitmap)
+ }
+ }
}
fun setSearchCompleteListener(mSearchCompleteListener: SearchCompleteListener) {
this.mSearchCompleteListener = mSearchCompleteListener
}
+ fun setGpxBitmapCreatedListener(gpxBitmapCreatedListener: GpxBitmapCreatedListener) {
+ this.gpxBitmapCreatedListener = gpxBitmapCreatedListener
+ }
+
private var mUpdatesListener: UpdatesListener? = null
interface UpdatesListener {
@@ -1059,4 +1079,16 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
}
return false
}
+
+ fun getBitmapForGpx(gpxUri: Uri, density: Float, widthPixels: Int, heightPixels: Int, color: Int): Boolean {
+ if (mIOsmAndAidlInterface != null) {
+ try {
+ app.grantUriPermission(app.settings.appToConnectPackage, gpxUri, Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ return mIOsmAndAidlInterface!!.getBitmapForGpx(CreateGpxBitmapParams(gpxUri, density, widthPixels, heightPixels, color), mIOsmAndAidlCallback)
+ } catch (e: RemoteException) {
+ e.printStackTrace()
+ }
+ }
+ return false
+ }
}
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java b/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java
index 70d91ccc96..b3c1faf20d 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/SavingTracksDbHelper.java
@@ -7,7 +7,6 @@ import android.os.AsyncTask;
import net.osmand.PlatformUtil;
import net.osmand.telegram.TelegramApplication;
-import net.osmand.telegram.ui.LiveNowTabFragment;
import net.osmand.telegram.utils.GPXUtilities;
import net.osmand.telegram.utils.GPXUtilities.GPXFile;
import net.osmand.telegram.utils.GPXUtilities.Track;
@@ -19,7 +18,6 @@ import org.drinkless.td.libcore.telegram.TdApi;
import org.jetbrains.annotations.NotNull;
import java.io.File;
-import java.lang.ref.WeakReference;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
@@ -50,7 +48,7 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
+ TRACK_COL_ALTITUDE + " double, " + TRACK_COL_SPEED + " double, " //$NON-NLS-1$ //$NON-NLS-2$
+ TRACK_COL_HDOP + " double, " + TRACK_COL_DATE + " long, " + TRACK_COL_TEXT_INFO + " int )";
- public final static Log log = PlatformUtil.getLog(SavingTracksDbHelper.class);
+ private final static Log log = PlatformUtil.getLog(SavingTracksDbHelper.class);
private final TelegramApplication app;
@@ -110,23 +108,32 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
}
}
- public void saveAsyncUserDataToGpx(LiveNowTabFragment fragment, File dir, int userId, long interval) {
- GPXFile gpxFile = app.getSavingTracksDbHelper().collectRecordedDataForUser(userId, interval);
+ public void saveUserDataToGpx(SaveGpxListener listener, File dir, int userId, long chatId, long start, long end) {
+ GPXFile gpxFile = collectRecordedDataForUserAndChat(userId, chatId, start, end);
if (gpxFile != null && !gpxFile.isEmpty()) {
- SaveGPXTrackToFileTask task = new SaveGPXTrackToFileTask(fragment, gpxFile, dir, userId);
+ SaveGPXTrackToFileTask task = new SaveGPXTrackToFileTask(app, listener, gpxFile, dir, userId);
+ task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+ }
+
+ public void saveGpx(SaveGpxListener listener, File dir, GPXFile gpxFile) {
+ if (gpxFile != null && !gpxFile.isEmpty()) {
+ SaveGPXTrackToFileTask task = new SaveGPXTrackToFileTask(app, listener, gpxFile, dir, 0);
task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
private void updateLocationMessage(TdApi.Message message) {
+ log.debug(message);
TdApi.MessageContent content = message.content;
+ int senderId = app.getTelegramHelper().getSenderMessageId(message);
if (content instanceof TdApi.MessageLocation) {
long lastTextMessageUpdate = getLastTextTrackPointTimeForUser(message.senderUserId);
long currentTime = System.currentTimeMillis();
if (lastTextMessageUpdate == 0 || currentTime - lastTextMessageUpdate < 10 * 1000) {
- log.debug("Add map message" + message.senderUserId);
+ log.debug("Add map message " + message.senderUserId);
TdApi.MessageLocation messageLocation = (TdApi.MessageLocation) content;
- insertData(message.senderUserId, message.chatId, messageLocation.location.latitude,
+ insertData(senderId, message.chatId, messageLocation.location.latitude,
messageLocation.location.longitude, 0.0, 0.0, 0.0,
Math.max(message.date, message.editDate), 0);
} else {
@@ -135,7 +142,7 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
} else if (content instanceof TelegramHelper.MessageLocation) {
log.debug("Add text message " + message.senderUserId);
TelegramHelper.MessageLocation messageLocation = (TelegramHelper.MessageLocation) content;
- insertData(message.senderUserId, message.chatId, messageLocation.getLat(), messageLocation.getLon(),
+ insertData(senderId, message.chatId, messageLocation.getLat(), messageLocation.getLon(),
messageLocation.getAltitude(), messageLocation.getSpeed(), messageLocation.getHdop(),
messageLocation.getLastUpdated() * 1000L, 1);
}
@@ -181,12 +188,12 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
return res;
}
- private GPXFile collectRecordedDataForUser(int userId, long interval) {
+ public GPXFile collectRecordedDataForUserAndChat(int userId, long chatId, long start, long end) {
GPXFile gpxFile = null;
SQLiteDatabase db = getReadableDatabase();
if (db != null && db.isOpen()) {
try {
- gpxFile = collectDBTracksForUser(db, userId, interval);
+ gpxFile = collectDBTracksForUser(db, userId, chatId, start, end);
} finally {
db.close();
}
@@ -194,21 +201,52 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
return gpxFile;
}
- private GPXFile collectDBTracksForUser(SQLiteDatabase db, int userId, long interval) {
- Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + "," + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
- + TRACK_COL_SPEED + "," + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME +
- " WHERE " + TRACK_COL_USER_ID + " = ? ORDER BY " + TRACK_COL_DATE + " ASC ", new String[]{String.valueOf(userId)}); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+ public GPXFile collectRecordedDataForUser(int userId, long chatId, long start, long end) {
+ GPXFile gpxFile = null;
+ SQLiteDatabase db = getReadableDatabase();
+ if (db != null && db.isOpen()) {
+ try {
+ if (chatId == 0) {
+ gpxFile = collectDBTracksForUser(db, userId, start, end);
+ } else {
+ gpxFile = collectDBTracksForUser(db, userId, chatId, start, end);
+ }
+ } finally {
+ db.close();
+ }
+ }
+ return gpxFile;
+ }
+
+ public ArrayList collectRecordedDataForUsers(long start, long end, ArrayList ignoredUsersIds) {
+ ArrayList data = new ArrayList<>();
+ SQLiteDatabase db = getReadableDatabase();
+ if (db != null && db.isOpen()) {
+ try {
+ collectDBTracksForUsers(db, data, start, end, ignoredUsersIds);
+ } finally {
+ db.close();
+ }
+ }
+ return data;
+ }
+
+ private GPXFile collectDBTracksForUser(SQLiteDatabase db, int userId, long chatId, long start, long end) {
+ Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + ","
+ + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," + TRACK_COL_SPEED + ","
+ + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_USER_ID + " = ?"
+ + " AND " + TRACK_COL_CHAT_ID + " = ?" + " AND " + TRACK_COL_DATE + " BETWEEN " + start + " AND " + end
+ + " ORDER BY " + TRACK_COL_DATE + " ASC ", new String[]{String.valueOf(userId), String.valueOf(chatId)});
+
GPXFile gpxFile = new GPXFile();
+ gpxFile.chatId = chatId;
+ gpxFile.userId = userId;
long previousTime = 0;
TrkSegment segment = null;
Track track = null;
if (query.moveToFirst()) {
do {
long time = query.getLong(7);
- long curTime = System.currentTimeMillis();
- if (curTime - time > interval) {
- continue;
- }
WptPt pt = new WptPt();
pt.userId = query.getInt(0);
pt.chatId = query.getLong(1);
@@ -244,19 +282,135 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
return gpxFile;
}
+ private GPXFile collectDBTracksForUser(SQLiteDatabase db, int userId, long start, long end) {
+ Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + ","
+ + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," + TRACK_COL_SPEED + ","
+ + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_USER_ID + " = ?"
+ + " AND " + TRACK_COL_DATE + " BETWEEN " + start + " AND " + end
+ + " ORDER BY " + TRACK_COL_DATE + " ASC ", new String[]{String.valueOf(userId)});
+
+ GPXFile gpxFile = new GPXFile();
+ gpxFile.userId = userId;
+ long previousTime = 0;
+ TrkSegment segment = null;
+ Track track = null;
+ if (query.moveToFirst()) {
+ do {
+ long time = query.getLong(7);
+ WptPt pt = new WptPt();
+ pt.userId = query.getInt(0);
+ pt.chatId = query.getLong(1);
+ pt.lat = query.getDouble(2);
+ pt.lon = query.getDouble(3);
+ pt.ele = query.getDouble(4);
+ pt.speed = query.getDouble(5);
+ pt.hdop = query.getDouble(6);
+ pt.time = time;
+ long currentInterval = Math.abs(time - previousTime);
+
+ if (track != null) {
+ if (currentInterval < 30 * 60 * 1000) {
+ // 30 minute - same segment
+ segment.points.add(pt);
+ } else {
+ segment = new TrkSegment();
+ segment.points.add(pt);
+ track.segments.add(segment);
+ }
+ } else {
+ track = new Track();
+ segment = new TrkSegment();
+ track.segments.add(segment);
+ segment.points.add(pt);
+
+ gpxFile.tracks.add(track);
+ }
+ previousTime = time;
+ } while (query.moveToNext());
+ }
+ query.close();
+ return gpxFile;
+ }
+
+ private void collectDBTracksForUsers(SQLiteDatabase db, ArrayList dataTracks, long start, long end, ArrayList ignoredUsersIds) {
+ Cursor query = db.rawQuery("SELECT " + TRACK_COL_USER_ID + "," + TRACK_COL_CHAT_ID + ","
+ + TRACK_COL_LAT + "," + TRACK_COL_LON + "," + TRACK_COL_ALTITUDE + "," + TRACK_COL_SPEED + ","
+ + TRACK_COL_HDOP + "," + TRACK_COL_DATE + " FROM " + TRACK_NAME + " WHERE " + TRACK_COL_DATE
+ + " BETWEEN " + start + " AND " + end + " ORDER BY " + TRACK_COL_USER_ID + " ASC, "
+ + TRACK_COL_CHAT_ID + " ASC, " + TRACK_COL_DATE + " ASC ", null);
+
+ long previousTime = 0;
+ long previousChatId = 0;
+ int previousUserId = 0;
+ TrkSegment segment = null;
+ Track track = null;
+ GPXFile gpx = new GPXFile();
+ if (query.moveToFirst()) {
+ do {
+ int userId = query.getInt(0);
+ if (ignoredUsersIds.contains(userId)) {
+ continue;
+ }
+ int chatId = query.getInt(1);
+ long time = query.getLong(7);
+ if (previousUserId != userId || previousChatId != chatId) {
+ gpx = new GPXFile();
+ gpx.chatId = chatId;
+ gpx.userId = userId;
+ previousTime = 0;
+ track = null;
+ segment = null;
+ dataTracks.add(gpx);
+ }
+
+ WptPt pt = new WptPt();
+ pt.userId = userId;
+ pt.chatId = chatId;
+ pt.lat = query.getDouble(2);
+ pt.lon = query.getDouble(3);
+ pt.ele = query.getDouble(4);
+ pt.speed = query.getDouble(5);
+ pt.hdop = query.getDouble(6);
+ pt.time = time;
+ long currentInterval = Math.abs(time - previousTime);
+ if (track != null) {
+ if (currentInterval < 30 * 60 * 1000) {
+ // 30 minute - same segment
+ segment.points.add(pt);
+ } else {
+ segment = new TrkSegment();
+ segment.points.add(pt);
+ track.segments.add(segment);
+ }
+ } else {
+ track = new Track();
+ segment = new TrkSegment();
+ track.segments.add(segment);
+ segment.points.add(pt);
+
+ gpx.tracks.add(track);
+ }
+ previousTime = time;
+ previousUserId = userId;
+ previousChatId = chatId;
+ } while (query.moveToNext());
+ }
+ query.close();
+ }
+
private static class SaveGPXTrackToFileTask extends AsyncTask> {
private TelegramApplication app;
- private WeakReference fragmentRef;
+ private SaveGpxListener listener;
private final GPXFile gpxFile;
private File dir;
private int userId;
- SaveGPXTrackToFileTask(LiveNowTabFragment fragment, GPXFile gpxFile, File dir, int userId) {
+ SaveGPXTrackToFileTask(TelegramApplication app, SaveGpxListener listener, GPXFile gpxFile, File dir, int userId) {
this.gpxFile = gpxFile;
- this.fragmentRef = new WeakReference<>(fragment);
- this.app = (TelegramApplication) fragment.getActivity().getApplication();
+ this.listener = listener;
+ this.app = app;
this.dir = dir;
this.userId = userId;
}
@@ -300,12 +454,21 @@ public class SavingTracksDbHelper extends SQLiteOpenHelper {
@Override
protected void onPostExecute(List warnings) {
- if (warnings != null && warnings.isEmpty()) {
- LiveNowTabFragment fragment = fragmentRef.get();
- if (fragment != null && fragment.isResumed()) {
- fragment.shareGpx(gpxFile.path);
+ if (listener != null) {
+ if (warnings != null && warnings.isEmpty()) {
+ listener.onSavingGpxFinish(gpxFile.path);
+ } else {
+ listener.onSavingGpxError(warnings);
}
}
}
}
+
+
+ public interface SaveGpxListener {
+
+ void onSavingGpxFinish(String path);
+
+ void onSavingGpxError(List warnings);
+ }
}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt
index af654a081c..be9c2886a4 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramHelper.kt
@@ -391,6 +391,15 @@ class TelegramHelper private constructor() {
fun isBot(userId: Int) = users[userId]?.type is TdApi.UserTypeBot
+ fun getSenderMessageId(message: TdApi.Message): Int {
+ val forwardInfo = message.forwardInfo
+ return if (forwardInfo != null && forwardInfo is TdApi.MessageForwardedFromUser) {
+ forwardInfo.senderUserId
+ } else {
+ message.senderUserId
+ }
+ }
+
fun startLiveMessagesUpdates(interval: Long) {
stopLiveMessagesUpdates()
@@ -738,10 +747,13 @@ class TelegramHelper private constructor() {
}
} else {
removeOldMessages(message, fromBot, viaBot)
- val oldMessage = usersLocationMessages.values.firstOrNull { it.senderUserId == message.senderUserId && !fromBot && !viaBot }
- if (oldMessage == null || (Math.max(message.editDate, message.date) > Math.max(oldMessage.editDate, oldMessage.date))) {
+ val oldMessage = usersLocationMessages.values.firstOrNull { getSenderMessageId(it) == getSenderMessageId(message) && !fromBot && !viaBot }
+ val hasNewerMessage = oldMessage != null && (Math.max(message.editDate, message.date) < Math.max(oldMessage.editDate, oldMessage.date))
+ if (!hasNewerMessage) {
usersLocationMessages[message.id] = message
- incomingMessagesListeners.forEach {
+ }
+ incomingMessagesListeners.forEach {
+ if (!hasNewerMessage || it is SavingTracksDbHelper) {
it.onReceiveChatLocationMessages(message.chatId, message)
}
}
@@ -754,7 +766,7 @@ class TelegramHelper private constructor() {
while (iterator.hasNext()) {
val message = iterator.next().value
if (newMessage.chatId == message.chatId) {
- val sameSender = newMessage.senderUserId == message.senderUserId
+ val sameSender = getSenderMessageId(newMessage) == getSenderMessageId(message)
val viaSameBot = newMessage.viaBotUserId == message.viaBotUserId
if (fromBot || viaBot) {
if ((fromBot && sameSender) || (viaBot && viaSameBot)) {
@@ -1075,23 +1087,6 @@ class TelegramHelper private constructor() {
return TdApi.InputMessageText(TdApi.FormattedText(textMessage, entities.toTypedArray()), true, true)
}
- /**
- * @chatId Id of the chat
- * @message Text of the message
- */
- fun sendTextMessage(chatId: Long, message: String): Boolean {
- // initialize reply markup just for testing
- //val row = arrayOf(TdApi.InlineKeyboardButton("https://telegram.org?1", TdApi.InlineKeyboardButtonTypeUrl()), TdApi.InlineKeyboardButton("https://telegram.org?2", TdApi.InlineKeyboardButtonTypeUrl()), TdApi.InlineKeyboardButton("https://telegram.org?3", TdApi.InlineKeyboardButtonTypeUrl()))
- //val replyMarkup = TdApi.ReplyMarkupInlineKeyboard(arrayOf(row, row, row))
-
- if (haveAuthorization) {
- val content = TdApi.InputMessageText(TdApi.FormattedText(message, null), false, true)
- client?.send(TdApi.SendMessage(chatId, 0, false, true, null, content), defaultHandler)
- return true
- }
- return false
- }
-
fun logout(): Boolean {
return if (libraryLoaded) {
haveAuthorization = false
@@ -1769,4 +1764,4 @@ class TelegramHelper private constructor() {
}// result is already received through UpdateAuthorizationState, nothing to do
}
}
-}
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt
index a1670f1912..2a4f1b1436 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/helpers/TelegramUiHelper.kt
@@ -8,6 +8,7 @@ import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.TelegramHelper.MessageOsmAndBotLocation
import net.osmand.telegram.helpers.TelegramHelper.MessageUserTextLocation
+import net.osmand.telegram.utils.GPXUtilities
import org.drinkless.td.libcore.telegram.TdApi
object TelegramUiHelper {
@@ -129,6 +130,10 @@ object TelegramUiHelper {
}
}
+ fun gpxToChatItem(helper: TelegramHelper, gpx: GPXUtilities.GPXFile, simpleUserItem: Boolean): GpxChatItem? {
+ return if (simpleUserItem) gpxToUserGpxChatItem(helper, gpx) else gpxToGpxChatItem(helper, gpx)
+ }
+
private fun botMessageToLocationItem(
chat: TdApi.Chat,
content: MessageOsmAndBotLocation
@@ -224,6 +229,49 @@ object TelegramUiHelper {
}
}
+ private fun gpxToGpxChatItem(
+ helper: TelegramHelper,
+ gpx: GPXUtilities.GPXFile
+ ): GpxChatItem? {
+ val user = helper.getUser(gpx.userId) ?: return null
+ val chat = helper.getChat(gpx.chatId) ?: return null
+ return GpxChatItem().apply {
+ chatId = chat.id
+ chatTitle = chat.title
+ gpxFile = gpx
+ name = TelegramUiHelper.getUserName(user)
+ if (helper.isGroup(chat)) {
+ photoPath = helper.getUserPhotoPath(user)
+ groupPhotoPath = chat.photo?.small?.local?.path
+ } else {
+ photoPath = user.profilePhoto?.small?.local?.path
+ }
+ grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
+ placeholderId = R.drawable.img_user_picture
+ userId = user.id
+ privateChat = helper.isPrivateChat(chat) || helper.isSecretChat(chat)
+ chatWithBot = helper.isBot(userId)
+ lastUpdated = (gpx.modifiedTime / 1000).toInt()
+ }
+ }
+
+ private fun gpxToUserGpxChatItem(
+ helper: TelegramHelper,
+ gpx: GPXUtilities.GPXFile
+ ): GpxChatItem? {
+ val user = helper.getUser(gpx.userId) ?: return null
+ return GpxChatItem().apply {
+ gpxFile = gpx
+ name = TelegramUiHelper.getUserName(user)
+ photoPath = user.profilePhoto?.small?.local?.path
+ grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
+ placeholderId = R.drawable.img_user_picture
+ userId = user.id
+ chatWithBot = helper.isBot(userId)
+ lastUpdated = (gpx.modifiedTime / 1000).toInt()
+ }
+ }
+
abstract class ListItem {
var chatId: Long = 0
@@ -272,6 +320,24 @@ object TelegramUiHelper {
override fun getVisibleName() = chatTitle
}
+ class GpxChatItem : ListItem() {
+
+ var gpxFile: GPXUtilities.GPXFile? = null
+ internal set
+ var groupPhotoPath: String? = null
+ internal set
+ var privateChat: Boolean = false
+ internal set
+ var chatWithBot: Boolean = false
+ internal set
+
+ override fun canBeOpenedOnMap() = latLon != null
+
+ override fun getMapPointId() = "${chatId}_$userId"
+
+ override fun getVisibleName() = chatTitle
+ }
+
class LocationItem : ListItem() {
override fun canBeOpenedOnMap() = latLon != null
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt
index 42ba73d4cc..073c9633f2 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/LiveNowTabFragment.kt
@@ -11,10 +11,7 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.animation.LinearInterpolator
-import android.widget.ArrayAdapter
-import android.widget.ImageView
-import android.widget.LinearLayout
-import android.widget.TextView
+import android.widget.*
import net.osmand.Location
import net.osmand.data.LatLon
import net.osmand.telegram.R
@@ -22,6 +19,7 @@ import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.TelegramLocationProvider.TelegramCompassListener
import net.osmand.telegram.TelegramLocationProvider.TelegramLocationListener
import net.osmand.telegram.TelegramSettings
+import net.osmand.telegram.helpers.SavingTracksDbHelper
import net.osmand.telegram.helpers.TelegramHelper.*
import net.osmand.telegram.helpers.TelegramUiHelper
import net.osmand.telegram.helpers.TelegramUiHelper.ChatItem
@@ -33,7 +31,7 @@ import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.UiUtils.UpdateLocationViewCache
import net.osmand.util.MapUtils
import org.drinkless.td.libcore.telegram.TdApi
-import java.io.File
+import java.util.*
private const val CHAT_VIEW_TYPE = 0
private const val LOCATION_ITEM_VIEW_TYPE = 1
@@ -233,15 +231,6 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
stopLocationUpdate()
}
- fun shareGpx(path: String) {
- val fileUri = AndroidUtils.getUriForFile(app, File(path))
- val sendIntent = Intent(Intent.ACTION_SEND)
- sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri)
- sendIntent.type = "application/gpx+xml"
- sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
- startActivity(sendIntent)
- }
-
private fun chooseOsmAnd() {
val ctx = context ?: return
val installedApps = TelegramSettings.AppConnect.getInstalledApps(ctx)
@@ -456,15 +445,6 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
app.showLocationHelper.showLocationOnMap(item, staleLocation)
}
}
- openOnMapView?.setOnLongClickListener {
- app.savingTracksDbHelper.saveAsyncUserDataToGpx(
- this@LiveNowTabFragment,
- app.getExternalFilesDir(null),
- item.userId,
- 60 * 60 * 24 * 1000
- )
- true
- }
} else {
openOnMapView?.setOnClickListener(null)
}
@@ -485,17 +465,6 @@ class LiveNowTabFragment : Fragment(), TelegramListener, TelegramIncomingMessage
if (lastItem) {
holder.lastTelegramUpdateTime?.visibility = View.VISIBLE
holder.lastTelegramUpdateTime?.text = OsmandFormatter.getListItemLiveTimeDescr(app, telegramHelper.lastTelegramUpdateTime, lastTelegramUpdateStr)
- holder.lastTelegramUpdateTime?.setOnClickListener {
- val currentUserId = telegramHelper.getCurrentUser()?.id
- if (currentUserId != null) {
- app.savingTracksDbHelper.saveAsyncUserDataToGpx(
- this@LiveNowTabFragment,
- app.getExternalFilesDir(null),
- currentUserId,
- 60 * 60 * 24 * 1000
- )
- }
- }
} else {
holder.lastTelegramUpdateTime?.visibility = View.GONE
}
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt
index 0ac6356a0b..62d50ee90d 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MainActivity.kt
@@ -27,6 +27,7 @@ import net.osmand.telegram.ui.MyLocationTabFragment.ActionButtonsListener
import net.osmand.telegram.ui.views.LockableViewPager
import net.osmand.telegram.utils.*
import org.drinkless.td.libcore.telegram.TdApi
+import java.io.File
import java.lang.ref.WeakReference
const val OPEN_MY_LOCATION_TAB_KEY = "open_my_location_tab"
@@ -35,6 +36,7 @@ private const val PERMISSION_REQUEST_LOCATION = 1
private const val MY_LOCATION_TAB_POS = 0
private const val LIVE_NOW_TAB_POS = 1
+private const val TIMELINE_TAB_POS = 2
class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListener, TelegramIncomingMessagesListener {
@@ -54,6 +56,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
private var myLocationTabFragment: MyLocationTabFragment? = null
private var liveNowTabFragment: LiveNowTabFragment? = null
+ private var timelineTabFragment: TimelineTabFragment? = null
private lateinit var buttonsBar: LinearLayout
private lateinit var bottomNav: BottomNavigationView
@@ -72,7 +75,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
val viewPager = findViewById(R.id.view_pager).apply {
swipeLocked = true
- offscreenPageLimit = 2
+ offscreenPageLimit = 3
adapter = ViewPagerAdapter(supportFragmentManager)
}
@@ -82,11 +85,13 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
when (it.itemId) {
R.id.action_my_location -> pos = MY_LOCATION_TAB_POS
R.id.action_live_now -> pos = LIVE_NOW_TAB_POS
+ R.id.action_timeline -> pos = TIMELINE_TAB_POS
}
if (pos != -1 && pos != viewPager.currentItem) {
when (pos) {
MY_LOCATION_TAB_POS -> liveNowTabFragment?.tabClosed()
LIVE_NOW_TAB_POS -> liveNowTabFragment?.tabOpened()
+ TIMELINE_TAB_POS -> liveNowTabFragment?.tabClosed()
}
viewPager.currentItem = pos
return@setOnNavigationItemSelectedListener true
@@ -139,10 +144,10 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
if (fragment is TelegramListener) {
listeners.add(WeakReference(fragment))
}
- if (fragment is MyLocationTabFragment) {
- myLocationTabFragment = fragment
- } else if (fragment is LiveNowTabFragment) {
- liveNowTabFragment = fragment
+ when (fragment) {
+ is MyLocationTabFragment -> myLocationTabFragment = fragment
+ is LiveNowTabFragment -> liveNowTabFragment = fragment
+ is TimelineTabFragment -> timelineTabFragment = fragment
}
}
@@ -317,6 +322,15 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
android.os.Process.killProcess(android.os.Process.myPid())
}
+ fun shareGpx(path: String) {
+ val fileUri = AndroidUtils.getUriForFile(app, File(path))
+ val sendIntent = Intent(Intent.ACTION_SEND)
+ sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri)
+ sendIntent.type = "application/gpx+xml"
+ sendIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ startActivity(sendIntent)
+ }
+
fun loginTelegram() {
if (telegramHelper.getTelegramAuthorizationState() != TelegramAuthorizationState.CLOSED) {
telegramHelper.logout()
@@ -463,7 +477,7 @@ class MainActivity : AppCompatActivity(), TelegramListener, ActionButtonsListene
class ViewPagerAdapter(fm: FragmentManager) : FragmentPagerAdapter(fm) {
- private val fragments = listOf(MyLocationTabFragment(), LiveNowTabFragment())
+ private val fragments = listOf(MyLocationTabFragment(), LiveNowTabFragment(), TimelineTabFragment())
override fun getItem(position: Int) = fragments[position]
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
index 8ce2e7a4f5..149f6c7cc1 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/MyLocationTabFragment.kt
@@ -599,12 +599,6 @@ class MyLocationTabFragment : Fragment(), TelegramListener {
}
holder.title?.text = title
- holder.icon?.setOnClickListener {
- app.forceUpdateMyLocation()
- val curUser = telegramHelper.getCurrentUser()
- val text = "${curUser?.id} ${curUser?.firstName} ${curUser?.lastName}"
- Toast.makeText(app, text, Toast.LENGTH_LONG).show()
- }
if (holder is ChatViewHolder) {
holder.description?.visibility = View.GONE
if (live) {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt
new file mode 100644
index 0000000000..6ddd564e8d
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/TimelineTabFragment.kt
@@ -0,0 +1,261 @@
+package net.osmand.telegram.ui
+
+import android.app.DatePickerDialog
+import android.graphics.drawable.Drawable
+import android.os.Build
+import android.os.Bundle
+import android.support.annotation.DrawableRes
+import android.support.v4.app.Fragment
+import android.support.v7.widget.LinearLayoutManager
+import android.support.v7.widget.RecyclerView
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.Switch
+import android.widget.TextView
+import net.osmand.PlatformUtil
+import net.osmand.telegram.R
+import net.osmand.telegram.TelegramApplication
+import net.osmand.telegram.helpers.TelegramUiHelper
+import net.osmand.telegram.helpers.TelegramUiHelper.ListItem
+import net.osmand.telegram.ui.TimelineTabFragment.LiveNowListAdapter.BaseViewHolder
+import net.osmand.telegram.utils.AndroidUtils
+import net.osmand.telegram.utils.OsmandFormatter
+import java.util.*
+
+
+class TimelineTabFragment : Fragment() {
+
+ private val log = PlatformUtil.getLog(TimelineTabFragment::class.java)
+
+ private val app: TelegramApplication
+ get() = activity?.application as TelegramApplication
+
+ private val telegramHelper get() = app.telegramHelper
+ private val settings get() = app.settings
+
+ private lateinit var adapter: LiveNowListAdapter
+
+ private lateinit var dateStartBtn: TextView
+ private lateinit var dateEndBtn: TextView
+ private lateinit var mainView: View
+
+ private var start = 0L
+ private var end = 0L
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
+ mainView = inflater.inflate(R.layout.fragment_timeline_tab, container, false)
+ val appBarLayout = mainView.findViewById(R.id.app_bar_layout)
+
+ start = System.currentTimeMillis()
+ end = System.currentTimeMillis()
+
+ AndroidUtils.addStatusBarPadding19v(context!!, appBarLayout)
+ adapter = LiveNowListAdapter()
+ mainView.findViewById(R.id.recycler_view).apply {
+ layoutManager = LinearLayoutManager(context)
+ adapter = this@TimelineTabFragment.adapter
+ }
+
+ val switcher = mainView.findViewById(R.id.monitoring_switcher)
+ val monitoringTv = mainView.findViewById(R.id.monitoring_title)
+ monitoringTv.setText(if (settings.monitoringEnabled) R.string.monitoring_is_enabled else R.string.monitoring_is_disabled)
+
+ mainView.findViewById(R.id.monitoring_container).setOnClickListener {
+ val monitoringEnabled = !settings.monitoringEnabled
+ settings.monitoringEnabled = monitoringEnabled
+ switcher.isChecked = monitoringEnabled
+ monitoringTv.setText(if (monitoringEnabled) R.string.monitoring_is_enabled else R.string.monitoring_is_disabled)
+ }
+
+ dateStartBtn = mainView.findViewById(R.id.date_start_btn).apply {
+ setOnClickListener {
+ selectStartDate()
+ }
+ setCompoundDrawablesWithIntrinsicBounds(getPressedStateIcon(R.drawable.ic_action_date_start), null, null, null)
+ }
+ dateEndBtn = mainView.findViewById(R.id.date_end_btn).apply {
+ setOnClickListener {
+ selectEndDate()
+ }
+ setCompoundDrawablesWithIntrinsicBounds(getPressedStateIcon(R.drawable.ic_action_date_add), null, null, null)
+ }
+
+ setupBtnTextColor(dateStartBtn)
+ setupBtnTextColor(dateEndBtn)
+
+ return mainView
+ }
+
+ private fun setupBtnTextColor(textView: TextView) {
+ textView.setTextColor(AndroidUtils.createPressedColorStateList(app, true, R.color.ctrl_active_light, R.color.ctrl_light))
+ }
+
+ private fun selectStartDate() {
+ val dateFromDialog =
+ DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
+ val from = Calendar.getInstance()
+ from.set(Calendar.YEAR, year)
+ from.set(Calendar.MONTH, monthOfYear)
+ from.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ start = from.timeInMillis
+ updateList()
+ updateDateButtons()
+ }
+ val startCalendar = Calendar.getInstance()
+ startCalendar.timeInMillis = start
+ DatePickerDialog(context, dateFromDialog,
+ startCalendar.get(Calendar.YEAR),
+ startCalendar.get(Calendar.MONTH),
+ startCalendar.get(Calendar.DAY_OF_MONTH)
+ ).show()
+ }
+
+ private fun selectEndDate() {
+ val dateFromDialog =
+ DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
+ val from = Calendar.getInstance()
+ from.set(Calendar.YEAR, year)
+ from.set(Calendar.MONTH, monthOfYear)
+ from.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ end = from.timeInMillis
+ updateList()
+ updateDateButtons()
+ }
+ val endCalendar = Calendar.getInstance()
+ endCalendar.timeInMillis = end
+ DatePickerDialog(context, dateFromDialog,
+ endCalendar.get(Calendar.YEAR),
+ endCalendar.get(Calendar.MONTH),
+ endCalendar.get(Calendar.DAY_OF_MONTH)
+ ).show()
+ }
+
+ private fun updateDateButtons() {
+ dateStartBtn.text = OsmandFormatter.getFormattedDate(start / 1000)
+ dateEndBtn.text = OsmandFormatter.getFormattedDate(end / 1000)
+ dateEndBtn.setCompoundDrawablesWithIntrinsicBounds(getPressedStateIcon(R.drawable.ic_action_date_end), null, null, null)
+ }
+
+ private fun getPressedStateIcon(@DrawableRes iconId: Int): Drawable? {
+ val normal = app.uiUtils.getActiveIcon(iconId)
+ if (Build.VERSION.SDK_INT >= 21) {
+ val active = app.uiUtils.getIcon(iconId, R.color.ctrl_light)
+ if (normal != null && active != null) {
+ return AndroidUtils.createPressedStateListDrawable(normal, active)
+ }
+ }
+ return normal
+ }
+
+ private fun updateList() {
+ val res = mutableListOf()
+ val s = System.currentTimeMillis()
+ log.debug("updateList $start")
+ val ignoredUsersIds = ArrayList()
+ val currentUserId = telegramHelper.getCurrentUser()?.id
+ if (currentUserId != null) {
+ val currentUserGpx = app.savingTracksDbHelper.collectRecordedDataForUser(currentUserId, 0, start, end)
+ TelegramUiHelper.gpxToChatItem(telegramHelper, currentUserGpx, true)?.also {
+ res.add(it)
+ }
+ ignoredUsersIds.add(currentUserId)
+ }
+ val gpxFiles = app.savingTracksDbHelper.collectRecordedDataForUsers(start, end, ignoredUsersIds)
+ val e = System.currentTimeMillis()
+
+ gpxFiles.forEach {
+ TelegramUiHelper.gpxToChatItem(telegramHelper, it,false)?.also { chatItem ->
+ res.add(chatItem)
+ }
+ }
+
+ adapter.items = sortAdapterItems(res)
+ log.debug("updateList $s dif: ${e - s}")
+ }
+
+ private fun sortAdapterItems(list: MutableList): MutableList {
+ val currentUserId = telegramHelper.getCurrentUser()?.id ?: 0
+ list.sortWith(java.util.Comparator { lhs, rhs ->
+ when (currentUserId) {
+ lhs.userId -> return@Comparator 1
+ rhs.userId -> return@Comparator 1
+ else -> return@Comparator lhs.name.compareTo(rhs.name)
+ }
+ })
+ return list
+ }
+
+ inner class LiveNowListAdapter : RecyclerView.Adapter() {
+
+ var items: List = emptyList()
+ set(value) {
+ field = value
+ notifyDataSetChanged()
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BaseViewHolder {
+ val inflater = LayoutInflater.from(parent.context)
+ return BaseViewHolder(inflater.inflate(R.layout.live_now_chat_card, parent, false))
+ }
+
+ override fun onBindViewHolder(holder: BaseViewHolder, position: Int) {
+ val lastItem = position == itemCount - 1
+ val item = items[position]
+ val currentUserId = telegramHelper.getCurrentUser()?.id ?: 0
+
+ TelegramUiHelper.setupPhoto(app, holder.icon, item.photoPath, R.drawable.img_user_picture_active, false)
+ holder.title?.text = item.name
+ holder.bottomShadow?.visibility = if (lastItem) View.VISIBLE else View.GONE
+ holder.lastTelegramUpdateTime?.visibility = View.GONE
+
+ if (item is TelegramUiHelper.GpxChatItem) {
+ val gpx = item.gpxFile
+ val groupDescrRowVisible = (!item.privateChat || item.chatWithBot) && item.userId != currentUserId
+ if (groupDescrRowVisible) {
+ holder.groupDescrContainer?.visibility = View.VISIBLE
+ holder.groupTitle?.text = item.getVisibleName()
+ TelegramUiHelper.setupPhoto(app, holder.groupImage, item.groupPhotoPath, item.placeholderId, false)
+ } else {
+ holder.groupDescrContainer?.visibility = View.GONE
+ }
+ holder.userRow?.setOnClickListener {
+ if (gpx != null) {
+ childFragmentManager.also {
+ UserGpxInfoFragment.showInstance(it, gpx, start, end)
+ }
+ }
+ }
+
+ holder.imageButton?.visibility = View.GONE
+ holder.showOnMapRow?.visibility = View.GONE
+ holder.bottomDivider?.visibility = if (lastItem) View.GONE else View.VISIBLE
+ holder.topDivider?.visibility = if (position != 0) View.GONE else View.VISIBLE
+ }
+ }
+
+ override fun getItemCount() = items.size
+
+ inner class BaseViewHolder(view: View) : RecyclerView.ViewHolder(view) {
+ val icon: ImageView? = view.findViewById(R.id.icon)
+ val title: TextView? = view.findViewById(R.id.title)
+ val description: TextView? = view.findViewById(R.id.description)
+ val bottomShadow: View? = view.findViewById(R.id.bottom_shadow)
+ val lastTelegramUpdateTime: TextView? = view.findViewById(R.id.last_telegram_update_time)
+
+ val userRow: View? = view.findViewById(R.id.user_row)
+ val groupDescrContainer: View? = view.findViewById(R.id.group_container)
+ val groupImage: ImageView? = view.findViewById(R.id.group_icon)
+ val groupTitle: TextView? = view.findViewById(R.id.group_title)
+ val imageButton: ImageView? = view.findViewById(R.id.image_button)
+ val showOnMapRow: View? = view.findViewById(R.id.show_on_map_row)
+ val topDivider: View? = view.findViewById(R.id.top_divider)
+ val bottomDivider: View? = view.findViewById(R.id.bottom_divider)
+ }
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt b/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt
new file mode 100644
index 0000000000..a411d80b7d
--- /dev/null
+++ b/OsmAnd-telegram/src/net/osmand/telegram/ui/UserGpxInfoFragment.kt
@@ -0,0 +1,322 @@
+package net.osmand.telegram.ui
+
+import android.app.DatePickerDialog
+import android.app.TimePickerDialog
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.graphics.drawable.BitmapDrawable
+import android.os.Bundle
+import android.support.v4.app.FragmentManager
+import android.util.DisplayMetrics
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.widget.ImageView
+import android.widget.LinearLayout
+import android.widget.TextView
+import android.widget.Toast
+import net.osmand.PlatformUtil
+import net.osmand.aidl.gpx.AGpxBitmap
+import net.osmand.telegram.R
+import net.osmand.telegram.helpers.OsmandAidlHelper
+import net.osmand.telegram.helpers.SavingTracksDbHelper
+import net.osmand.telegram.helpers.TelegramUiHelper
+import net.osmand.telegram.utils.AndroidUtils
+import net.osmand.telegram.utils.GPXUtilities
+import net.osmand.telegram.utils.OsmandFormatter
+import net.osmand.util.Algorithms
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.*
+
+class UserGpxInfoFragment : BaseDialogFragment() {
+
+ private val log = PlatformUtil.getLog(UserGpxInfoFragment::class.java)
+
+ private val uiUtils get() = app.uiUtils
+
+ private lateinit var gpxFile: GPXUtilities.GPXFile
+
+ private lateinit var dateStartBtn: TextView
+ private lateinit var timeStartBtn: TextView
+ private lateinit var dateEndBtn: TextView
+ private lateinit var timeEndBtn: TextView
+
+ private lateinit var avgElevationTv: TextView
+ private lateinit var avgSpeedTv: TextView
+ private lateinit var totalDistanceTv: TextView
+ private lateinit var timeSpanTv: TextView
+
+ private var startCalendar = Calendar.getInstance()
+ private var endCalendar = Calendar.getInstance()
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ parent: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ val mainView = inflater.inflate(R.layout.fragment_user_gpx_info, parent)
+ AndroidUtils.addStatusBarPadding19v(context!!, mainView)
+
+ readFromBundle(savedInstanceState ?: arguments)
+
+ val userId = gpxFile.userId
+ val chatId = gpxFile.chatId
+
+ val user = app.telegramHelper.getUser(userId)
+ if (user != null) {
+ mainView.findViewById(R.id.title).text = TelegramUiHelper.getUserName(user)
+ TelegramUiHelper.setupPhoto(app, mainView.findViewById(R.id.user_icon),
+ telegramHelper.getUserPhotoPath(user), R.drawable.img_user_placeholder, false)
+ }
+ app.osmandAidlHelper.setGpxBitmapCreatedListener(
+ object : OsmandAidlHelper.GpxBitmapCreatedListener {
+ override fun onGpxBitmapCreated(bitmap: AGpxBitmap) {
+ activity?.runOnUiThread {
+ mainView.findViewById(R.id.gpx_map).setImageDrawable(BitmapDrawable(app.resources, bitmap.bitmap))
+ }
+ }
+ })
+
+ updateGPXMap()
+
+ val backBtn = mainView.findViewById(R.id.back_button)
+ backBtn.setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_arrow_back))
+ backBtn.setOnClickListener {
+ dismiss()
+ }
+
+ dateStartBtn = mainView.findViewById(R.id.date_start_btn)
+ timeStartBtn = mainView.findViewById(R.id.time_start_btn)
+ dateEndBtn = mainView.findViewById(R.id.date_end_btn)
+ timeEndBtn = mainView.findViewById(R.id.time_end_btn)
+
+ dateStartBtn.setOnClickListener { selectStartDate() }
+ timeStartBtn.setOnClickListener { selectStartTime() }
+ dateEndBtn.setOnClickListener { selectEndDate() }
+ timeEndBtn.setOnClickListener { selectEndTime() }
+
+ setupBtnTextColor(dateStartBtn)
+ setupBtnTextColor(timeStartBtn)
+ setupBtnTextColor(dateEndBtn)
+ setupBtnTextColor(timeEndBtn)
+
+ updateDateAndTimeButtons()
+
+ avgElevationTv = mainView.findViewById(R.id.average_altitude_text)
+ avgSpeedTv = mainView.findViewById(R.id.average_speed_text)
+ totalDistanceTv = mainView.findViewById(R.id.distance_text)
+ timeSpanTv = mainView.findViewById(R.id.duration_text)
+
+ mainView.findViewById(R.id.average_altitude_icon).apply {
+ setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_altitude_range))
+ }
+ mainView.findViewById(R.id.average_speed_icon).apply {
+ setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_speed_average))
+ }
+ mainView.findViewById(R.id.distance_icon).apply {
+ setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_altitude_range))
+ }
+ mainView.findViewById(R.id.duration_icon).apply {
+ setImageDrawable(uiUtils.getThemedIcon(R.drawable.ic_action_altitude_range))
+ }
+
+ updateGPXStatisticRow()
+
+ mainView.findViewById(R.id.open_in_osmand_icon).setImageResource(R.drawable.ic_logo_osmand_free)
+
+ mainView.findViewById(R.id.open_in_osmand_btn).apply {
+ setOnClickListener {
+ val gpx = gpxFile
+ if (gpx.path.isNotEmpty()) {
+ openGpx(gpx.path)
+ } else {
+ saveCurrentGpxToFile(object :
+ SavingTracksDbHelper.SaveGpxListener {
+ override fun onSavingGpxFinish(path: String) {
+ openGpx(path)
+ }
+
+ override fun onSavingGpxError(warnings: MutableList?) {
+ Toast.makeText(app, warnings?.firstOrNull(), Toast.LENGTH_LONG).show()
+ }
+ })
+ }
+ }
+ }
+
+ mainView.findViewById(R.id.share_gpx_icon).setImageDrawable(uiUtils.getActiveIcon(R.drawable.ic_action_share))
+
+ mainView.findViewById(R.id.share_gpx_btn).apply {
+ setOnClickListener {
+ val gpx = gpxFile
+ if (gpx.path.isNotEmpty()) {
+ (activity as MainActivity).shareGpx(gpx.path)
+ } else {
+ saveCurrentGpxToFile(object :
+ SavingTracksDbHelper.SaveGpxListener {
+ override fun onSavingGpxFinish(path: String) {
+ (activity as MainActivity).shareGpx(path)
+ }
+
+ override fun onSavingGpxError(warnings: MutableList?) {
+ Toast.makeText(app, warnings?.firstOrNull(), Toast.LENGTH_LONG).show()
+ }
+ })
+ }
+ }
+ }
+
+ return mainView
+ }
+
+ override fun onSaveInstanceState(outState: Bundle) {
+ super.onSaveInstanceState(outState)
+ outState.putLong(START_KEY, startCalendar.timeInMillis)
+ outState.putLong(END_KEY, endCalendar.timeInMillis)
+ }
+
+ private fun openGpx(path: String) {
+ val fileUri = AndroidUtils.getUriForFile(app, File(path))
+ val openGpxIntent = Intent(Intent.ACTION_VIEW)
+ openGpxIntent.setDataAndType(fileUri, "application/gpx+xml")
+// openGpxIntent.type = "application/gpx+xml"
+ openGpxIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+ val resolved = activity?.packageManager?.resolveActivity(openGpxIntent, PackageManager.MATCH_DEFAULT_ONLY)
+ if (resolved != null) {
+ startActivity(openGpxIntent)
+ }
+ }
+
+ private fun saveCurrentGpxToFile(listener: SavingTracksDbHelper.SaveGpxListener) {
+ app.savingTracksDbHelper.saveGpx(listener, app.getExternalFilesDir(null), gpxFile)
+ }
+
+ private fun readFromBundle(bundle: Bundle?) {
+ bundle?.also {
+ startCalendar.timeInMillis = it.getLong(START_KEY)
+ endCalendar.timeInMillis = it.getLong(END_KEY)
+ }
+ }
+
+ private fun setupBtnTextColor(textView: TextView) {
+ textView.setTextColor(AndroidUtils.createPressedColorStateList(app, true, R.color.ctrl_active_light, R.color.ctrl_light))
+ }
+
+ private fun updateGpxInfo() {
+ gpxFile = app.savingTracksDbHelper.collectRecordedDataForUser(gpxFile.userId, gpxFile.chatId, startCalendar.timeInMillis, endCalendar.timeInMillis)
+ updateGPXStatisticRow()
+ updateDateAndTimeButtons()
+ updateGPXMap()
+ }
+
+ private fun updateDateAndTimeButtons() {
+ dateStartBtn.text = SimpleDateFormat("dd MMM", Locale.getDefault()).format(startCalendar.timeInMillis)
+ dateEndBtn.text = SimpleDateFormat("dd MMM", Locale.getDefault()).format(endCalendar.timeInMillis)
+
+ timeStartBtn.text = SimpleDateFormat("HH:mm", Locale.getDefault()).format(startCalendar.timeInMillis)
+ timeEndBtn.text = SimpleDateFormat("HH:mm", Locale.getDefault()).format(endCalendar.timeInMillis)
+ }
+
+ private fun updateGPXStatisticRow() {
+ val analysis: GPXUtilities.GPXTrackAnalysis = gpxFile.getAnalysis(0)
+ avgElevationTv.text = OsmandFormatter.getFormattedAlt(analysis.avgElevation, app)
+ avgSpeedTv.text = if (analysis.isSpeedSpecified) OsmandFormatter.getFormattedSpeed(analysis.avgSpeed, app) else ""
+ totalDistanceTv.text = OsmandFormatter.getFormattedDistance(analysis.totalDistance, app)
+ timeSpanTv.text = Algorithms.formatDuration((analysis.timeSpan / 1000).toInt(), true)
+ }
+
+ private fun updateGPXMap() {
+ saveCurrentGpxToFile(object :
+ SavingTracksDbHelper.SaveGpxListener {
+ override fun onSavingGpxFinish(path: String) {
+ val mgr = activity?.getSystemService(Context.WINDOW_SERVICE)
+ if (mgr != null) {
+ val dm = DisplayMetrics()
+ (mgr as WindowManager).defaultDisplay.getMetrics(dm)
+ val widthPixels = dm.widthPixels - (2 * app.resources.getDimensionPixelSize(R.dimen.content_padding_standard))
+ val heightPixels = AndroidUtils.dpToPx(app, 152f)
+ val gpxUri = AndroidUtils.getUriForFile(app, File(path))
+ app.osmandAidlHelper.getBitmapForGpx(gpxUri, dm.density , widthPixels, heightPixels, GPX_TRACK_COLOR)
+ }
+ }
+
+ override fun onSavingGpxError(warnings: MutableList?) {
+ log.debug("onSavingGpxError ${warnings?.firstOrNull()}")
+ }
+ })
+ }
+
+ private fun selectStartDate() {
+ val dateFromDialog =
+ DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
+ startCalendar.set(Calendar.YEAR, year)
+ startCalendar.set(Calendar.MONTH, monthOfYear)
+ startCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ updateGpxInfo()
+ }
+ DatePickerDialog(context, dateFromDialog,
+ startCalendar.get(Calendar.YEAR),
+ startCalendar.get(Calendar.MONTH),
+ startCalendar.get(Calendar.DAY_OF_MONTH)).show()
+ }
+
+ private fun selectStartTime() {
+ TimePickerDialog(context,
+ TimePickerDialog.OnTimeSetListener { _, hours, minutes ->
+ startCalendar.set(Calendar.HOUR_OF_DAY, hours)
+ startCalendar.set(Calendar.MINUTE, minutes)
+ updateGpxInfo()
+ }, 0, 0, true).show()
+ }
+
+ private fun selectEndDate() {
+ val dateFromDialog =
+ DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
+ endCalendar.set(Calendar.YEAR, year)
+ endCalendar.set(Calendar.MONTH, monthOfYear)
+ endCalendar.set(Calendar.DAY_OF_MONTH, dayOfMonth)
+ updateGpxInfo()
+ }
+ DatePickerDialog(context, dateFromDialog,
+ endCalendar.get(Calendar.YEAR),
+ endCalendar.get(Calendar.MONTH),
+ endCalendar.get(Calendar.DAY_OF_MONTH)).show()
+ }
+
+ private fun selectEndTime() {
+ TimePickerDialog(context,
+ TimePickerDialog.OnTimeSetListener { _, hours, minutes ->
+ endCalendar.set(Calendar.HOUR_OF_DAY, hours)
+ endCalendar.set(Calendar.MINUTE, minutes)
+ updateGpxInfo()
+ }, 0, 0, true).show()
+ }
+
+ companion object {
+
+ private const val TAG = "UserGpxInfoFragment"
+ private const val START_KEY = "start_key"
+ private const val END_KEY = "end_key"
+
+ private const val GPX_TRACK_COLOR = -65536
+
+ fun showInstance(fm: FragmentManager, gpxFile: GPXUtilities.GPXFile, start: Long, end: Long): Boolean {
+ return try {
+ val fragment = UserGpxInfoFragment().apply {
+ arguments = Bundle().apply {
+ putLong(START_KEY, start)
+ putLong(END_KEY, end)
+ }
+ }
+ fragment.gpxFile = gpxFile
+ fragment.show(fm, TAG)
+ true
+ } catch (e: RuntimeException) {
+ false
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/utils/GPXUtilities.java b/OsmAnd-telegram/src/net/osmand/telegram/utils/GPXUtilities.java
index 5d2ba74d8f..b27293c40b 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/utils/GPXUtilities.java
+++ b/OsmAnd-telegram/src/net/osmand/telegram/utils/GPXUtilities.java
@@ -10,6 +10,7 @@ import android.text.TextUtils;
import net.osmand.Location;
import net.osmand.PlatformUtil;
+import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.telegram.TelegramApplication;
import net.osmand.util.Algorithms;
@@ -49,7 +50,7 @@ import java.util.Set;
import java.util.Stack;
import java.util.TimeZone;
-// copy from net.osmand.plus.GPXUtilities and changes done to WptPt (userId,chatId)
+// copy from net.osmand.plus.GPXUtilities and changes done to WptPt and GPXFile (userId,chatId)
public class GPXUtilities {
public final static Log log = PlatformUtil.getLog(GPXUtilities.class);
@@ -815,6 +816,8 @@ public class GPXUtilities {
public String path = "";
public boolean showCurrentTrack;
public long modifiedTime = 0;
+ public int userId;
+ public long chatId;
private Track generalTrack;
private TrkSegment generalSegment;
@@ -1248,6 +1251,57 @@ public class GPXUtilities {
}
return categories;
}
+
+ public QuadRect getRect() {
+ double left = 0, right = 0;
+ double top = 0, bottom = 0;
+ for (Track track : tracks) {
+ for (TrkSegment segment : track.segments) {
+ for (WptPt p : segment.points) {
+ if (left == 0 && right == 0) {
+ left = p.getLongitude();
+ right = p.getLongitude();
+ top = p.getLatitude();
+ bottom = p.getLatitude();
+ } else {
+ left = Math.min(left, p.getLongitude());
+ right = Math.max(right, p.getLongitude());
+ top = Math.max(top, p.getLatitude());
+ bottom = Math.min(bottom, p.getLatitude());
+ }
+ }
+ }
+ }
+ for (WptPt p : points) {
+ if (left == 0 && right == 0) {
+ left = p.getLongitude();
+ right = p.getLongitude();
+ top = p.getLatitude();
+ bottom = p.getLatitude();
+ } else {
+ left = Math.min(left, p.getLongitude());
+ right = Math.max(right, p.getLongitude());
+ top = Math.max(top, p.getLatitude());
+ bottom = Math.min(bottom, p.getLatitude());
+ }
+ }
+ for (GPXUtilities.Route route : routes) {
+ for (WptPt p : route.points) {
+ if (left == 0 && right == 0) {
+ left = p.getLongitude();
+ right = p.getLongitude();
+ top = p.getLatitude();
+ bottom = p.getLatitude();
+ } else {
+ left = Math.min(left, p.getLongitude());
+ right = Math.max(right, p.getLongitude());
+ top = Math.max(top, p.getLatitude());
+ bottom = Math.min(bottom, p.getLatitude());
+ }
+ }
+ }
+ return new QuadRect(left, top, right, bottom);
+ }
}
public static String asString(GPXFile file, TelegramApplication ctx) {
diff --git a/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandFormatter.kt b/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandFormatter.kt
index 7e8e4d9b32..3a9719848a 100644
--- a/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandFormatter.kt
+++ b/OsmAnd-telegram/src/net/osmand/telegram/utils/OsmandFormatter.kt
@@ -23,6 +23,7 @@ object OsmandFormatter {
private const val SHORT_TIME_FORMAT = "%02d:%02d"
private const val SIMPLE_TIME_OF_DAY_FORMAT = "HH:mm"
private const val SIMPLE_DATE_FORMAT = "dd MMM HH:mm:ss"
+ private const val SHORT_DATE_FORMAT = "dd MMM yyyy"
private const val MIN_DURATION_FOR_DATE_FORMAT = 48 * 60 * 60
@@ -77,8 +78,13 @@ object OsmandFormatter {
}
}
- fun getFormattedDate(seconds: Long): String =
- SimpleDateFormat(SIMPLE_DATE_FORMAT, Locale.getDefault()).format(seconds * 1000L)
+ fun getFormattedDate(seconds: Long, shortFormat: Boolean = false): String {
+ return if (shortFormat) {
+ SimpleDateFormat(SIMPLE_DATE_FORMAT, Locale.getDefault()).format(seconds * 1000L)
+ } else {
+ SimpleDateFormat(SHORT_DATE_FORMAT, Locale.getDefault()).format(seconds * 1000L)
+ }
+ }
fun getListItemLiveTimeDescr(ctx: TelegramApplication, lastUpdated: Int, prefix: String = ""): String {
return if (lastUpdated > 0) {
diff --git a/OsmAnd/src/net/osmand/aidl/IOsmAndAidlCallback.aidl b/OsmAnd/src/net/osmand/aidl/IOsmAndAidlCallback.aidl
index 6baa3578a7..6f0cb8f65b 100644
--- a/OsmAnd/src/net/osmand/aidl/IOsmAndAidlCallback.aidl
+++ b/OsmAnd/src/net/osmand/aidl/IOsmAndAidlCallback.aidl
@@ -1,6 +1,7 @@
package net.osmand.aidl;
import net.osmand.aidl.search.SearchResult;
+import net.osmand.aidl.gpx.AGpxBitmap;
interface IOsmAndAidlCallback {
void onSearchComplete(in List resultSet);
@@ -8,4 +9,6 @@ interface IOsmAndAidlCallback {
void onUpdate();
void onAppInitialized();
+
+ void onGpxBitmapCreated(in AGpxBitmap bitmap);
}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/aidl/IOsmAndAidlInterface.aidl b/OsmAnd/src/net/osmand/aidl/IOsmAndAidlInterface.aidl
index b7ed9b1cef..af2423cd8b 100644
--- a/OsmAnd/src/net/osmand/aidl/IOsmAndAidlInterface.aidl
+++ b/OsmAnd/src/net/osmand/aidl/IOsmAndAidlInterface.aidl
@@ -74,6 +74,8 @@ import net.osmand.aidl.customization.OsmandSettingsParams;
import net.osmand.aidl.gpx.AGpxFile;
import net.osmand.aidl.gpx.AGpxFileDetails;
+import net.osmand.aidl.gpx.CreateGpxBitmapParams;
+
import net.osmand.aidl.tiles.ASqliteDbFile;
import net.osmand.aidl.plugins.PluginParams;
@@ -175,4 +177,6 @@ interface IOsmAndAidlInterface {
boolean changePluginState(in PluginParams params);
boolean registerForOsmandInitListener(in IOsmAndAidlCallback callback);
+
+ boolean getBitmapForGpx(in CreateGpxBitmapParams file, IOsmAndAidlCallback callback);
}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java b/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java
index 8ec5eb8317..5f833bd475 100644
--- a/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java
+++ b/OsmAnd/src/net/osmand/aidl/OsmandAidlApi.java
@@ -10,6 +10,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
+import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.net.Uri;
import android.os.AsyncTask;
@@ -24,10 +25,12 @@ import android.text.TextUtils;
import android.view.View;
import android.widget.ArrayAdapter;
+import net.osmand.CallbackWithObject;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.aidl.favorite.AFavorite;
import net.osmand.aidl.favorite.group.AFavoriteGroup;
+import net.osmand.aidl.gpx.AGpxBitmap;
import net.osmand.aidl.gpx.AGpxFile;
import net.osmand.aidl.gpx.AGpxFileDetails;
import net.osmand.aidl.gpx.ASelectedGpxFile;
@@ -69,6 +72,7 @@ import net.osmand.plus.dialogs.ConfigureMapMenu;
import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.helpers.ExternalApiHelper;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
+import net.osmand.plus.myplaces.TrackBitmapDrawer;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.routing.RoutingHelper;
import net.osmand.plus.views.AidlMapLayer;
@@ -1907,7 +1911,96 @@ public class OsmandAidlApi {
return app.getAppCustomization().changePluginStatus(params);
}
+ boolean getBitmapForGpx(final Uri gpxUri, final float density, final int widthPixels, final int heightPixels, final int color, final GpxBitmapCreatedCallback callback) {
+ if (gpxUri == null || callback == null) {
+ return false;
+ }
+ final TrackBitmapDrawer.TrackBitmapDrawerListener drawerListener = new TrackBitmapDrawer.TrackBitmapDrawerListener() {
+ @Override
+ public void onTrackBitmapDrawing() {
+ }
+ @Override
+ public void onTrackBitmapDrawn() {
+ }
+
+ @Override
+ public boolean isTrackBitmapSelectionSupported() {
+ return false;
+ }
+
+ @Override
+ public void drawTrackBitmap(Bitmap bitmap) {
+ callback.onGpxBitmapCreatedComplete(new AGpxBitmap(bitmap));
+ }
+ };
+
+ if (app.isApplicationInitializing()) {
+ app.getAppInitializer().addListener(new AppInitializer.AppInitializeListener() {
+ @Override
+ public void onProgress(AppInitializer init, AppInitializer.InitEvents event) {
+ }
+
+ @Override
+ public void onFinish(AppInitializer init) {
+ createGpxBitmapFromUri(gpxUri, density, widthPixels, heightPixels, color, drawerListener);
+ }
+ });
+ } else {
+ createGpxBitmapFromUri(gpxUri, density, widthPixels, heightPixels, color, drawerListener);
+ }
+ return true;
+ }
+
+ private void createGpxBitmapFromUri(final Uri gpxUri, final float density, final int widthPixels, final int heightPixels, final int color, final TrackBitmapDrawer.TrackBitmapDrawerListener drawerListener) {
+ GpxAsyncLoaderTask gpxAsyncLoaderTask = new GpxAsyncLoaderTask(app, gpxUri, new CallbackWithObject() {
+ @Override
+ public boolean processResult(GPXFile result) {
+ TrackBitmapDrawer trackBitmapDrawer = new TrackBitmapDrawer(app, result, null, result.getRect(), density, widthPixels, heightPixels);
+ trackBitmapDrawer.addListener(drawerListener);
+ trackBitmapDrawer.setDrawEnabled(true);
+ trackBitmapDrawer.setTrackColor(color);
+ trackBitmapDrawer.initAndDraw();
+ return false;
+ }
+ });
+ gpxAsyncLoaderTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ }
+
+ private static class GpxAsyncLoaderTask extends AsyncTask {
+
+ private final OsmandApplication app;
+ private final CallbackWithObject callback;
+ private final Uri gpxUri;
+
+ GpxAsyncLoaderTask(@NonNull OsmandApplication app, @NonNull Uri gpxUri, final CallbackWithObject callback) {
+ this.app = app;
+ this.gpxUri = gpxUri;
+ this.callback = callback;
+ }
+
+ @Override
+ protected void onPostExecute(GPXFile gpxFile) {
+ if (gpxFile.warning == null && callback != null) {
+ callback.processResult(gpxFile);
+ }
+ }
+
+ @Override
+ protected GPXFile doInBackground(Void... voids) {
+ ParcelFileDescriptor gpxParcelDescriptor = null;
+ try {
+ gpxParcelDescriptor = app.getContentResolver().openFileDescriptor(gpxUri, "r");
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ if (gpxParcelDescriptor != null) {
+ final FileDescriptor fileDescriptor = gpxParcelDescriptor.getFileDescriptor();
+ return GPXUtilities.loadGPXFile(app, new FileInputStream(fileDescriptor));
+ }
+ return null;
+ }
+ }
private static AGpxFileDetails createGpxFileDetails(@NonNull GPXTrackAnalysis a) {
return new AGpxFileDetails(a.totalDistance, a.totalTracks, a.startTime, a.endTime,
@@ -1980,6 +2073,10 @@ public class OsmandAidlApi {
void onSearchComplete(List resultSet);
}
+ public interface GpxBitmapCreatedCallback {
+ void onGpxBitmapCreatedComplete(AGpxBitmap aGpxBitmap);
+ }
+
public interface OsmandAppInitCallback {
void onAppInitialized();
}
diff --git a/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java b/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java
index f8d2c0d30b..949b589fe5 100644
--- a/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java
+++ b/OsmAnd/src/net/osmand/aidl/OsmandAidlService.java
@@ -11,6 +11,7 @@ import android.os.RemoteException;
import android.support.annotation.Nullable;
import net.osmand.PlatformUtil;
+import net.osmand.aidl.OsmandAidlApi.GpxBitmapCreatedCallback;
import net.osmand.aidl.OsmandAidlApi.OsmandAppInitCallback;
import net.osmand.aidl.OsmandAidlApi.SearchCompleteCallback;
import net.osmand.aidl.calculateroute.CalculateRouteParams;
@@ -22,8 +23,10 @@ import net.osmand.aidl.favorite.UpdateFavoriteParams;
import net.osmand.aidl.favorite.group.AddFavoriteGroupParams;
import net.osmand.aidl.favorite.group.RemoveFavoriteGroupParams;
import net.osmand.aidl.favorite.group.UpdateFavoriteGroupParams;
+import net.osmand.aidl.gpx.AGpxBitmap;
import net.osmand.aidl.gpx.AGpxFile;
import net.osmand.aidl.gpx.ASelectedGpxFile;
+import net.osmand.aidl.gpx.CreateGpxBitmapParams;
import net.osmand.aidl.gpx.HideGpxParams;
import net.osmand.aidl.gpx.ImportGpxParams;
import net.osmand.aidl.gpx.RemoveGpxParams;
@@ -822,5 +825,25 @@ public class OsmandAidlService extends Service {
return false;
}
}
+
+ @Override
+ public boolean getBitmapForGpx(CreateGpxBitmapParams params, final IOsmAndAidlCallback callback) throws RemoteException {
+ try {
+ OsmandAidlApi api = getApi("getBitmapForGpx");
+ return params != null && api != null && api.getBitmapForGpx(params.getGpxUri(), params.getDensity(), params.getWidthPixels(), params.getHeightPixels(), params.getColor(), new GpxBitmapCreatedCallback() {
+ @Override
+ public void onGpxBitmapCreatedComplete(AGpxBitmap aGpxBitmap) {
+ try {
+ callback.onGpxBitmapCreated(aGpxBitmap);
+ } catch (RemoteException e) {
+ handleException(e);
+ }
+ }
+ });
+ } catch (Exception e) {
+ handleException(e);
+ return false;
+ }
+ }
};
}
diff --git a/OsmAnd/src/net/osmand/aidl/gpx/AGpxBitmap.aidl b/OsmAnd/src/net/osmand/aidl/gpx/AGpxBitmap.aidl
new file mode 100644
index 0000000000..ca9f623833
--- /dev/null
+++ b/OsmAnd/src/net/osmand/aidl/gpx/AGpxBitmap.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.gpx;
+
+parcelable AGpxBitmap;
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/aidl/gpx/AGpxBitmap.java b/OsmAnd/src/net/osmand/aidl/gpx/AGpxBitmap.java
new file mode 100644
index 0000000000..f4bdef433d
--- /dev/null
+++ b/OsmAnd/src/net/osmand/aidl/gpx/AGpxBitmap.java
@@ -0,0 +1,46 @@
+package net.osmand.aidl.gpx;
+
+import android.graphics.Bitmap;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.support.annotation.NonNull;
+
+public class AGpxBitmap implements Parcelable {
+
+ private Bitmap bitmap;
+
+ public AGpxBitmap(@NonNull Bitmap bitmap) {
+ this.bitmap = bitmap;
+ }
+
+ public AGpxBitmap(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public Bitmap getBitmap() {
+ return bitmap;
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public AGpxBitmap createFromParcel(Parcel in) {
+ return new AGpxBitmap(in);
+ }
+
+ public AGpxBitmap[] newArray(int size) {
+ return new AGpxBitmap[size];
+ }
+ };
+
+ public void writeToParcel(Parcel out, int flags) {
+ out.writeParcelable(bitmap, flags);
+ }
+
+ private void readFromParcel(Parcel in) {
+ bitmap = in.readParcelable(Bitmap.class.getClassLoader());
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
diff --git a/OsmAnd/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.aidl b/OsmAnd/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.aidl
new file mode 100644
index 0000000000..b02d5c6e70
--- /dev/null
+++ b/OsmAnd/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.aidl
@@ -0,0 +1,3 @@
+package net.osmand.aidl.gpx;
+
+parcelable CreateGpxBitmapParams;
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.java b/OsmAnd/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.java
new file mode 100644
index 0000000000..b6af1d354c
--- /dev/null
+++ b/OsmAnd/src/net/osmand/aidl/gpx/CreateGpxBitmapParams.java
@@ -0,0 +1,101 @@
+package net.osmand.aidl.gpx;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.io.File;
+
+public class CreateGpxBitmapParams implements Parcelable {
+
+ private File gpxFile;
+ private Uri gpxUri;
+ private float density;
+ private int widthPixels;
+ private int heightPixels;
+ private int color; //ARGB color int
+
+ public CreateGpxBitmapParams(File gpxFile, float density, int widthPixels, int heightPixels, int color) {
+ this.gpxFile = gpxFile;
+ this.density = density;
+ this.widthPixels = widthPixels;
+ this.heightPixels = heightPixels;
+ this.color = color;
+ }
+
+ public CreateGpxBitmapParams(Uri gpxUri, float density, int widthPixels, int heightPixels, int color) {
+ this.gpxUri = gpxUri;
+ this.density = density;
+ this.widthPixels = widthPixels;
+ this.heightPixels = heightPixels;
+ this.color = color;
+ }
+
+ public CreateGpxBitmapParams(Parcel in) {
+ readFromParcel(in);
+ }
+
+ public static final Creator CREATOR = new
+ Creator() {
+ public CreateGpxBitmapParams createFromParcel(Parcel in) {
+ return new CreateGpxBitmapParams(in);
+ }
+
+ public CreateGpxBitmapParams[] newArray(int size) {
+ return new CreateGpxBitmapParams[size];
+ }
+ };
+
+ public File getGpxFile() {
+ return gpxFile;
+ }
+
+ public Uri getGpxUri() {
+ return gpxUri;
+ }
+
+ public int getWidthPixels() {
+ return widthPixels;
+ }
+
+ public int getHeightPixels() {
+ return heightPixels;
+ }
+
+ public float getDensity() {
+ return density;
+ }
+
+ public int getColor() {
+ return color;
+ }
+
+ public void writeToParcel(Parcel out, int flags) {
+ if (gpxFile != null) {
+ out.writeString(gpxFile.getAbsolutePath());
+ } else {
+ out.writeString(null);
+ }
+ out.writeParcelable(gpxUri, flags);
+ out.writeFloat(density);
+ out.writeInt(widthPixels);
+ out.writeInt(heightPixels);
+ out.writeInt(color);
+ }
+
+ private void readFromParcel(Parcel in) {
+ String gpxAbsolutePath = in.readString();
+ if (gpxAbsolutePath != null) {
+ gpxFile = new File(gpxAbsolutePath);
+ }
+ gpxUri = in.readParcelable(Uri.class.getClassLoader());
+ density = in.readFloat();
+ widthPixels = in.readInt();
+ heightPixels = in.readInt();
+ color = in.readInt();
+ }
+
+ public int describeContents() {
+ return 0;
+ }
+}
\ No newline at end of file
diff --git a/OsmAnd/src/net/osmand/plus/GPXUtilities.java b/OsmAnd/src/net/osmand/plus/GPXUtilities.java
index 166aa89fce..ccc1c3b33f 100644
--- a/OsmAnd/src/net/osmand/plus/GPXUtilities.java
+++ b/OsmAnd/src/net/osmand/plus/GPXUtilities.java
@@ -13,6 +13,7 @@ import net.osmand.Location;
import net.osmand.PlatformUtil;
import net.osmand.data.LocationPoint;
import net.osmand.data.PointDescription;
+import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.plus.views.Renderable;
import net.osmand.util.Algorithms;
@@ -1247,6 +1248,57 @@ public class GPXUtilities {
}
return categories;
}
+
+ public QuadRect getRect() {
+ double left = 0, right = 0;
+ double top = 0, bottom = 0;
+ for (Track track : tracks) {
+ for (TrkSegment segment : track.segments) {
+ for (WptPt p : segment.points) {
+ if (left == 0 && right == 0) {
+ left = p.getLongitude();
+ right = p.getLongitude();
+ top = p.getLatitude();
+ bottom = p.getLatitude();
+ } else {
+ left = Math.min(left, p.getLongitude());
+ right = Math.max(right, p.getLongitude());
+ top = Math.max(top, p.getLatitude());
+ bottom = Math.min(bottom, p.getLatitude());
+ }
+ }
+ }
+ }
+ for (WptPt p : points) {
+ if (left == 0 && right == 0) {
+ left = p.getLongitude();
+ right = p.getLongitude();
+ top = p.getLatitude();
+ bottom = p.getLatitude();
+ } else {
+ left = Math.min(left, p.getLongitude());
+ right = Math.max(right, p.getLongitude());
+ top = Math.max(top, p.getLatitude());
+ bottom = Math.min(bottom, p.getLatitude());
+ }
+ }
+ for (GPXUtilities.Route route : routes) {
+ for (WptPt p : route.points) {
+ if (left == 0 && right == 0) {
+ left = p.getLongitude();
+ right = p.getLongitude();
+ top = p.getLatitude();
+ bottom = p.getLatitude();
+ } else {
+ left = Math.min(left, p.getLongitude());
+ right = Math.max(right, p.getLongitude());
+ top = Math.max(top, p.getLatitude());
+ bottom = Math.min(bottom, p.getLatitude());
+ }
+ }
+ }
+ return new QuadRect(left, top, right, bottom);
+ }
}
public static String asString(GPXFile file, OsmandApplication ctx) {
diff --git a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java
index 564fc109ba..3b01d00303 100644
--- a/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java
+++ b/OsmAnd/src/net/osmand/plus/activities/TrackActivity.java
@@ -1,5 +1,6 @@
package net.osmand.plus.activities;
+import android.content.Context;
import android.content.Intent;
import android.content.res.ColorStateList;
import android.os.AsyncTask;
@@ -9,9 +10,11 @@ import android.support.annotation.Nullable;
import android.support.design.widget.BottomNavigationView;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBar;
+import android.util.DisplayMetrics;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
+import android.view.WindowManager;
import net.osmand.AndroidUtils;
import net.osmand.data.LatLon;
@@ -20,7 +23,6 @@ import net.osmand.data.QuadRect;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.GPXUtilities.GPXFile;
-import net.osmand.plus.GPXUtilities.Track;
import net.osmand.plus.GPXUtilities.TrkSegment;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.GpxSelectionHelper;
@@ -35,7 +37,6 @@ import net.osmand.plus.mapmarkers.CoordinateInputDialogFragment;
import net.osmand.plus.measurementtool.NewGpxData;
import net.osmand.plus.myplaces.FavoritesActivity;
import net.osmand.plus.myplaces.SplitSegmentDialogFragment;
-import net.osmand.plus.myplaces.TrackActivityFragmentAdapter;
import net.osmand.plus.myplaces.TrackBitmapDrawer;
import net.osmand.plus.myplaces.TrackBitmapDrawer.TrackBitmapDrawerListener;
import net.osmand.plus.myplaces.TrackPointFragment;
@@ -156,56 +157,11 @@ public class TrackActivity extends TabActivity {
}
public QuadRect getRect() {
- double left = 0, right = 0;
- double top = 0, bottom = 0;
if (getGpx() != null) {
- for (Track track : getGpx().tracks) {
- for (TrkSegment segment : track.segments) {
- for (WptPt p : segment.points) {
- if (left == 0 && right == 0) {
- left = p.getLongitude();
- right = p.getLongitude();
- top = p.getLatitude();
- bottom = p.getLatitude();
- } else {
- left = Math.min(left, p.getLongitude());
- right = Math.max(right, p.getLongitude());
- top = Math.max(top, p.getLatitude());
- bottom = Math.min(bottom, p.getLatitude());
- }
- }
- }
- }
- for (WptPt p : getGpx().getPoints()) {
- if (left == 0 && right == 0) {
- left = p.getLongitude();
- right = p.getLongitude();
- top = p.getLatitude();
- bottom = p.getLatitude();
- } else {
- left = Math.min(left, p.getLongitude());
- right = Math.max(right, p.getLongitude());
- top = Math.max(top, p.getLatitude());
- bottom = Math.min(bottom, p.getLatitude());
- }
- }
- for (GPXUtilities.Route route : getGpx().routes) {
- for (WptPt p : route.points) {
- if (left == 0 && right == 0) {
- left = p.getLongitude();
- right = p.getLongitude();
- top = p.getLatitude();
- bottom = p.getLatitude();
- } else {
- left = Math.min(left, p.getLongitude());
- right = Math.max(right, p.getLongitude());
- top = Math.max(top, p.getLatitude());
- bottom = Math.min(bottom, p.getLatitude());
- }
- }
- }
+ return getGpx().getRect();
+ } else {
+ return new QuadRect(0, 0, 0, 0);
}
- return new QuadRect(left, top, right, bottom);
}
protected void setGpxDataItem(GpxDataItem gpxDataItem) {
@@ -383,8 +339,11 @@ public class TrackActivity extends TabActivity {
setGpx(gpxFile);
setGpxDataItem(file != null ? app.getGpxDatabase().getItem(file) : null);
- if (gpxFile != null) {
- trackBitmapDrawer = new TrackBitmapDrawer(this, gpxFile, getGpxDataItem(), getRect());
+ WindowManager mgr = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
+ if (gpxFile != null && mgr != null) {
+ DisplayMetrics dm = new DisplayMetrics();
+ mgr.getDefaultDisplay().getMetrics(dm);
+ trackBitmapDrawer = new TrackBitmapDrawer(app, gpxFile, getGpxDataItem(), getRect(), dm.density, dm.widthPixels, AndroidUtils.dpToPx(app, 152f));
}
for (WeakReference f : fragList) {
diff --git a/OsmAnd/src/net/osmand/plus/myplaces/TrackBitmapDrawer.java b/OsmAnd/src/net/osmand/plus/myplaces/TrackBitmapDrawer.java
index de4df5d6b3..df3a5fa23e 100644
--- a/OsmAnd/src/net/osmand/plus/myplaces/TrackBitmapDrawer.java
+++ b/OsmAnd/src/net/osmand/plus/myplaces/TrackBitmapDrawer.java
@@ -1,7 +1,5 @@
package net.osmand.plus.myplaces;
-import android.app.Activity;
-import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
@@ -12,8 +10,6 @@ import android.support.annotation.ColorInt;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
-import android.util.DisplayMetrics;
-import android.view.WindowManager;
import net.osmand.AndroidUtils;
import net.osmand.data.LatLon;
@@ -32,15 +28,16 @@ import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.views.OsmandMapLayer.DrawSettings;
import net.osmand.plus.views.Renderable;
-import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.List;
public class TrackBitmapDrawer {
private OsmandApplication app;
- private WeakReference activityRef;
private QuadRect rect;
+ private float density;
+ private int widthPixels;
+ private int heightPixels;
private boolean drawEnabled;
private RotatedTileBox rotatedTileBox;
@@ -69,11 +66,13 @@ public class TrackBitmapDrawer {
void drawTrackBitmap(Bitmap bitmap);
}
- public TrackBitmapDrawer(@NonNull Activity activity, @NonNull GPXFile gpxFile,
- @Nullable GpxDataItem gpxDataItem, @NonNull QuadRect rect) {
- this.activityRef = new WeakReference<>(activity);
+ public TrackBitmapDrawer(@NonNull OsmandApplication app, @NonNull GPXFile gpxFile,
+ @Nullable GpxDataItem gpxDataItem, @NonNull QuadRect rect, float density, int widthPixels, int heightPixels) {
+ this.density = density;
+ this.widthPixels = widthPixels;
+ this.heightPixels = heightPixels;
this.rect = rect;
- this.app = (OsmandApplication) activity.getApplication();
+ this.app = app;
this.gpxFile = gpxFile;
this.gpxDataItem = gpxDataItem;
@@ -83,8 +82,8 @@ public class TrackBitmapDrawer {
paint.setStrokeWidth(AndroidUtils.dpToPx(app, 4f));
defPointColor = ContextCompat.getColor(app, R.color.gpx_color_point);
paintIcon = new Paint();
- pointSmall = BitmapFactory.decodeResource(activity.getResources(), R.drawable.map_white_shield_small);
- selectedPoint = BitmapFactory.decodeResource(activity.getResources(), R.drawable.map_default_location);
+ pointSmall = BitmapFactory.decodeResource(app.getResources(), R.drawable.map_white_shield_small);
+ selectedPoint = BitmapFactory.decodeResource(app.getResources(), R.drawable.map_default_location);
}
public void addListener(TrackBitmapDrawerListener l) {
@@ -150,54 +149,48 @@ public class TrackBitmapDrawer {
}
public boolean initAndDraw() {
- Activity activity = activityRef.get();
- if (activity != null) {
- WindowManager mgr = (WindowManager) activity.getSystemService(Context.WINDOW_SERVICE);
- if (mgr != null && rect != null && rect.left != 0 && rect.top != 0) {
- notifyDrawing();
+ if (rect != null && rect.left != 0 && rect.top != 0) {
+ notifyDrawing();
- double clat = rect.bottom / 2 + rect.top / 2;
- double clon = rect.left / 2 + rect.right / 2;
- DisplayMetrics dm = new DisplayMetrics();
- mgr.getDefaultDisplay().getMetrics(dm);
- RotatedTileBox.RotatedTileBoxBuilder boxBuilder = new RotatedTileBox.RotatedTileBoxBuilder()
- .setLocation(clat, clon)
- .setZoom(15)
- .density(dm.density)
- .setPixelDimensions(dm.widthPixels, AndroidUtils.dpToPx(app, 152f), 0.5f, 0.5f);
+ double clat = rect.bottom / 2 + rect.top / 2;
+ double clon = rect.left / 2 + rect.right / 2;
+ RotatedTileBox.RotatedTileBoxBuilder boxBuilder = new RotatedTileBox.RotatedTileBoxBuilder()
+ .setLocation(clat, clon)
+ .setZoom(15)
+ .density(density)
+ .setPixelDimensions(widthPixels, heightPixels, 0.5f, 0.5f);
- rotatedTileBox = boxBuilder.build();
- while (rotatedTileBox.getZoom() < 17 && rotatedTileBox.containsLatLon(rect.top, rect.left) && rotatedTileBox.containsLatLon(rect.bottom, rect.right)) {
- rotatedTileBox.setZoom(rotatedTileBox.getZoom() + 1);
- }
- while (rotatedTileBox.getZoom() >= 7 && (!rotatedTileBox.containsLatLon(rect.top, rect.left) || !rotatedTileBox.containsLatLon(rect.bottom, rect.right))) {
- rotatedTileBox.setZoom(rotatedTileBox.getZoom() - 1);
- }
+ rotatedTileBox = boxBuilder.build();
+ while (rotatedTileBox.getZoom() < 17 && rotatedTileBox.containsLatLon(rect.top, rect.left) && rotatedTileBox.containsLatLon(rect.bottom, rect.right)) {
+ rotatedTileBox.setZoom(rotatedTileBox.getZoom() + 1);
+ }
+ while (rotatedTileBox.getZoom() >= 7 && (!rotatedTileBox.containsLatLon(rect.top, rect.left) || !rotatedTileBox.containsLatLon(rect.bottom, rect.right))) {
+ rotatedTileBox.setZoom(rotatedTileBox.getZoom() - 1);
+ }
- final DrawSettings drawSettings = new DrawSettings(!app.getSettings().isLightContent(), true);
- final ResourceManager resourceManager = app.getResourceManager();
- final MapRenderRepositories renderer = resourceManager.getRenderer();
- if (resourceManager.updateRenderedMapNeeded(rotatedTileBox, drawSettings)) {
- resourceManager.updateRendererMap(rotatedTileBox, new OnMapLoadedListener() {
- @Override
- public void onMapLoaded(boolean interrupted) {
- app.runInUIThread(new Runnable() {
- @Override
- public void run() {
- if (isDrawEnabled()) {
- mapBitmap = renderer.getBitmap();
- if (mapBitmap != null) {
- notifyDrawn();
- refreshTrackBitmap();
- }
+ final DrawSettings drawSettings = new DrawSettings(!app.getSettings().isLightContent(), true);
+ final ResourceManager resourceManager = app.getResourceManager();
+ final MapRenderRepositories renderer = resourceManager.getRenderer();
+ if (resourceManager.updateRenderedMapNeeded(rotatedTileBox, drawSettings)) {
+ resourceManager.updateRendererMap(rotatedTileBox, new OnMapLoadedListener() {
+ @Override
+ public void onMapLoaded(boolean interrupted) {
+ app.runInUIThread(new Runnable() {
+ @Override
+ public void run() {
+ if (isDrawEnabled()) {
+ mapBitmap = renderer.getBitmap();
+ if (mapBitmap != null) {
+ notifyDrawn();
+ refreshTrackBitmap();
}
}
- });
- }
- });
- }
- return true;
+ }
+ });
+ }
+ });
}
+ return true;
}
return false;
}