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 androidx.annotation.NonNull; import androidx.room.Entity; import androidx.room.Index; import androidx.room.PrimaryKey; import com.radio.codec2talkie.protocol.aprs.tools.AprsSymbolTable; import java.util.Objects; @Entity(indices = {@Index(value = {"srcCallsign"}, unique = true)}) public class StationItem { @NonNull @PrimaryKey private String srcCallsign; private long timestampEpoch; public String dstCallsign; public String digipath; private String maidenHead; public double latitude; public double longitude; public double altitudeMeters; public double bearingDegrees; public double speedMetersPerSecond; public String status; public String comment; public String symbolCode; public String logLine; public int privacyLevel; public double rangeMiles; public int directivityDeg; public StationItem(@NonNull String srcCallsign) { this.srcCallsign = srcCallsign; } public long getTimestampEpoch() { return timestampEpoch; } public String getSrcCallsign() { return srcCallsign; } public String getDstCallsign() { return dstCallsign; } public String getDigipath() { return digipath; } public double getLatitude() { return latitude; } public double getLongitude() { return longitude; } public String getMaidenHead() { return maidenHead; } public double getAltitudeMeters() { return altitudeMeters; } public double getBearingDegrees() { return bearingDegrees; } public double getSpeedMetersPerSecond() { return speedMetersPerSecond; } public String getStatus() { return status; } public String getComment() { return comment; } public String getSymbolCode() { return symbolCode; } public String getLogLine() { return logLine; } public int getPrivacyLevel() { return privacyLevel; } public double getRangeMiles() { return rangeMiles; } public int getDirectivityDeg() { return directivityDeg; } public void setTimestampEpoch(long timestampEpoch) { this.timestampEpoch = timestampEpoch; } public void setSrcCallsign(@NonNull String srcCallsign) { this.srcCallsign = srcCallsign; } public void setDigipath(String digipath) { this.digipath = digipath; } public void setMaidenHead(String maidenHead) { this.maidenHead = maidenHead; } public void setDstCallsign(String dstCallsign) { this.dstCallsign = dstCallsign; } public void setLatitude(double latitude) { this.latitude = latitude; } public void setLongitude(double longitude) { this.longitude = longitude; } public void setAltitudeMeters(double altitudeMeters) { this.altitudeMeters = altitudeMeters; } public void setBearingDegrees(double bearingDegrees) { this.bearingDegrees = bearingDegrees; } public void setSpeedMetersPerSecond(double speedMetersPerSecond) { this.speedMetersPerSecond = speedMetersPerSecond; } public void setStatus(String status) { this.status = status; } public void setComment(String comment) { this.comment = comment; } public void setSymbolCode(String symbolCode) { this.symbolCode = symbolCode; } public void setPrivacyLevel(int privacyLevel) { this.privacyLevel = privacyLevel; } public void setLogLine(String logLine) { this.logLine = logLine; } public void setRangeMiles(double rangeMiles) { this.rangeMiles = rangeMiles; } public void setDirectivityDeg(int directivityDeg) { this.directivityDeg = directivityDeg; } public void updateFrom(StationItem stationItem) { setTimestampEpoch(stationItem.getTimestampEpoch()); setDstCallsign(stationItem.getDstCallsign()); // update position if known if (stationItem.getMaidenHead() != null) { setMaidenHead(stationItem.getMaidenHead()); setLatitude(stationItem.getLatitude()); setLongitude(stationItem.getLongitude()); setAltitudeMeters(stationItem.getAltitudeMeters()); setBearingDegrees(stationItem.getBearingDegrees()); setSpeedMetersPerSecond(stationItem.getSpeedMetersPerSecond()); setPrivacyLevel(stationItem.getPrivacyLevel()); setRangeMiles(stationItem.getRangeMiles()); setDirectivityDeg(stationItem.getDirectivityDeg()); } if (stationItem.getStatus() != null) setStatus(stationItem.getStatus()); if (stationItem.getComment() != null) setComment(stationItem.getComment()); if (stationItem.getSymbolCode() != null) setSymbolCode(stationItem.getSymbolCode()); if (stationItem.getLogLine() != null) setLogLine(stationItem.getLogLine()); if (stationItem.getDigipath() != null) setDigipath(stationItem.getDigipath()); } @Override public boolean equals(Object o) { StationItem stationItem = (StationItem)o; return srcCallsign.equals(stationItem.getSrcCallsign()) && timestampEpoch == stationItem.getTimestampEpoch() && Objects.equals(comment, stationItem.getComment()) && Objects.equals(dstCallsign, stationItem.getDstCallsign()) && latitude == stationItem.getLatitude() && 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, Bitmap.Config.ARGB_8888); 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); } }