kopia lustrzana https://github.com/sh123/codec2_talkie
Refactoring
rodzic
370ef3f2db
commit
6b119b892d
|
@ -62,7 +62,7 @@ public class MapStations {
|
||||||
|
|
||||||
_aprsSymbolTable = AprsSymbolTable.getInstance(context);
|
_aprsSymbolTable = AprsSymbolTable.getInstance(context);
|
||||||
_infoWindow = new MarkerInfoWindow(R.layout.bonuspack_bubble, _mapView);
|
_infoWindow = new MarkerInfoWindow(R.layout.bonuspack_bubble, _mapView);
|
||||||
_activeTrack = new MapTrack(_mapView, _owner);
|
_activeTrack = new MapTrack(_context, _mapView, _owner);
|
||||||
|
|
||||||
StationItemViewModel _stationItemViewModel = new ViewModelProvider(_owner).get(StationItemViewModel.class);
|
StationItemViewModel _stationItemViewModel = new ViewModelProvider(_owner).get(StationItemViewModel.class);
|
||||||
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
|
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
|
||||||
|
@ -138,70 +138,22 @@ public class MapStations {
|
||||||
|
|
||||||
// create new marker
|
// create new marker
|
||||||
if (marker == null) {
|
if (marker == null) {
|
||||||
// icon from symbol
|
|
||||||
Bitmap bitmapIcon = _aprsSymbolTable.bitmapFromSymbol(group.getSymbolCode(), false);
|
|
||||||
if (bitmapIcon == null) return false;
|
|
||||||
Bitmap bitmapInfoIcon = _aprsSymbolTable.bitmapFromSymbol(group.getSymbolCode(), true);
|
Bitmap bitmapInfoIcon = _aprsSymbolTable.bitmapFromSymbol(group.getSymbolCode(), true);
|
||||||
if (bitmapInfoIcon == null) return false;
|
if (bitmapInfoIcon == null) return false;
|
||||||
|
|
||||||
// construct and calculate bounds
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setStyle(Paint.Style.FILL);
|
|
||||||
Rect bounds = new Rect();
|
|
||||||
paint.getTextBounds(callsign, 0, callsign.length(), bounds);
|
|
||||||
int width = Math.max(bitmapIcon.getWidth(), bounds.width());
|
|
||||||
int height = bitmapIcon.getHeight() + bounds.height();
|
|
||||||
|
|
||||||
// create overlay bitmap
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(width, height, null);
|
|
||||||
bitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT);
|
|
||||||
|
|
||||||
// draw APRS icon
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
float bitmapLeft = width > bitmapIcon.getWidth() ? width / 2.0f - bitmapIcon.getWidth() / 2.0f : 0;
|
|
||||||
// do not rotate
|
|
||||||
if (group.getBearingDegrees() == 0 || !AprsSymbolTable.needsRotation(group.getSymbolCode())) {
|
|
||||||
canvas.drawBitmap(bitmapIcon, bitmapLeft, 0, null);
|
|
||||||
// rotate
|
|
||||||
} else {
|
|
||||||
float rotationDeg = (float) (group.getBearingDegrees() - 90.0f);
|
|
||||||
Matrix m = new Matrix();
|
|
||||||
// flip/rotate
|
|
||||||
if (group.getBearingDegrees() > 180) {
|
|
||||||
m.postScale(-1, 1);
|
|
||||||
m.postTranslate(bitmapIcon.getWidth(), 0);
|
|
||||||
m.postRotate(rotationDeg - 180, bitmapIcon.getWidth() / 2.0f, bitmapIcon.getHeight() / 2.0f);
|
|
||||||
// rotate
|
|
||||||
} else {
|
|
||||||
m.postRotate(rotationDeg, bitmapIcon.getWidth() / 2.0f, bitmapIcon.getHeight() / 2.0f);
|
|
||||||
}
|
|
||||||
m.postTranslate(bitmapLeft, 0);
|
|
||||||
canvas.drawBitmap(bitmapIcon, m, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw background
|
|
||||||
paint.setColor(Color.WHITE);
|
|
||||||
paint.setAlpha(120);
|
|
||||||
bounds.set(0, bitmapIcon.getHeight(), width, height);
|
|
||||||
canvas.drawRect(bounds, paint);
|
|
||||||
|
|
||||||
// draw text
|
|
||||||
paint.setColor(Color.BLACK);
|
|
||||||
paint.setAlpha(255);
|
|
||||||
paint.setTextSize(12);
|
|
||||||
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
|
||||||
canvas.drawText(callsign, 0, height, paint);
|
|
||||||
|
|
||||||
// add marker
|
// add marker
|
||||||
BitmapDrawable drawableText = new BitmapDrawable(_context.getResources(), bitmap);
|
BitmapDrawable drawableText = group.drawLabelWithIcon(_context, 12);
|
||||||
BitmapDrawable drawableInfoIcon = new BitmapDrawable(_context.getResources(), bitmapInfoIcon);
|
BitmapDrawable drawableInfoIcon = new BitmapDrawable(_context.getResources(), bitmapInfoIcon);
|
||||||
marker = new Marker(_mapView);
|
marker = new Marker(_mapView);
|
||||||
marker.setId(callsign);
|
marker.setId(callsign);
|
||||||
marker.setIcon(drawableText);
|
if (drawableText == null)
|
||||||
|
Log.e(TAG, "Cannot load icon for " + callsign);
|
||||||
|
else
|
||||||
|
marker.setIcon(drawableText);
|
||||||
marker.setImage(drawableInfoIcon);
|
marker.setImage(drawableInfoIcon);
|
||||||
marker.setOnMarkerClickListener((monitoredStationMarker, mapView) -> {
|
marker.setOnMarkerClickListener((monitoredStationMarker, mapView) -> {
|
||||||
GeoPoint markerPoint = monitoredStationMarker.getPosition();
|
GeoPoint markerPoint = monitoredStationMarker.getPosition();
|
||||||
_infoWindow.open(monitoredStationMarker, new GeoPoint(markerPoint.getLatitude(), markerPoint.getLongitude()), 0, -2*height);
|
_infoWindow.open(monitoredStationMarker, new GeoPoint(markerPoint.getLatitude(), markerPoint.getLongitude()), 0, -64);
|
||||||
_activeTrack.drawForStationMarker(monitoredStationMarker);
|
_activeTrack.drawForStationMarker(monitoredStationMarker);
|
||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,8 +1,14 @@
|
||||||
package com.radio.codec2talkie.maps;
|
package com.radio.codec2talkie.maps;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
import android.graphics.Color;
|
import android.graphics.Color;
|
||||||
import android.graphics.DashPathEffect;
|
import android.graphics.DashPathEffect;
|
||||||
import android.graphics.Paint;
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.lifecycle.LifecycleOwner;
|
import androidx.lifecycle.LifecycleOwner;
|
||||||
|
@ -10,8 +16,13 @@ import androidx.lifecycle.LiveData;
|
||||||
import androidx.lifecycle.ViewModelProvider;
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
import androidx.lifecycle.ViewModelStoreOwner;
|
import androidx.lifecycle.ViewModelStoreOwner;
|
||||||
|
|
||||||
|
import com.radio.codec2talkie.protocol.position.Position;
|
||||||
import com.radio.codec2talkie.storage.position.PositionItem;
|
import com.radio.codec2talkie.storage.position.PositionItem;
|
||||||
import com.radio.codec2talkie.storage.position.PositionItemViewModel;
|
import com.radio.codec2talkie.storage.position.PositionItemViewModel;
|
||||||
|
import com.radio.codec2talkie.storage.station.StationItem;
|
||||||
|
import com.radio.codec2talkie.tools.BitmapTools;
|
||||||
|
import com.radio.codec2talkie.tools.DateTools;
|
||||||
|
import com.radio.codec2talkie.tools.UnitTools;
|
||||||
|
|
||||||
import org.osmdroid.util.GeoPoint;
|
import org.osmdroid.util.GeoPoint;
|
||||||
import org.osmdroid.views.MapView;
|
import org.osmdroid.views.MapView;
|
||||||
|
@ -19,9 +30,10 @@ import org.osmdroid.views.overlay.Marker;
|
||||||
import org.osmdroid.views.overlay.Polyline;
|
import org.osmdroid.views.overlay.Polyline;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Locale;
|
||||||
|
|
||||||
public class MapTrack {
|
public class MapTrack {
|
||||||
private static final String TAG = MapTrack.class.getSimpleName();
|
private static final String TAG = MapTrack.class.getSimpleName();
|
||||||
|
@ -29,15 +41,23 @@ public class MapTrack {
|
||||||
private final PositionItemViewModel _positionItemViewModel;
|
private final PositionItemViewModel _positionItemViewModel;
|
||||||
private final ViewModelStoreOwner _owner;
|
private final ViewModelStoreOwner _owner;
|
||||||
private final MapView _mapView;
|
private final MapView _mapView;
|
||||||
|
private final Context _context;
|
||||||
|
|
||||||
|
// track db data
|
||||||
private LiveData<List<PositionItem>> _activeTrackLiveData;
|
private LiveData<List<PositionItem>> _activeTrackLiveData;
|
||||||
|
|
||||||
|
// track data
|
||||||
private final HashSet<Long> _activeTrackTimestamps = new HashSet<>();
|
private final HashSet<Long> _activeTrackTimestamps = new HashSet<>();
|
||||||
private final List<GeoPoint> _activeTrackPoints = new ArrayList<>();
|
private final List<GeoPoint> _activeTrackPoints = new ArrayList<>();
|
||||||
private final Polyline _activeTrackLine = new Polyline();
|
private final Polyline _activeTrackLine = new Polyline();
|
||||||
|
|
||||||
public MapTrack(MapView mapView, ViewModelStoreOwner owner) {
|
// track points
|
||||||
|
private final HashSet<Marker> _trackMarkers = new HashSet<>();
|
||||||
|
|
||||||
|
public MapTrack(Context context, MapView mapView, ViewModelStoreOwner owner) {
|
||||||
_owner = owner;
|
_owner = owner;
|
||||||
_mapView = mapView;
|
_mapView = mapView;
|
||||||
|
_context = context;
|
||||||
_positionItemViewModel = new ViewModelProvider(_owner).get(PositionItemViewModel.class);
|
_positionItemViewModel = new ViewModelProvider(_owner).get(PositionItemViewModel.class);
|
||||||
|
|
||||||
// initialize track
|
// initialize track
|
||||||
|
@ -52,11 +72,20 @@ public class MapTrack {
|
||||||
public void drawForStationMarker(Marker marker) {
|
public void drawForStationMarker(Marker marker) {
|
||||||
if (_activeTrackLiveData != null)
|
if (_activeTrackLiveData != null)
|
||||||
_activeTrackLiveData.removeObservers((LifecycleOwner) _owner);
|
_activeTrackLiveData.removeObservers((LifecycleOwner) _owner);
|
||||||
|
|
||||||
|
for (Marker trackMarker : _trackMarkers) {
|
||||||
|
_mapView.getOverlays().remove(trackMarker);
|
||||||
|
}
|
||||||
_mapView.getOverlays().remove(_activeTrackLine);
|
_mapView.getOverlays().remove(_activeTrackLine);
|
||||||
|
|
||||||
_activeTrackPoints.clear();
|
_activeTrackPoints.clear();
|
||||||
_activeTrackTimestamps.clear();
|
_activeTrackTimestamps.clear();
|
||||||
|
_trackMarkers.clear();
|
||||||
|
|
||||||
_activeTrackLine.setPoints(_activeTrackPoints);
|
_activeTrackLine.setPoints(_activeTrackPoints);
|
||||||
|
_activeTrackLine.setVisible(false);
|
||||||
_mapView.getOverlays().add(_activeTrackLine);
|
_mapView.getOverlays().add(_activeTrackLine);
|
||||||
|
|
||||||
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
|
// FIXME, room livedata sends all list if one item changed event with distinctUntilChanged
|
||||||
_activeTrackLiveData = _positionItemViewModel.getPositionItems(marker.getId());
|
_activeTrackLiveData = _positionItemViewModel.getPositionItems(marker.getId());
|
||||||
_activeTrackLiveData.observe((LifecycleOwner) _owner, this::addTrack);
|
_activeTrackLiveData.observe((LifecycleOwner) _owner, this::addTrack);
|
||||||
|
@ -66,14 +95,39 @@ public class MapTrack {
|
||||||
boolean shouldSet = false;
|
boolean shouldSet = false;
|
||||||
for (PositionItem trackPoint : positions) {
|
for (PositionItem trackPoint : positions) {
|
||||||
if (!_activeTrackTimestamps.contains(trackPoint.getTimestampEpoch())) {
|
if (!_activeTrackTimestamps.contains(trackPoint.getTimestampEpoch())) {
|
||||||
|
long pointTimestamp = trackPoint.getTimestampEpoch();
|
||||||
Log.i(TAG, "addPoint " + trackPoint.getTimestampEpoch() + " " + trackPoint.getLatitude() + " " + trackPoint.getLongitude());
|
Log.i(TAG, "addPoint " + trackPoint.getTimestampEpoch() + " " + trackPoint.getLatitude() + " " + trackPoint.getLongitude());
|
||||||
|
|
||||||
|
// add point into the line
|
||||||
GeoPoint point = new GeoPoint(trackPoint.getLatitude(), trackPoint.getLongitude());
|
GeoPoint point = new GeoPoint(trackPoint.getLatitude(), trackPoint.getLongitude());
|
||||||
_activeTrackPoints.add(point);
|
_activeTrackPoints.add(point);
|
||||||
_activeTrackTimestamps.add(trackPoint.getTimestampEpoch());
|
_activeTrackTimestamps.add(pointTimestamp);
|
||||||
|
if (_activeTrackPoints.size() > 1)
|
||||||
|
_activeTrackLine.setVisible(true);
|
||||||
|
|
||||||
|
// draw point marker with time
|
||||||
|
Marker marker = new Marker(_mapView);
|
||||||
|
marker.setIcon(BitmapTools.drawLabel(_context, DateTools.epochToIso8601Time(pointTimestamp), 11));
|
||||||
|
marker.setTitle(DateTools.epochToIso8601(pointTimestamp) + " " + trackPoint.getSrcCallsign());
|
||||||
|
marker.setSnippet(getStatus(trackPoint));
|
||||||
|
marker.setPosition(point);
|
||||||
|
_trackMarkers.add(marker);
|
||||||
|
_mapView.getOverlays().add(marker);
|
||||||
|
|
||||||
shouldSet = true;
|
shouldSet = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (shouldSet)
|
if (shouldSet)
|
||||||
_activeTrackLine.setPoints(_activeTrackPoints);
|
_activeTrackLine.setPoints(_activeTrackPoints);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String getStatus(PositionItem position) {
|
||||||
|
return String.format(Locale.US, "%s<br>%s %f %f<br>%03d° %03dkm/h %04dm<br>%s",
|
||||||
|
position.getDigipath(),
|
||||||
|
position.getMaidenHead(), position.getLatitude(), position.getLongitude(),
|
||||||
|
(int)position.getBearingDegrees(),
|
||||||
|
UnitTools.metersPerSecondToKilometersPerHour((int)position.getSpeedMetersPerSecond()),
|
||||||
|
(int)position.getAltitudeMeters(),
|
||||||
|
position.getComment());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,14 @@
|
||||||
package com.radio.codec2talkie.storage.station;
|
package com.radio.codec2talkie.storage.station;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Matrix;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
@ -7,6 +16,8 @@ import androidx.room.Entity;
|
||||||
import androidx.room.Index;
|
import androidx.room.Index;
|
||||||
import androidx.room.PrimaryKey;
|
import androidx.room.PrimaryKey;
|
||||||
|
|
||||||
|
import com.radio.codec2talkie.protocol.aprs.tools.AprsSymbolTable;
|
||||||
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@Entity(indices = {@Index(value = {"srcCallsign"}, unique = true)})
|
@Entity(indices = {@Index(value = {"srcCallsign"}, unique = true)})
|
||||||
|
@ -140,4 +151,62 @@ public class StationItem {
|
||||||
latitude == stationItem.getLatitude() &&
|
latitude == stationItem.getLatitude() &&
|
||||||
longitude == stationItem.getLongitude();
|
longitude == stationItem.getLongitude();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BitmapDrawable drawLabelWithIcon(Context context, float textSize) {
|
||||||
|
String callsign = getSrcCallsign();
|
||||||
|
|
||||||
|
Bitmap bitmapIcon = AprsSymbolTable.getInstance(context).bitmapFromSymbol(getSymbolCode(), false);
|
||||||
|
if (bitmapIcon == null) return null;
|
||||||
|
|
||||||
|
// construct and calculate bounds
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
paint.setTextSize(textSize);
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
paint.getTextBounds(callsign, 0, callsign.length(), bounds);
|
||||||
|
int width = Math.max(bitmapIcon.getWidth(), bounds.width());
|
||||||
|
int height = bitmapIcon.getHeight() + bounds.height();
|
||||||
|
|
||||||
|
// create overlay bitmap
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(width, height, null);
|
||||||
|
bitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT);
|
||||||
|
|
||||||
|
// draw APRS icon
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
float bitmapLeft = width > bitmapIcon.getWidth() ? width / 2.0f - bitmapIcon.getWidth() / 2.0f : 0;
|
||||||
|
// do not rotate
|
||||||
|
if (getBearingDegrees() == 0 || !AprsSymbolTable.needsRotation(getSymbolCode())) {
|
||||||
|
canvas.drawBitmap(bitmapIcon, bitmapLeft, 0, null);
|
||||||
|
// rotate
|
||||||
|
} else {
|
||||||
|
float rotationDeg = (float) (getBearingDegrees() - 90.0f);
|
||||||
|
Matrix m = new Matrix();
|
||||||
|
// flip/rotate
|
||||||
|
if (getBearingDegrees() > 180) {
|
||||||
|
m.postScale(-1, 1);
|
||||||
|
m.postTranslate(bitmapIcon.getWidth(), 0);
|
||||||
|
m.postRotate(rotationDeg - 180, bitmapIcon.getWidth() / 2.0f, bitmapIcon.getHeight() / 2.0f);
|
||||||
|
// rotate
|
||||||
|
} else {
|
||||||
|
m.postRotate(rotationDeg, bitmapIcon.getWidth() / 2.0f, bitmapIcon.getHeight() / 2.0f);
|
||||||
|
}
|
||||||
|
m.postTranslate(bitmapLeft, 0);
|
||||||
|
canvas.drawBitmap(bitmapIcon, m, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// draw background
|
||||||
|
paint.setColor(Color.WHITE);
|
||||||
|
paint.setAlpha(120);
|
||||||
|
bounds.set(0, bitmapIcon.getHeight(), width, height);
|
||||||
|
canvas.drawRect(bounds, paint);
|
||||||
|
|
||||||
|
// draw text
|
||||||
|
paint.setColor(Color.BLACK);
|
||||||
|
paint.setAlpha(255);
|
||||||
|
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
canvas.drawText(callsign, 0, height, paint);
|
||||||
|
|
||||||
|
// add marker
|
||||||
|
return new BitmapDrawable(context.getResources(), bitmap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
package com.radio.codec2talkie.tools;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.Canvas;
|
||||||
|
import android.graphics.Color;
|
||||||
|
import android.graphics.Paint;
|
||||||
|
import android.graphics.Rect;
|
||||||
|
import android.graphics.drawable.BitmapDrawable;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
|
||||||
|
public class BitmapTools {
|
||||||
|
public static BitmapDrawable drawLabel(Context context, String text, float textSize) {
|
||||||
|
Paint paint = new Paint();
|
||||||
|
paint.setStyle(Paint.Style.FILL);
|
||||||
|
paint.setTextSize(textSize);
|
||||||
|
|
||||||
|
Rect bounds = new Rect();
|
||||||
|
paint.getTextBounds(text, 0, text.length(), bounds);
|
||||||
|
|
||||||
|
Bitmap bitmap = Bitmap.createBitmap(bounds.width(), bounds.height(), null);
|
||||||
|
bitmap.setDensity(DisplayMetrics.DENSITY_DEFAULT);
|
||||||
|
|
||||||
|
Canvas canvas = new Canvas(bitmap);
|
||||||
|
|
||||||
|
paint.setColor(Color.WHITE);
|
||||||
|
//paint.setAlpha(200);
|
||||||
|
canvas.drawRect(0, 0, bounds.width(), bounds.height(), paint);
|
||||||
|
|
||||||
|
paint.setColor(Color.BLACK);
|
||||||
|
paint.setAlpha(255);
|
||||||
|
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
|
||||||
|
canvas.drawText(text, -bounds.left, bounds.height(), paint);
|
||||||
|
|
||||||
|
return new BitmapDrawable(context.getResources(), bitmap);
|
||||||
|
}
|
||||||
|
}
|
|
@ -13,6 +13,13 @@ public class DateTools {
|
||||||
return sdf.format(new Date(timeMilliseconds));
|
return sdf.format(new Date(timeMilliseconds));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String epochToIso8601Time(long timeMilliseconds) {
|
||||||
|
String format = "HH:mm:ss";
|
||||||
|
SimpleDateFormat sdf = new SimpleDateFormat(format, Locale.getDefault());
|
||||||
|
sdf.setTimeZone(TimeZone.getDefault());
|
||||||
|
return sdf.format(new Date(timeMilliseconds));
|
||||||
|
}
|
||||||
|
|
||||||
public static long currentTimestampMinusHours(int hours) {
|
public static long currentTimestampMinusHours(int hours) {
|
||||||
return System.currentTimeMillis() - (hours * 60L * 60L * 1000L);
|
return System.currentTimeMillis() - (hours * 60L * 60L * 1000L);
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue