Add aidl methods for setting context menu buttons and update menu with map for AMapPoints

This commit is contained in:
Chumva 2019-04-20 13:53:06 +03:00
parent ab5da34225
commit 30b444bcd6
40 changed files with 1430 additions and 93 deletions

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="direction">Direction</string>
<string name="precision">Precision</string>
<string name="altitude">Altitude</string>
<string name="bearing">Bearing</string>
<string name="search_contacts">Search contacts</string>
<string name="search_contacts_descr">Search across all of your groups and contacts.</string>
<string name="type_contact_or_group_name">Type contact or group name</string>

View file

@ -36,4 +36,6 @@ interface IOsmAndAidlCallback {
* @return directionInfo - update on distance to next turn and turns type.
*/
void updateNavigationInfo(in ADirectionInfo directionInfo);
void onContextMenuButtonClicked(in int buttonId, String pointId, String layerId);
}

View file

@ -83,6 +83,10 @@ import net.osmand.aidl.copyfile.CopyFileParams;
import net.osmand.aidl.navigation.ANavigationUpdateParams;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.UpdateContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.RemoveContextMenuButtonsParams;
// NOTE: Add new methods at the end of file!!!
@ -691,4 +695,8 @@ interface IOsmAndAidlInterface {
* @params callback (IOsmAndAidlCallback) - callback to notify user on navigation data change
*/
long registerForNavigationUpdates(in ANavigationUpdateParams params, IOsmAndAidlCallback callback);
long addContextMenuButtons(in ContextMenuButtonsParams params, IOsmAndAidlCallback callback);
boolean removeContextMenuButtons(in RemoveContextMenuButtonsParams params);
boolean updateContextMenuButtons(in UpdateContextMenuButtonsParams params);
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable AContextMenuButton;

View file

@ -0,0 +1,101 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class AContextMenuButton implements Parcelable {
private int buttonId;
private String leftTextCaption;
private String rightTextCaption;
private String leftIconName;
private String rightIconName;
private boolean needColorizeIcon;
private boolean enabled;
public AContextMenuButton(int buttonId, String leftTextCaption, String rightTextCaption, String leftIconName, String rightIconName, boolean needColorizeIcon, boolean enabled) {
this.buttonId = buttonId;
this.leftTextCaption = leftTextCaption;
this.rightTextCaption = rightTextCaption;
this.leftIconName = leftIconName;
this.rightIconName = rightIconName;
this.needColorizeIcon = needColorizeIcon;
this.enabled = enabled;
}
protected AContextMenuButton(Parcel in) {
readFromParcel(in);
}
public static final Creator<AContextMenuButton> CREATOR = new Creator<AContextMenuButton>() {
@Override
public AContextMenuButton createFromParcel(Parcel in) {
return new AContextMenuButton(in);
}
@Override
public AContextMenuButton[] newArray(int size) {
return new AContextMenuButton[size];
}
};
public int getButtonId() {
return buttonId;
}
public String getLeftTextCaption() {
return leftTextCaption;
}
public String getRightTextCaption() {
return rightTextCaption;
}
public String getLeftIconName() {
return leftIconName;
}
public String getRightIconName() {
return rightIconName;
}
public boolean isNeedColorizeIcon() {
return needColorizeIcon;
}
public boolean isEnabled() {
return enabled;
}
public static Creator<AContextMenuButton> getCREATOR() {
return CREATOR;
}
@Override
public void writeToParcel(Parcel dest, int f) {
dest.writeInt(buttonId);
dest.writeString(leftTextCaption);
dest.writeString(rightTextCaption);
dest.writeString(leftIconName);
dest.writeString(rightIconName);
dest.writeInt(needColorizeIcon ? 1 : 0);
dest.writeInt(enabled ? 1 : 0);
}
private void readFromParcel(Parcel in) {
buttonId = in.readInt();
leftTextCaption = in.readString();
rightTextCaption = in.readString();
leftIconName = in.readString();
rightIconName = in.readString();
needColorizeIcon = in.readInt() != 0;
enabled = in.readInt() != 0;
}
@Override
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable ContextMenuButtonsParams;

View file

@ -0,0 +1,105 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class ContextMenuButtonsParams implements Parcelable {
private AContextMenuButton leftButton;
private AContextMenuButton rightButton;
private String id;
private String appPackage;
private String layerId;
private long callbackId = -1L;
private List<String> pointsIds = new ArrayList<>();
public ContextMenuButtonsParams(AContextMenuButton leftButton, AContextMenuButton rightButton, String id, String appPackage, String layerId, boolean followOpenedPoint, long callbackId, List<String> pointsIds) {
this.leftButton = leftButton;
this.rightButton = rightButton;
this.id = id;
this.appPackage = appPackage;
this.layerId = layerId;
this.callbackId = callbackId;
this.pointsIds = pointsIds;
}
public ContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<ContextMenuButtonsParams> CREATOR = new Creator<ContextMenuButtonsParams>() {
@Override
public ContextMenuButtonsParams createFromParcel(Parcel in) {
return new ContextMenuButtonsParams(in);
}
@Override
public ContextMenuButtonsParams[] newArray(int size) {
return new ContextMenuButtonsParams[size];
}
};
public AContextMenuButton getLeftButton() {
return leftButton;
}
public AContextMenuButton getRightButton() {
return rightButton;
}
public String getId() {
return id;
}
public String getAppPackage() {
return appPackage;
}
public String getLayerId() {
return layerId;
}
public long getCallbackId() {
return callbackId;
}
public void setCallbackId(long callbackId) {
this.callbackId = callbackId;
}
public List<String> getPointsIds() {
return pointsIds;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(leftButton, flags);
dest.writeParcelable(rightButton, flags);
dest.writeString(id);
dest.writeString(appPackage);
dest.writeString(layerId);
dest.writeLong(callbackId);
dest.writeStringList(pointsIds);
}
private void readFromParcel(Parcel in) {
leftButton = in.readParcelable(AContextMenuButton.class.getClassLoader());
rightButton = in.readParcelable(AContextMenuButton.class.getClassLoader());
id = in.readString();
appPackage = in.readString();
layerId = in.readString();
callbackId = in.readLong();
in.readStringList(pointsIds);
}
@Override
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable RemoveContextMenuButtonsParams;

View file

@ -0,0 +1,53 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class RemoveContextMenuButtonsParams implements Parcelable {
private String paramsId;
private long callbackId = -1L;
public RemoveContextMenuButtonsParams(String paramsId, long callbackId) {
this.paramsId = paramsId;
this.callbackId = callbackId;
}
public RemoveContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<RemoveContextMenuButtonsParams> CREATOR = new
Creator<RemoveContextMenuButtonsParams>() {
public RemoveContextMenuButtonsParams createFromParcel(Parcel in) {
return new RemoveContextMenuButtonsParams(in);
}
public RemoveContextMenuButtonsParams[] newArray(int size) {
return new RemoveContextMenuButtonsParams[size];
}
};
public String getParamsId() {
return paramsId;
}
public long getCallbackId() {
return callbackId;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(paramsId);
dest.writeLong(callbackId);
}
private void readFromParcel(Parcel in) {
paramsId = in.readString();
callbackId = in.readLong();
}
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable UpdateContextMenuButtonsParams;

View file

@ -0,0 +1,43 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class UpdateContextMenuButtonsParams implements Parcelable {
private ContextMenuButtonsParams buttonsParams;
public UpdateContextMenuButtonsParams(ContextMenuButtonsParams widget) {
this.buttonsParams = widget;
}
public UpdateContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<UpdateContextMenuButtonsParams> CREATOR = new
Creator<UpdateContextMenuButtonsParams>() {
public UpdateContextMenuButtonsParams createFromParcel(Parcel in) {
return new UpdateContextMenuButtonsParams(in);
}
public UpdateContextMenuButtonsParams[] newArray(int size) {
return new UpdateContextMenuButtonsParams[size];
}
};
public ContextMenuButtonsParams getContextMenuButtonsParams() {
return buttonsParams;
}
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(buttonsParams, flags);
}
private void readFromParcel(Parcel in) {
buttonsParams = in.readParcelable(ContextMenuButtonsParams.class.getClassLoader());
}
public int describeContents() {
return 0;
}
}

View file

@ -20,17 +20,19 @@ public class AMapPoint implements Parcelable {
private String shortName;
private String fullName;
private String typeName;
private String layerId;
private int color;
private ALatLon location;
private List<String> details = new ArrayList<>();
private Map<String, String> params = new HashMap<>();
public AMapPoint(String id, String shortName, String fullName, String typeName, int color,
ALatLon location, List<String> details, Map<String, String> params) {
public AMapPoint(String id, String shortName, String fullName, String typeName, String layerId,
int color, ALatLon location, List<String> details, Map<String, String> params) {
this.id = id;
this.shortName = shortName;
this.fullName = fullName;
this.typeName = typeName;
this.layerId = layerId;
this.color = color;
this.location = location;
if (details != null) {
@ -72,6 +74,10 @@ public class AMapPoint implements Parcelable {
return typeName;
}
public String getLayerId() {
return layerId;
}
public int getColor() {
return color;
}
@ -93,6 +99,7 @@ public class AMapPoint implements Parcelable {
out.writeString(shortName);
out.writeString(fullName);
out.writeString(typeName);
out.writeString(layerId);
out.writeInt(color);
out.writeParcelable(location, flags);
out.writeStringList(details);
@ -104,6 +111,7 @@ public class AMapPoint implements Parcelable {
shortName = in.readString();
fullName = in.readString();
typeName = in.readString();
layerId = in.readString();
color = in.readInt();
location = in.readParcelable(ALatLon.class.getClassLoader());
in.readStringList(details);

View file

@ -6,10 +6,12 @@ import android.os.Parcelable;
public class UpdateMapPointParams implements Parcelable {
private String layerId;
private AMapPoint point;
private boolean updateOpenedMenuAndMap;
public UpdateMapPointParams(String layerId, AMapPoint point) {
public UpdateMapPointParams(String layerId, AMapPoint point, boolean updateOpenedMenuAndMap) {
this.layerId = layerId;
this.point = point;
this.updateOpenedMenuAndMap = updateOpenedMenuAndMap;
}
public UpdateMapPointParams(Parcel in) {
@ -35,14 +37,20 @@ public class UpdateMapPointParams implements Parcelable {
return point;
}
public boolean isUpdateOpenedMenuAndMap() {
return updateOpenedMenuAndMap;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(layerId);
out.writeParcelable(point, flags);
out.writeInt(updateOpenedMenuAndMap ? 1 : 0);
}
private void readFromParcel(Parcel in) {
layerId = in.readString();
point = in.readParcelable(AMapPoint.class.getClassLoader());
updateOpenedMenuAndMap = in.readInt() != 0;
}
public int describeContents() {

View file

@ -52,6 +52,7 @@ class TelegramApplication : Application(), OsmandHelperListener {
listOf("ic_action_location_sharing_app"),
listOf(-1)
)
showLocationHelper.addDirectionContextMenuButton()
if (settings.hasAnyChatToShowOnMap()) {
showLocationHelper.startShowingLocation()
}
@ -138,7 +139,10 @@ class TelegramApplication : Application(), OsmandHelperListener {
}
override fun onOsmandConnectionStateChanged(connected: Boolean) {
showLocationHelper.setupMapLayer()
if (connected) {
showLocationHelper.setupMapLayer()
showLocationHelper.addDirectionContextMenuButton()
}
}
private fun startTelegramService(intent: Int, serviceOffInterval: Long = 0) {

View file

@ -9,6 +9,9 @@ import android.os.IBinder
import android.os.RemoteException
import net.osmand.aidl.IOsmAndAidlCallback
import net.osmand.aidl.IOsmAndAidlInterface
import net.osmand.aidl.contextmenu.AContextMenuButton
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams
import net.osmand.aidl.contextmenu.RemoveContextMenuButtonsParams
import net.osmand.aidl.favorite.AFavorite
import net.osmand.aidl.favorite.AddFavoriteParams
import net.osmand.aidl.favorite.RemoveFavoriteParams
@ -43,6 +46,7 @@ import net.osmand.aidl.note.TakePhotoNoteParams
import net.osmand.aidl.search.SearchParams
import net.osmand.aidl.search.SearchResult
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.ShowLocationHelper.Companion.MAP_LAYER_ID
import java.io.File
import java.util.*
@ -61,7 +65,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
private var initialized: Boolean = false
private var bound: Boolean = false
private var osmandCallbackId: Long = 0
private var osmandUpdatesCallbackId: Long = -1
private var osmandContextMenuCallbackId: Long = -1
var listener: OsmandHelperListener? = null
@ -81,6 +86,12 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun onGpxBitmapCreated(bitmap: AGpxBitmap)
}
private var contextMenuButtonsListener: ContextMenuButtonsListener? = null
interface ContextMenuButtonsListener {
fun onContextMenuButtonClicked(buttonId:Int, pointId: String, layerId: String)
}
private val mIOsmAndAidlCallback = object : IOsmAndAidlCallback.Stub() {
@Throws(RemoteException::class)
@ -110,6 +121,12 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
override fun updateNavigationInfo(directionInfo: ADirectionInfo?) {
}
override fun onContextMenuButtonClicked(buttonId:Int, pointId: String, layerId: String) {
if (contextMenuButtonsListener != null) {
contextMenuButtonsListener!!.onContextMenuButtonClicked(buttonId, pointId, layerId)
}
}
}
fun setSearchCompleteListener(mSearchCompleteListener: SearchCompleteListener) {
@ -120,6 +137,10 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
this.gpxBitmapCreatedListener = gpxBitmapCreatedListener
}
fun setContextMenuButtonsListener(contextMenuButtonsListener: ContextMenuButtonsListener) {
this.contextMenuButtonsListener = contextMenuButtonsListener
}
private var mUpdatesListener: UpdatesListener? = null
interface UpdatesListener {
@ -130,7 +151,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
this.mUpdatesListener = mUpdatesListener
}
fun updatesCallbackRegistered() = osmandCallbackId > 0
fun updatesCallbackRegistered() = osmandUpdatesCallbackId > 0
/**
* Class for interacting with the main interface of the service.
*/
@ -411,6 +432,22 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
/**
* Add map marker at given location.
*
* @param marker - AMapMarker.
*/
fun addMapMarker(marker: AMapMarker): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
return mIOsmAndAidlInterface!!.addMapMarker(AddMapMarkerParams(marker))
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
@ -436,6 +473,23 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
/**
* Update map marker at given location with name.
*
* @param markerPrev - AMapMarker (current marker).
* @param markerNew - AMapMarker (new marker).
*/
fun updateMapMarker(markerPrev: AMapMarker, markerNew: AMapMarker): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
return mIOsmAndAidlInterface!!.updateMapMarker(UpdateMapMarkerParams(markerPrev, markerNew))
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
@ -615,7 +669,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
typeName: String, color: Int, location: ALatLon, details: List<String>?, params: Map<String, String>?): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params)
val point = AMapPoint(pointId, shortName, fullName, typeName, layerId, color, location, details, params)
return mIOsmAndAidlInterface!!.showMapPoint(ShowMapPointParams(layerId, point))
} catch (e: RemoteException) {
e.printStackTrace()
@ -640,7 +694,7 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
typeName: String, color: Int, location: ALatLon, details: List<String>?, params: Map<String, String>?): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params)
val point = AMapPoint(pointId, shortName, fullName, typeName, layerId, color, location, details, params)
return mIOsmAndAidlInterface!!.addMapPoint(AddMapPointParams(layerId, point))
} catch (e: RemoteException) {
e.printStackTrace()
@ -666,8 +720,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
typeName: String, color: Int, location: ALatLon, details: List<String>?, params: Map<String, String>?): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val point = AMapPoint(pointId, shortName, fullName, typeName, color, location, details, params)
return mIOsmAndAidlInterface!!.updateMapPoint(UpdateMapPointParams(layerId, point))
val point = AMapPoint(pointId, shortName, fullName, typeName, layerId, color, location, details, params)
return mIOsmAndAidlInterface!!.updateMapPoint(UpdateMapPointParams(layerId, point, true))
} catch (e: RemoteException) {
e.printStackTrace()
}
@ -1074,8 +1128,8 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun registerForUpdates(): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
osmandCallbackId = mIOsmAndAidlInterface!!.registerForUpdates(UPDATE_TIME_MS, mIOsmAndAidlCallback)
return osmandCallbackId > 0
osmandUpdatesCallbackId = mIOsmAndAidlInterface!!.registerForUpdates(UPDATE_TIME_MS, mIOsmAndAidlCallback)
return osmandUpdatesCallbackId > 0
} catch (e: RemoteException) {
e.printStackTrace()
}
@ -1086,9 +1140,9 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
fun unregisterFromUpdates(): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val unregistered = mIOsmAndAidlInterface!!.unregisterFromUpdates(osmandCallbackId)
val unregistered = mIOsmAndAidlInterface!!.unregisterFromUpdates(osmandUpdatesCallbackId)
if (unregistered) {
osmandCallbackId = 0
osmandUpdatesCallbackId = 0
}
return unregistered
} catch (e: RemoteException) {
@ -1109,4 +1163,39 @@ class OsmandAidlHelper(private val app: TelegramApplication) {
}
return false
}
fun addContextMenuButtons(
appPackage: String,paramsId:String,
leftTextCaption: String, rightTextCaption: String,
leftIconName: String, rightIconName: String,
needColorizeIcon: Boolean, enabled: Boolean, buttonId: Int
): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val leftButton = AContextMenuButton(buttonId, leftTextCaption, rightTextCaption, leftIconName, rightIconName, needColorizeIcon, enabled)
val params = ContextMenuButtonsParams(leftButton, null, paramsId, appPackage, MAP_LAYER_ID, true, osmandContextMenuCallbackId, mutableListOf())
osmandContextMenuCallbackId = mIOsmAndAidlInterface!!.addContextMenuButtons(params, mIOsmAndAidlCallback)
return osmandContextMenuCallbackId >= 0
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
fun removeContextMenuButtons(paramsId: String): Boolean {
if (mIOsmAndAidlInterface != null) {
try {
val params = RemoveContextMenuButtonsParams(paramsId, osmandContextMenuCallbackId)
val removed = mIOsmAndAidlInterface!!.removeContextMenuButtons(params)
if (removed) {
osmandContextMenuCallbackId = -1
}
return removed
} catch (e: RemoteException) {
e.printStackTrace()
}
}
return false
}
}

View file

@ -6,15 +6,19 @@ import android.os.AsyncTask
import android.text.TextUtils
import net.osmand.aidl.map.ALatLon
import net.osmand.aidl.maplayer.point.AMapPoint
import net.osmand.aidl.mapmarker.AMapMarker
import net.osmand.telegram.R
import net.osmand.telegram.TelegramApplication
import net.osmand.telegram.helpers.OsmandAidlHelper.ContextMenuButtonsListener
import net.osmand.telegram.helpers.TelegramUiHelper.ListItem
import net.osmand.telegram.utils.AndroidUtils
import net.osmand.telegram.utils.OsmandFormatter
import net.osmand.telegram.utils.OsmandLocationUtils
import net.osmand.telegram.utils.OsmandLocationUtils.MessageOsmAndBotLocation
import net.osmand.telegram.utils.OsmandLocationUtils.MessageUserLocation
import org.drinkless.td.libcore.telegram.TdApi
import java.io.File
import java.util.*
import java.util.concurrent.Executors
class ShowLocationHelper(private val app: TelegramApplication) {
@ -23,23 +27,65 @@ class ShowLocationHelper(private val app: TelegramApplication) {
const val MAP_LAYER_ID = "telegram_layer"
const val MIN_OSMAND_CALLBACK_VERSION_CODE = 320
const val MAP_CONTEXT_MENU_BUTTON_ID = 1
const val MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID = "DIRECTION"
const val DIRECTION_ICON_ID = "ic_action_start_navigation"
}
private val telegramHelper = app.telegramHelper
private val osmandAidlHelper = app.osmandAidlHelper
private val executor = Executors.newSingleThreadExecutor()
private val points = mutableMapOf<String, TdApi.Message>()
private val markers = mutableMapOf<String, AMapMarker>()
var showingLocation: Boolean = false
private set
private var forcedStop: Boolean = false
init {
app.osmandAidlHelper.setContextMenuButtonsListener(object : ContextMenuButtonsListener {
override fun onContextMenuButtonClicked(buttonId: Int, pointId: String, layerId: String) {
updateDirectionMarker(pointId)
}
})
}
fun setupMapLayer() {
osmandAidlHelper.execOsmandApi {
osmandAidlHelper.addMapLayer(MAP_LAYER_ID, "Telegram", 5.5f, null)
}
}
private fun updateDirectionMarker(pointId: String) {
val message = points[pointId]
if (message != null) {
val aLatLon = getALatLonFromMessage(message.content)
val name = getNameFromMessage(message)
if (aLatLon != null) {
val marker = AMapMarker(ALatLon(aLatLon.latitude, aLatLon.longitude), name)
val markerPrev = markers[pointId]
var markerUpdated: Boolean
if (markerPrev != null) {
markerUpdated = app.osmandAidlHelper.updateMapMarker(markerPrev, marker)
if (!markerUpdated) {
app.osmandAidlHelper.removeMapMarker(markerPrev.latLon.latitude, markerPrev.latLon.longitude, name)
markerUpdated = app.osmandAidlHelper.addMapMarker(marker)
}
} else {
markerUpdated = app.osmandAidlHelper.addMapMarker(marker)
}
if (markerUpdated) {
markers[pointId] = marker
}
}
}
}
fun showLocationOnMap(item: ListItem, stale: Boolean = false) {
if (item.latLon == null) {
return
@ -53,8 +99,8 @@ class ShowLocationHelper(private val app: TelegramApplication) {
item.chatTitle,
Color.WHITE,
ALatLon(item.latLon!!.latitude, item.latLon!!.longitude),
null,
generatePointParams(if (stale) item.grayscalePhotoPath else item.photoPath, stale)
generatePointDetails(item.bearing?.toFloat(), item.altitude?.toFloat(), item.precision?.toFloat()),
generatePointParams(if (stale) item.grayscalePhotoPath else item.photoPath, stale, item.speed?.toFloat())
)
}
}
@ -77,61 +123,89 @@ class ShowLocationHelper(private val app: TelegramApplication) {
fun addOrUpdateLocationOnMap(message: TdApi.Message, update: Boolean = false) {
osmandAidlHelper.execOsmandApi {
val chatId = message.chatId
val chatTitle = telegramHelper.getChat(message.chatId)?.title
val chat = telegramHelper.getChat(message.chatId)
val chatTitle = chat?.title
val isGroup = chat != null && telegramHelper.isGroup(chat)
val content = message.content
val date = OsmandLocationUtils.getLastUpdatedTime(message)
val stale = System.currentTimeMillis() / 1000 - date > app.settings.staleLocTime
if (chatTitle != null && (content is TdApi.MessageLocation || (content is MessageUserLocation && content.isValid()))) {
var userName = ""
var photoPath: String? = null
val user = telegramHelper.getUser(OsmandLocationUtils.getSenderMessageId(message))
if (user != null) {
userName = "${user.firstName} ${user.lastName}".trim()
if (userName.isEmpty()) {
userName = user.username
val aLatLon = getALatLonFromMessage(content)
val details = if (content is OsmandLocationUtils.MessageLocation) generatePointDetails(content.bearing.toFloat(), content.altitude.toFloat(), content.hdop.toFloat()) else null
val name = getNameFromMessage(message)
val senderId = OsmandLocationUtils.getSenderMessageId(message)
val pointId = if (content is MessageOsmAndBotLocation) "${chatId}_${content.deviceName}" else "${chatId}_$senderId"
if (aLatLon != null && chatTitle != null) {
if ((content is TdApi.MessageLocation || (content is MessageUserLocation && content.isValid()))) {
var photoPath: String? = null
val user = telegramHelper.getUser(senderId)
if (user != null) {
photoPath = if (stale) {
telegramHelper.getUserGreyPhotoPath(user)
} else {
telegramHelper.getUserPhotoPath(user)
}
}
if (userName.isEmpty()) {
userName = user.phoneNumber
}
photoPath = if (stale) {
telegramHelper.getUserGreyPhotoPath(user)
} else {
telegramHelper.getUserPhotoPath(user)
}
}
if (userName.isEmpty()) {
userName = OsmandLocationUtils.getSenderMessageId(message).toString()
}
setupMapLayer()
val params = generatePointParams(photoPath, stale)
val aLatLon = when (content) {
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
is MessageUserLocation -> ALatLon(content.lat, content.lon)
else -> null
}
if (aLatLon != null) {
setupMapLayer()
val params = generatePointParams(photoPath, stale, if (content is MessageUserLocation) content.speed.toFloat() else null)
val typeName = if (isGroup) chatTitle else OsmandFormatter.getListItemLiveTimeDescr(app, date, app.getString(R.string.last_response) + ": ")
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, "${chatId}_${OsmandLocationUtils.getSenderMessageId(message)}", userName, userName,
chatTitle, Color.WHITE, aLatLon, null, params)
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, pointId, name, name, typeName, Color.WHITE, aLatLon, details, params)
} else {
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, "${chatId}_${OsmandLocationUtils.getSenderMessageId(message)}", userName, userName,
chatTitle, Color.WHITE, aLatLon, null, params)
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, pointId, name, name, typeName, Color.WHITE, aLatLon, details, params)
}
points[pointId] = message
} else if (content is MessageOsmAndBotLocation && content.isValid()) {
setupMapLayer()
val params = generatePointParams(null, stale, content.speed.toFloat())
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, pointId, name, name, chatTitle, Color.WHITE, aLatLon, details, params)
} else {
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, pointId, name, name, chatTitle, Color.WHITE, aLatLon, details, params)
}
points[pointId] = message
}
} else if (chatTitle != null && content is MessageOsmAndBotLocation && content.isValid()) {
val name = content.deviceName
setupMapLayer()
if (update) {
osmandAidlHelper.updateMapPoint(MAP_LAYER_ID, "${chatId}_$name", name, name,
chatTitle, Color.WHITE, ALatLon(content.lat, content.lon), null, generatePointParams(null, stale))
} else {
osmandAidlHelper.addMapPoint(MAP_LAYER_ID, "${chatId}_$name", name, name,
chatTitle, Color.WHITE, ALatLon(content.lat, content.lon), null, generatePointParams(null, stale))
if (markers.containsKey(pointId)) {
updateDirectionMarker(pointId)
}
}
}
}
private fun getALatLonFromMessage(content: TdApi.MessageContent): ALatLon? {
return when (content) {
is TdApi.MessageLocation -> ALatLon(content.location.latitude, content.location.longitude)
is OsmandLocationUtils.MessageLocation -> ALatLon(content.lat, content.lon)
else -> null
}
}
private fun getNameFromMessage(message: TdApi.Message): String {
var name = ""
val content = message.content
val senderId = OsmandLocationUtils.getSenderMessageId(message)
if ((content is TdApi.MessageLocation || (content is MessageUserLocation && content.isValid()))) {
val user = telegramHelper.getUser(senderId)
if (user != null) {
name = "${user.firstName} ${user.lastName}".trim()
if (name.isEmpty()) {
name = user.username
}
if (name.isEmpty()) {
name = user.phoneNumber
}
}
if (name.isEmpty()) {
name = senderId.toString()
}
} else if (content is MessageOsmAndBotLocation && content.isValid()) {
name = content.deviceName
}
return name
}
fun showChatMessages(chatId: Long) {
osmandAidlHelper.execOsmandApi {
val messages = telegramHelper.getChatMessages(chatId)
@ -156,6 +230,14 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
}
fun addDirectionContextMenuButton() {
osmandAidlHelper.addContextMenuButtons(app.packageName, MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID, app.getString(R.string.direction), "", DIRECTION_ICON_ID, "", true, true, MAP_CONTEXT_MENU_BUTTON_ID)
}
fun removeDirectionContextMenuButton() {
osmandAidlHelper.removeContextMenuButtons(MAP_CONTEXT_MENU_BUTTONS_PARAMS_ID)
}
fun startShowingLocation() {
if (!showingLocation && !forcedStop) {
showingLocation = if (isUseOsmandCallback() && !app.settings.monitoringEnabled) {
@ -164,6 +246,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
app.startUserLocationService()
true
}
addDirectionContextMenuButton()
}
}
@ -176,6 +259,7 @@ class ShowLocationHelper(private val app: TelegramApplication) {
} else if (!app.settings.monitoringEnabled) {
app.stopUserLocationService()
}
removeDirectionContextMenuButton()
}
}
@ -253,17 +337,37 @@ class ShowLocationHelper(private val app: TelegramApplication) {
}
}
private fun generatePointParams(photoPath: String?, stale: Boolean): Map<String, String> {
private fun generatePointDetails(bearing: Float?, altitude: Float?, precision: Float?): List<String> {
val details = mutableListOf<String>()
if (bearing != null && bearing != 0.0f) {
details.add(String.format(Locale.US, "${OsmandLocationUtils.BEARING_PREFIX}%.1f \n", bearing))
}
if (altitude != null && altitude != 0.0f) {
details.add(String.format(Locale.US, "${OsmandLocationUtils.ALTITUDE_PREFIX}%.1f m\n", altitude))
}
if (precision != null && precision != 0.0f) {
details.add(String.format(Locale.US, "${OsmandLocationUtils.HDOP_PREFIX}%d m\n", precision.toInt()))
}
return details
}
private fun generatePointParams(photoPath: String?, stale: Boolean, speed: Float?): Map<String, String> {
val photoUri = generatePhotoUri(photoPath, stale)
app.grantUriPermission(
app.settings.appToConnectPackage,
photoUri,
Intent.FLAG_GRANT_READ_URI_PERMISSION
)
return mapOf(
val params = mutableMapOf(
AMapPoint.POINT_IMAGE_URI_PARAM to photoUri.toString(),
AMapPoint.POINT_STALE_LOC_PARAM to stale.toString()
)
if (speed != 0.0f) {
params[AMapPoint.POINT_SPEED_PARAM] = speed.toString()
}
return params
}
private fun generatePhotoUri(photoPath: String?, stale: Boolean) =

View file

@ -71,6 +71,10 @@ object TelegramUiHelper {
res.latLon = LatLon(content.location.latitude, content.location.longitude)
} else if (content is MessageUserLocation) {
res.latLon = LatLon(content.lat, content.lon)
res.speed = content.speed
res.bearing = content.bearing
res.altitude = content.altitude
res.precision = content.hdop
}
}
if (user != null) {
@ -140,6 +144,10 @@ object TelegramUiHelper {
chatTitle = chat.title
name = content.deviceName
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
placeholderId = R.drawable.img_user_picture
lastUpdated = content.lastUpdated
}
@ -158,11 +166,18 @@ object TelegramUiHelper {
return LocationItem().apply {
chatId = chat.id
chatTitle = chat.title
name = TelegramUiHelper.getUserName(user)
latLon = when (content) {
is TdApi.MessageLocation -> LatLon(content.location.latitude, content.location.longitude)
is MessageUserLocation -> LatLon(content.lat, content.lon)
else -> null
name = getUserName(user)
when (content) {
is TdApi.MessageLocation -> {
latLon = LatLon(content.location.latitude, content.location.longitude)
}
is MessageUserLocation -> {
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
}
}
photoPath = helper.getUserPhotoPath(user)
grayscalePhotoPath = helper.getUserGreyPhotoPath(user)
@ -184,6 +199,10 @@ object TelegramUiHelper {
chatTitle = chat.title
name = content.deviceName
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
photoPath = chat.photo?.small?.local?.path
placeholderId = R.drawable.img_user_picture
privateChat = helper.isPrivateChat(chat) || helper.isSecretChat(chat)
@ -205,11 +224,18 @@ object TelegramUiHelper {
return ChatItem().apply {
chatId = chat.id
chatTitle = chat.title
name = TelegramUiHelper.getUserName(user)
latLon = when (content) {
is TdApi.MessageLocation -> LatLon(content.location.latitude, content.location.longitude)
is MessageUserLocation -> LatLon(content.lat, content.lon)
else -> null
name = getUserName(user)
when (content) {
is TdApi.MessageLocation -> {
latLon = LatLon(content.location.latitude, content.location.longitude)
}
is MessageUserLocation -> {
latLon = LatLon(content.lat, content.lon)
speed = content.speed
bearing = content.bearing
altitude = content.altitude
precision = content.hdop
}
}
if (helper.isGroup(chat)) {
photoPath = helper.getUserPhotoPath(user)
@ -244,7 +270,7 @@ object TelegramUiHelper {
photoPath = user?.profilePhoto?.small?.local?.path
}
if (user != null) {
name = TelegramUiHelper.getUserName(user)
name = getUserName(user)
userId = user.id
}
userLocations = userLocation
@ -264,6 +290,14 @@ object TelegramUiHelper {
internal set
var latLon: LatLon? = null
internal set
var bearing: Double? = null
internal set
var speed: Double? = null
internal set
var altitude: Double? = null
internal set
var precision: Double? = null
internal set
var photoPath: String? = null
internal set
var grayscalePhotoPath: String? = null

View file

@ -29,6 +29,7 @@ object OsmandLocationUtils {
const val SHARING_LINK = "https://play.google.com/store/apps/details?id=net.osmand.telegram"
const val ALTITUDE_PREFIX = "Altitude: "
const val BEARING_PREFIX = "Bearing: "
const val SPEED_PREFIX = "Speed: "
const val HDOP_PREFIX = "Horizontal precision: "

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:osmand="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:baselineAligned="false"
android:orientation="horizontal"
android:paddingBottom="@dimen/context_menu_padding_margin_small">
<LinearLayout
android:id="@+id/additional_button_left_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/context_menu_padding_margin_small"
android:layout_marginRight="@dimen/context_menu_padding_margin_small"
android:layout_weight="1"
android:background="?attr/ctx_menu_controller_bg"
android:minHeight="@dimen/context_menu_controller_height">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/additional_button_left"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:gravity="center_vertical"
android:paddingLeft="@dimen/context_menu_button_padding_x"
android:paddingRight="@dimen/context_menu_button_padding_x"
android:textColor="?attr/ctx_menu_controller_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/poi_additional_type" />
</LinearLayout>
<LinearLayout
android:id="@+id/additional_button_right_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/context_menu_padding_margin_small"
android:layout_marginRight="@dimen/context_menu_padding_margin_small"
android:layout_weight="1"
android:background="?attr/ctx_menu_controller_bg"
android:minHeight="@dimen/context_menu_controller_height">
<net.osmand.plus.widgets.TextViewEx
android:id="@+id/additional_button_right"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@null"
android:gravity="center_vertical"
android:paddingLeft="@dimen/context_menu_button_padding_x"
android:paddingRight="@dimen/context_menu_button_padding_x"
android:textColor="?attr/ctx_menu_controller_text_color"
android:textSize="@dimen/default_desc_text_size"
osmand:typeface="@string/font_roboto_medium"
tools:text="@string/shared_string_others" />
</LinearLayout>
</LinearLayout>

View file

@ -414,6 +414,14 @@
</LinearLayout>
<LinearLayout
android:id="@+id/additional_buttons_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:visibility="gone"
tools:visibility="visible"/>
<LinearLayout
android:id="@+id/title_progress_container"
android:layout_width="fill_parent"

View file

@ -36,4 +36,6 @@ interface IOsmAndAidlCallback {
* @return directionInfo - update on distance to next turn and turns type.
*/
void updateNavigationInfo(in ADirectionInfo directionInfo);
void onContextMenuButtonClicked(in int buttonId, String pointId, String layerId);
}

View file

@ -83,6 +83,10 @@ import net.osmand.aidl.copyfile.CopyFileParams;
import net.osmand.aidl.navigation.ANavigationUpdateParams;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.UpdateContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.RemoveContextMenuButtonsParams;
// NOTE: Add new methods at the end of file!!!
@ -691,4 +695,8 @@ interface IOsmAndAidlInterface {
* @params callback (IOsmAndAidlCallback) - callback to notify user on navigation data change
*/
long registerForNavigationUpdates(in ANavigationUpdateParams params, IOsmAndAidlCallback callback);
long addContextMenuButtons(in ContextMenuButtonsParams params, IOsmAndAidlCallback callback);
boolean removeContextMenuButtons(in RemoveContextMenuButtonsParams params);
boolean updateContextMenuButtons(in UpdateContextMenuButtonsParams params);
}

View file

@ -26,8 +26,12 @@ import android.view.View;
import android.widget.ArrayAdapter;
import net.osmand.CallbackWithObject;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.IndexConstants;
import net.osmand.PlatformUtil;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.copyfile.CopyFileParams;
import net.osmand.aidl.favorite.AFavorite;
import net.osmand.aidl.favorite.group.AFavoriteGroup;
@ -57,9 +61,6 @@ import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.FavouritesDbHelper;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.GPXUtilities;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.MapMarkersHelper;
@ -73,6 +74,8 @@ import net.osmand.plus.audionotes.AudioVideoNotesPlugin;
import net.osmand.plus.dialogs.ConfigureMapMenu;
import net.osmand.plus.helpers.ColorDialogs;
import net.osmand.plus.helpers.ExternalApiHelper;
import net.osmand.plus.mapcontextmenu.MapContextMenu;
import net.osmand.plus.mapcontextmenu.other.IContextMenuButtonListener;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.myplaces.TrackBitmapDrawer;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
@ -121,6 +124,7 @@ import static net.osmand.aidl.OsmandAidlConstants.COPY_FILE_PART_SIZE_LIMIT_ERRO
import static net.osmand.aidl.OsmandAidlConstants.COPY_FILE_UNSUPPORTED_FILE_TYPE_ERROR;
import static net.osmand.aidl.OsmandAidlConstants.COPY_FILE_WRITE_LOCK_ERROR;
import static net.osmand.aidl.OsmandAidlConstants.OK_RESPONSE;
import static net.osmand.aidl.OsmandAidlService.KEY_ON_CONTEXT_MENU_BUTTONS_CLICK;
import static net.osmand.aidl.OsmandAidlService.KEY_ON_NAV_DATA_UPDATE;
import static net.osmand.plus.OsmAndCustomizationConstants.DRAWER_ITEM_ID_SCHEME;
@ -155,6 +159,9 @@ public class OsmandAidlApi {
private static final String AIDL_ADD_MAP_WIDGET = "aidl_add_map_widget";
private static final String AIDL_REMOVE_MAP_WIDGET = "aidl_remove_map_widget";
private static final String AIDL_ADD_CONTEXT_MENU_BUTTONS = "aidl_add_context_menu_buttons";
private static final String AIDL_REMOVE_CONTEXT_MENU_BUTTONS = "aidl_remove_context_menu_buttons";
private static final String AIDL_ADD_MAP_LAYER = "aidl_add_map_layer";
private static final String AIDL_REMOVE_MAP_LAYER = "aidl_remove_map_layer";
@ -196,6 +203,9 @@ public class OsmandAidlApi {
private Map<String, OsmandMapLayer> mapLayers = new ConcurrentHashMap<>();
private Map<String, BroadcastReceiver> receivers = new TreeMap<>();
private Map<String, ConnectedApp> connectedApps = new ConcurrentHashMap<>();
private Map<String, ContextMenuButtonsParams> contextMenuButtonsParams = new ConcurrentHashMap<>();
private AMapPointUpdateListener aMapPointUpdateListener;
private boolean mapActivityActive = false;
@ -209,6 +219,7 @@ public class OsmandAidlApi {
registerRefreshMapReceiver(mapActivity);
registerSetMapLocationReceiver(mapActivity);
registerAddMapWidgetReceiver(mapActivity);
registerAddContextMenuButtonsReceiver(mapActivity);
registerRemoveMapWidgetReceiver(mapActivity);
registerAddMapLayerReceiver(mapActivity);
registerRemoveMapLayerReceiver(mapActivity);
@ -228,6 +239,7 @@ public class OsmandAidlApi {
registerHideSqliteDbFileReceiver(mapActivity);
initOsmandTelegram();
app.getAppCustomization().addListener(mapActivity);
aMapPointUpdateListener = mapActivity;
}
public void onDestroyMapActivity(MapActivity mapActivity) {
@ -344,6 +356,27 @@ public class OsmandAidlApi {
registerReceiver(addMapWidgetReceiver, mapActivity, AIDL_ADD_MAP_WIDGET);
}
private void registerAddContextMenuButtonsReceiver(MapActivity mapActivity) {
final WeakReference<MapActivity> mapActivityRef = new WeakReference<>(mapActivity);
BroadcastReceiver addContextMenuButtonsParamsReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
MapActivity mapActivity = mapActivityRef.get();
String ContextMenuButtonsParamsId = intent.getStringExtra(AIDL_OBJECT_ID);
if (mapActivity != null && ContextMenuButtonsParamsId != null) {
ContextMenuButtonsParams buttonsParams = contextMenuButtonsParams.get(ContextMenuButtonsParamsId);
if (buttonsParams != null) {
MapContextMenu mapContextMenu = mapActivity.getContextMenu();
if (mapContextMenu.isVisible()) {
mapContextMenu.updateData();
}
}
}
}
};
registerReceiver(addContextMenuButtonsParamsReceiver, mapActivity, AIDL_ADD_CONTEXT_MENU_BUTTONS);
}
private void registerReceiver(BroadcastReceiver rec, MapActivity ma,
String filter) {
receivers.put(filter, rec);
@ -1173,6 +1206,21 @@ public class OsmandAidlApi {
return false;
}
boolean updateMapPoint(String layerId, AMapPoint point, boolean updateOpenedMenuAndMap) {
if (point != null) {
AMapLayer layer = layers.get(layerId);
if (layer != null) {
layer.putPoint(point);
refreshMap();
if (updateOpenedMenuAndMap && aMapPointUpdateListener != null) {
aMapPointUpdateListener.onAMapPointUpdated(point, layerId);
}
return true;
}
}
return false;
}
boolean removeMapPoint(String layerId, String pointId) {
if (pointId != null) {
AMapLayer layer = layers.get(layerId);
@ -1968,6 +2016,83 @@ public class OsmandAidlApi {
}
public Map<String, ContextMenuButtonsParams> getContextMenuButtonsParams() {
return contextMenuButtonsParams;
}
boolean addContextMenuButtons(ContextMenuButtonsParams buttonsParams, long callbackId) {
if (buttonsParams != null) {
if (contextMenuButtonsParams.containsKey(buttonsParams.getId())) {
updateContextMenuButtons(buttonsParams, callbackId);
} else {
addContextMenuButtonListener(buttonsParams, callbackId);
contextMenuButtonsParams.put(buttonsParams.getId(), buttonsParams);
Intent intent = new Intent();
intent.setAction(AIDL_ADD_CONTEXT_MENU_BUTTONS);
intent.putExtra(AIDL_OBJECT_ID, buttonsParams.getId());
app.sendBroadcast(intent);
}
return true;
} else {
return false;
}
}
boolean removeContextMenuButtons(String buttonsParamsId, long callbackId) {
if (!Algorithms.isEmpty(buttonsParamsId) && contextMenuButtonsParams.containsKey(buttonsParamsId)) {
contextMenuButtonsParams.remove(buttonsParamsId);
contextMenuButtonsCallbacks.remove(callbackId);
Intent intent = new Intent();
intent.setAction(AIDL_REMOVE_CONTEXT_MENU_BUTTONS);
intent.putExtra(AIDL_OBJECT_ID, buttonsParamsId);
app.sendBroadcast(intent);
return true;
} else {
return false;
}
}
boolean updateContextMenuButtons(ContextMenuButtonsParams buttonsParams, long callbackId) {
if (buttonsParams != null && contextMenuButtonsParams.containsKey(buttonsParams.getId())) {
contextMenuButtonsParams.put(buttonsParams.getId(), buttonsParams);
addContextMenuButtonListener(buttonsParams, callbackId);
return true;
} else {
return false;
}
}
private void addContextMenuButtonListener(ContextMenuButtonsParams buttonsParams, long callbackId) {
IContextMenuButtonListener listener = new IContextMenuButtonListener() {
@Override
public void onContextMenuButtonClicked(int buttonId, String pointId, String layerId) {
if (aidlCallbackListener != null) {
for (OsmandAidlService.AidlCallbackParams cb : aidlCallbackListener.getAidlCallbacks().values()) {
if (!aidlCallbackListener.getAidlCallbacks().isEmpty() && (cb.getKey() & KEY_ON_CONTEXT_MENU_BUTTONS_CLICK) > 0) {
try {
cb.getCallback().onContextMenuButtonClicked(buttonId, pointId, layerId);
} catch (Exception e) {
LOG.debug(e.getMessage(), e);
}
}
}
}
}
};
buttonsParams.setCallbackId(callbackId);
contextMenuButtonsCallbacks.put(callbackId, listener);
}
private Map<Long, IContextMenuButtonListener> contextMenuButtonsCallbacks = new ConcurrentHashMap<>();
public void contextMenuCallbackButtonClicked(long callbackId, int buttonId, String pointId, String layerId) {
IContextMenuButtonListener contextMenuButtonListener = contextMenuButtonsCallbacks.get(callbackId);
if (contextMenuButtonListener != null) {
contextMenuButtonListener.onContextMenuButtonClicked(buttonId, pointId, layerId);
}
}
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) {
@ -2236,4 +2361,7 @@ public class OsmandAidlApi {
void onAppInitialized();
}
public interface AMapPointUpdateListener {
void onAMapPointUpdated(AMapPoint point, String layerId);
}
}

View file

@ -10,13 +10,15 @@ import android.os.IBinder;
import android.os.RemoteException;
import android.support.annotation.Nullable;
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;
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;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.RemoveContextMenuButtonsParams;
import net.osmand.aidl.contextmenu.UpdateContextMenuButtonsParams;
import net.osmand.aidl.customization.OsmandSettingsParams;
import net.osmand.aidl.customization.SetWidgetsParams;
import net.osmand.aidl.favorite.AddFavoriteParams;
@ -93,6 +95,7 @@ public class OsmandAidlService extends Service implements AidlCallbackListener {
public static final int KEY_ON_UPDATE = 1;
public static final int KEY_ON_NAV_DATA_UPDATE = 2;
public static final int KEY_ON_CONTEXT_MENU_BUTTONS_CLICK = 4;
private Map<Long, AidlCallbackParams> callbacks = new ConcurrentHashMap<>();
private Handler mHandler = null;
@ -360,7 +363,7 @@ public class OsmandAidlService extends Service implements AidlCallbackListener {
public boolean updateMapPoint(UpdateMapPointParams params) {
try {
OsmandAidlApi api = getApi("updateMapPoint");
return params != null && api != null && api.putMapPoint(params.getLayerId(), params.getPoint());
return params != null && api != null && api.updateMapPoint(params.getLayerId(), params.getPoint(), params.isUpdateOpenedMenuAndMap());
} catch (Exception e) {
handleException(e);
return false;
@ -1058,8 +1061,58 @@ public class OsmandAidlService extends Service implements AidlCallbackListener {
return UNKNOWN_API_ERROR;
}
}
};
@Override
public long addContextMenuButtons(ContextMenuButtonsParams params, final IOsmAndAidlCallback callback) {
try {
OsmandAidlApi api = getApi("addContextMenuButtons");
if (api != null && params != null) {
long callbackId = params.getCallbackId();
if (callbackId == -1 || !callbacks.containsKey(callbackId)) {
callbackId = addAidlCallback(callback, KEY_ON_CONTEXT_MENU_BUTTONS_CLICK);
params.setCallbackId(callbackId);
}
boolean buttonsAdded = api.addContextMenuButtons(params, callbackId);
return buttonsAdded ? callbackId : -1;
} else {
return -1;
}
} catch (Exception e) {
handleException(e);
return UNKNOWN_API_ERROR;
}
}
@Override
public boolean removeContextMenuButtons(RemoveContextMenuButtonsParams params) {
try {
OsmandAidlApi api = getApi("removeContextMenuButtons");
if (params != null && api != null) {
long callbackId = params.getCallbackId();
removeAidlCallback(callbackId);
return api.removeContextMenuButtons(params.getParamsId(), callbackId);
}
return false;
} catch (Exception e) {
return false;
}
}
@Override
public boolean updateContextMenuButtons(UpdateContextMenuButtonsParams params) {
try {
OsmandAidlApi api = getApi("updateContextMenuButtons");
if (params != null && api != null) {
ContextMenuButtonsParams buttonsParams = params.getContextMenuButtonsParams();
return api.updateContextMenuButtons(buttonsParams, buttonsParams.getCallbackId());
}
return false;
} catch (Exception e) {
handleException(e);
return false;
}
}
};
public static class AidlCallbackParams {
private IOsmAndAidlCallback callback;

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable AContextMenuButton;

View file

@ -0,0 +1,101 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class AContextMenuButton implements Parcelable {
private int buttonId;
private String leftTextCaption;
private String rightTextCaption;
private String leftIconName;
private String rightIconName;
private boolean needColorizeIcon;
private boolean enabled;
public AContextMenuButton(int buttonId, String leftTextCaption, String rightTextCaption, String leftIconName, String rightIconName, boolean needColorizeIcon, boolean enabled) {
this.buttonId = buttonId;
this.leftTextCaption = leftTextCaption;
this.rightTextCaption = rightTextCaption;
this.leftIconName = leftIconName;
this.rightIconName = rightIconName;
this.needColorizeIcon = needColorizeIcon;
this.enabled = enabled;
}
protected AContextMenuButton(Parcel in) {
readFromParcel(in);
}
public static final Creator<AContextMenuButton> CREATOR = new Creator<AContextMenuButton>() {
@Override
public AContextMenuButton createFromParcel(Parcel in) {
return new AContextMenuButton(in);
}
@Override
public AContextMenuButton[] newArray(int size) {
return new AContextMenuButton[size];
}
};
public int getButtonId() {
return buttonId;
}
public String getLeftTextCaption() {
return leftTextCaption;
}
public String getRightTextCaption() {
return rightTextCaption;
}
public String getLeftIconName() {
return leftIconName;
}
public String getRightIconName() {
return rightIconName;
}
public boolean isNeedColorizeIcon() {
return needColorizeIcon;
}
public boolean isEnabled() {
return enabled;
}
public static Creator<AContextMenuButton> getCREATOR() {
return CREATOR;
}
@Override
public void writeToParcel(Parcel dest, int f) {
dest.writeInt(buttonId);
dest.writeString(leftTextCaption);
dest.writeString(rightTextCaption);
dest.writeString(leftIconName);
dest.writeString(rightIconName);
dest.writeInt(needColorizeIcon ? 1 : 0);
dest.writeInt(enabled ? 1 : 0);
}
private void readFromParcel(Parcel in) {
buttonId = in.readInt();
leftTextCaption = in.readString();
rightTextCaption = in.readString();
leftIconName = in.readString();
rightIconName = in.readString();
needColorizeIcon = in.readInt() != 0;
enabled = in.readInt() != 0;
}
@Override
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable ContextMenuButtonsParams;

View file

@ -0,0 +1,105 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.ArrayList;
import java.util.List;
public class ContextMenuButtonsParams implements Parcelable {
private AContextMenuButton leftButton;
private AContextMenuButton rightButton;
private String id;
private String appPackage;
private String layerId;
private long callbackId = -1L;
private List<String> pointsIds = new ArrayList<>();
public ContextMenuButtonsParams(AContextMenuButton leftButton, AContextMenuButton rightButton, String id, String appPackage, String layerId, boolean followOpenedPoint, long callbackId, List<String> pointsIds) {
this.leftButton = leftButton;
this.rightButton = rightButton;
this.id = id;
this.appPackage = appPackage;
this.layerId = layerId;
this.callbackId = callbackId;
this.pointsIds = pointsIds;
}
public ContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<ContextMenuButtonsParams> CREATOR = new Creator<ContextMenuButtonsParams>() {
@Override
public ContextMenuButtonsParams createFromParcel(Parcel in) {
return new ContextMenuButtonsParams(in);
}
@Override
public ContextMenuButtonsParams[] newArray(int size) {
return new ContextMenuButtonsParams[size];
}
};
public AContextMenuButton getLeftButton() {
return leftButton;
}
public AContextMenuButton getRightButton() {
return rightButton;
}
public String getId() {
return id;
}
public String getAppPackage() {
return appPackage;
}
public String getLayerId() {
return layerId;
}
public long getCallbackId() {
return callbackId;
}
public void setCallbackId(long callbackId) {
this.callbackId = callbackId;
}
public List<String> getPointsIds() {
return pointsIds;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeParcelable(leftButton, flags);
dest.writeParcelable(rightButton, flags);
dest.writeString(id);
dest.writeString(appPackage);
dest.writeString(layerId);
dest.writeLong(callbackId);
dest.writeStringList(pointsIds);
}
private void readFromParcel(Parcel in) {
leftButton = in.readParcelable(AContextMenuButton.class.getClassLoader());
rightButton = in.readParcelable(AContextMenuButton.class.getClassLoader());
id = in.readString();
appPackage = in.readString();
layerId = in.readString();
callbackId = in.readLong();
in.readStringList(pointsIds);
}
@Override
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable RemoveContextMenuButtonsParams;

View file

@ -0,0 +1,53 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
public class RemoveContextMenuButtonsParams implements Parcelable {
private String paramsId;
private long callbackId = -1L;
public RemoveContextMenuButtonsParams(String paramsId, long callbackId) {
this.paramsId = paramsId;
this.callbackId = callbackId;
}
public RemoveContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<RemoveContextMenuButtonsParams> CREATOR = new
Creator<RemoveContextMenuButtonsParams>() {
public RemoveContextMenuButtonsParams createFromParcel(Parcel in) {
return new RemoveContextMenuButtonsParams(in);
}
public RemoveContextMenuButtonsParams[] newArray(int size) {
return new RemoveContextMenuButtonsParams[size];
}
};
public String getParamsId() {
return paramsId;
}
public long getCallbackId() {
return callbackId;
}
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(paramsId);
dest.writeLong(callbackId);
}
private void readFromParcel(Parcel in) {
paramsId = in.readString();
callbackId = in.readLong();
}
public int describeContents() {
return 0;
}
}

View file

@ -0,0 +1,3 @@
package net.osmand.aidl.contextmenu;
parcelable UpdateContextMenuButtonsParams;

View file

@ -0,0 +1,45 @@
package net.osmand.aidl.contextmenu;
import android.os.Parcel;
import android.os.Parcelable;
import net.osmand.aidl.mapwidget.AMapWidget;
public class UpdateContextMenuButtonsParams implements Parcelable {
private ContextMenuButtonsParams buttonsParams;
public UpdateContextMenuButtonsParams(ContextMenuButtonsParams widget) {
this.buttonsParams = widget;
}
public UpdateContextMenuButtonsParams(Parcel in) {
readFromParcel(in);
}
public static final Creator<UpdateContextMenuButtonsParams> CREATOR = new
Creator<UpdateContextMenuButtonsParams>() {
public UpdateContextMenuButtonsParams createFromParcel(Parcel in) {
return new UpdateContextMenuButtonsParams(in);
}
public UpdateContextMenuButtonsParams[] newArray(int size) {
return new UpdateContextMenuButtonsParams[size];
}
};
public ContextMenuButtonsParams getContextMenuButtonsParams() {
return buttonsParams;
}
public void writeToParcel(Parcel out, int flags) {
out.writeParcelable(buttonsParams, flags);
}
private void readFromParcel(Parcel in) {
buttonsParams = in.readParcelable(ContextMenuButtonsParams.class.getClassLoader());
}
public int describeContents() {
return 0;
}
}

View file

@ -20,17 +20,19 @@ public class AMapPoint implements Parcelable {
private String shortName;
private String fullName;
private String typeName;
private String layerId;
private int color;
private ALatLon location;
private List<String> details = new ArrayList<>();
private Map<String, String> params = new HashMap<>();
public AMapPoint(String id, String shortName, String fullName, String typeName, int color,
ALatLon location, List<String> details, Map<String, String> params) {
public AMapPoint(String id, String shortName, String fullName, String typeName, String layerId,
int color, ALatLon location, List<String> details, Map<String, String> params) {
this.id = id;
this.shortName = shortName;
this.fullName = fullName;
this.typeName = typeName;
this.layerId = layerId;
this.color = color;
this.location = location;
if (details != null) {
@ -72,6 +74,10 @@ public class AMapPoint implements Parcelable {
return typeName;
}
public String getLayerId() {
return layerId;
}
public int getColor() {
return color;
}
@ -93,6 +99,7 @@ public class AMapPoint implements Parcelable {
out.writeString(shortName);
out.writeString(fullName);
out.writeString(typeName);
out.writeString(layerId);
out.writeInt(color);
out.writeParcelable(location, flags);
out.writeStringList(details);
@ -104,6 +111,7 @@ public class AMapPoint implements Parcelable {
shortName = in.readString();
fullName = in.readString();
typeName = in.readString();
layerId = in.readString();
color = in.readInt();
location = in.readParcelable(ALatLon.class.getClassLoader());
in.readStringList(details);

View file

@ -6,10 +6,12 @@ import android.os.Parcelable;
public class UpdateMapPointParams implements Parcelable {
private String layerId;
private AMapPoint point;
private boolean updateOpenedMenuAndMap;
public UpdateMapPointParams(String layerId, AMapPoint point) {
public UpdateMapPointParams(String layerId, AMapPoint point, boolean updateOpenedMenuAndMap) {
this.layerId = layerId;
this.point = point;
this.updateOpenedMenuAndMap = updateOpenedMenuAndMap;
}
public UpdateMapPointParams(Parcel in) {
@ -35,14 +37,20 @@ public class UpdateMapPointParams implements Parcelable {
return point;
}
public boolean isUpdateOpenedMenuAndMap() {
return updateOpenedMenuAndMap;
}
public void writeToParcel(Parcel out, int flags) {
out.writeString(layerId);
out.writeParcelable(point, flags);
out.writeInt(updateOpenedMenuAndMap ? 1 : 0);
}
private void readFromParcel(Parcel in) {
layerId = in.readString();
point = in.readParcelable(AMapPoint.class.getClassLoader());
updateOpenedMenuAndMap = in.readInt() != 0;
}
public int describeContents() {

View file

@ -47,6 +47,10 @@ import net.osmand.SecondSplashScreenFragment;
import net.osmand.StateChangedListener;
import net.osmand.ValueHolder;
import net.osmand.access.MapAccessibilityActions;
import net.osmand.aidl.OsmandAidlApi.AMapPointUpdateListener;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.map.ALatLon;
import net.osmand.aidl.maplayer.point.AMapPoint;
import net.osmand.core.android.AtlasMapRendererView;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
@ -117,6 +121,7 @@ import net.osmand.plus.search.QuickSearchDialogFragment;
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchTab;
import net.osmand.plus.search.QuickSearchDialogFragment.QuickSearchType;
import net.osmand.plus.views.AddGpxPointBottomSheetHelper.NewGpxPoint;
import net.osmand.plus.views.AidlMapLayer;
import net.osmand.plus.views.AnimateDraggingMapThread;
import net.osmand.plus.views.MapControlsLayer;
import net.osmand.plus.views.MapInfoLayer;
@ -149,7 +154,7 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class MapActivity extends OsmandActionBarActivity implements DownloadEvents,
OnRequestPermissionsResultCallback, IRouteInformationListener,
OnRequestPermissionsResultCallback, IRouteInformationListener, AMapPointUpdateListener,
MapMarkerChangedListener, OnDismissDialogFragmentListener, OnDrawMapListener, OsmAndAppCustomizationListener {
public static final String INTENT_KEY_PARENT_MAP_ACTIVITY = "intent_parent_map_activity_key";
@ -1785,6 +1790,31 @@ public class MapActivity extends OsmandActionBarActivity implements DownloadEven
refreshMap();
}
@Override
public void onAMapPointUpdated(final AMapPoint point, String layerId) {
if (canUpdateAMapPointMenu(point, layerId)) {
app.runInUIThread(new Runnable() {
@Override
public void run() {
ALatLon loc = point.getLocation();
LatLon latLon = new LatLon(loc.getLatitude(), loc.getLongitude());
PointDescription pointDescription = new PointDescription(PointDescription.POINT_TYPE_MARKER, point.getFullName());
mapContextMenu.update(latLon, pointDescription, point);
mapContextMenu.centerMarkerLocation();
}
});
}
}
private boolean canUpdateAMapPointMenu(AMapPoint point, String layerId) {
Object object = mapContextMenu.getObject();
if (!mapContextMenu.isVisible() || !(object instanceof AMapPoint)) {
return false;
}
AMapPoint oldPoint = (AMapPoint) object;
return oldPoint.getLayerId().equals(layerId) && oldPoint.getId().equals(point.getId());
}
private class ScreenOffReceiver extends BroadcastReceiver {
@Override

View file

@ -7,10 +7,13 @@ import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Pair;
import android.view.View;
import android.widget.LinearLayout;
import net.osmand.CallbackWithObject;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.Location;
import net.osmand.StateChangedListener;
import net.osmand.data.Amenity;
@ -20,8 +23,6 @@ import net.osmand.data.PointDescription;
import net.osmand.data.TransportStop;
import net.osmand.plus.ApplicationMode;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.GPXUtilities.GPXFile;
import net.osmand.GPXUtilities.WptPt;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.MapMarkersHelper.MapMarker;
import net.osmand.plus.MapMarkersHelper.MapMarkerChangedListener;
@ -419,10 +420,14 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL
active = false;
}
} else {
WeakReference<MapContextMenuFragment> fragmentRef = findMenuFragment();
if (fragmentRef != null) {
fragmentRef.get().centerMarkerLocation();
}
centerMarkerLocation();
}
}
public void centerMarkerLocation() {
WeakReference<MapContextMenuFragment> fragmentRef = findMenuFragment();
if (fragmentRef != null) {
fragmentRef.get().centerMarkerLocation();
}
}
@ -1386,6 +1391,15 @@ public class MapContextMenu extends MenuTitleController implements StateChangedL
}
}
public List<Pair<TitleButtonController, TitleButtonController>> getAdditionalButtonsControllers() {
MenuController menuController = getMenuController();
if (menuController != null) {
return menuController.getAdditionalButtonsControllers();
} else {
return null;
}
}
public TitleProgressController getTitleProgressController() {
MenuController menuController = getMenuController();
if (menuController != null) {

View file

@ -14,7 +14,9 @@ import android.support.annotation.Nullable;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.content.ContextCompat;
import android.support.v7.view.ContextThemeWrapper;
import android.text.TextUtils;
import android.util.Pair;
import android.util.TypedValue;
import android.view.GestureDetector;
import android.view.Gravity;
@ -1083,6 +1085,7 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
TitleButtonController bottomTitleButtonController = menu.getBottomTitleButtonController();
TitleButtonController leftDownloadButtonController = menu.getLeftDownloadButtonController();
TitleButtonController rightDownloadButtonController = menu.getRightDownloadButtonController();
List<Pair<TitleButtonController, TitleButtonController>> additionalButtonsControllers = menu.getAdditionalButtonsControllers();
TitleProgressController titleProgressController = menu.getTitleProgressController();
// Title buttons
@ -1195,6 +1198,17 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
rightDownloadButtonView.setVisibility(View.INVISIBLE);
}
final LinearLayout additionalButtonsContainer = (LinearLayout) view.findViewById(R.id.additional_buttons_container);
if (additionalButtonsControllers != null && !additionalButtonsControllers.isEmpty()) {
additionalButtonsContainer.removeAllViews();
for (Pair<TitleButtonController, TitleButtonController> buttonControllers : additionalButtonsControllers) {
attachButtonsRow(additionalButtonsContainer, buttonControllers.first, buttonControllers.second);
}
additionalButtonsContainer.setVisibility(View.VISIBLE);
} else {
additionalButtonsContainer.setVisibility(View.GONE);
}
// Progress bar
final View titleProgressContainer = view.findViewById(R.id.title_progress_container);
if (titleProgressController != null) {
@ -1222,6 +1236,46 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
}
}
private void attachButtonsRow(ViewGroup container, final TitleButtonController leftButtonController, final TitleButtonController rightButtonController) {
ContextThemeWrapper ctx = new ContextThemeWrapper(getMapActivity(), !nightMode ? R.style.OsmandLightTheme : R.style.OsmandDarkTheme);
LayoutInflater inflater = LayoutInflater.from(ctx);
View view = inflater.inflate(R.layout.context_menu_buttons, container, false);
// Left button
final View leftButtonView = view.findViewById(R.id.additional_button_left_view);
final TextView leftButton = (TextView) view.findViewById(R.id.additional_button_left);
fillButtonInfo(leftButtonController, leftButtonView, leftButton);
// Right button
final View rightButtonView = view.findViewById(R.id.additional_button_right_view);
final TextView rightButton = (TextView) view.findViewById(R.id.additional_button_right);
fillButtonInfo(rightButtonController, rightButtonView, rightButton);
container.addView(view);
}
private void fillButtonInfo(final TitleButtonController buttonController, View buttonView, TextView buttonText) {
if (buttonController != null) {
enableDisableButtons(buttonView, buttonText, buttonController.enabled);
buttonText.setText(buttonController.caption);
buttonView.setVisibility(buttonController.visible ? View.VISIBLE : View.INVISIBLE);
Drawable leftIcon = buttonController.getLeftIcon();
Drawable rightIcon = buttonController.getRightIcon();
buttonText.setCompoundDrawablesWithIntrinsicBounds(leftIcon, null, rightIcon, null);
buttonText.setCompoundDrawablePadding(dpToPx(8f));
((LinearLayout) buttonView).setGravity(rightIcon != null ? Gravity.END : Gravity.START);
buttonView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
buttonController.buttonPressed();
}
});
} else {
buttonView.setVisibility(View.INVISIBLE);
}
}
private void buildHeader() {
OsmandApplication app = getMyApplication();
if (app != null && view != null) {
@ -1479,6 +1533,12 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
titleBottomButtonHeight = titleBottomButtonContainer.getMeasuredHeight();
}
int additionalButtonsHeight = 0;
View additionalButtonsContainer = view.findViewById(R.id.additional_buttons_container);
if (additionalButtonsContainer.getVisibility() == View.VISIBLE) {
additionalButtonsHeight = additionalButtonsContainer.getMeasuredHeight();
}
int titleProgressHeight = 0;
View titleProgressContainer = view.findViewById(R.id.title_progress_container);
if (titleProgressContainer.getVisibility() == View.VISIBLE) {
@ -1493,12 +1553,12 @@ public class MapContextMenuFragment extends BaseOsmAndFragment implements Downlo
}
newMenuTopViewHeight = menuTopViewHeightExcludingTitle + titleHeight
+ titleButtonHeight + downloadButtonsHeight
+ titleBottomButtonHeight + titleProgressHeight + line3Height;
+ titleBottomButtonHeight + additionalButtonsHeight + titleProgressHeight + line3Height;
dy = Math.max(0, newMenuTopViewHeight - menuTopViewHeight
- (newMenuTopShadowAllHeight - menuTopShadowAllHeight));
} else {
menuTopViewHeightExcludingTitle = newMenuTopViewHeight - line1.getMeasuredHeight() - line2MeasuredHeight
- titleButtonHeight - downloadButtonsHeight - titleBottomButtonHeight - titleProgressHeight-line3Height;
- titleButtonHeight - downloadButtonsHeight - titleBottomButtonHeight - additionalButtonsHeight - titleProgressHeight-line3Height;
menuTitleTopBottomPadding = (line1.getMeasuredHeight() - line1.getLineCount() * line1.getLineHeight())
+ (line2MeasuredHeight - line2LineCount * line2LineHeight);
menuButtonsHeight = view.findViewById(R.id.context_menu_bottom_buttons).getHeight()

View file

@ -12,6 +12,7 @@ import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.text.SpannableString;
import android.text.style.ForegroundColorSpan;
import android.util.Pair;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.LinearLayout;
@ -79,7 +80,6 @@ import net.osmand.util.OpeningHoursParser.OpeningHours;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
@ -111,6 +111,7 @@ public abstract class MenuController extends BaseMenuController implements Colla
protected TitleButtonController leftDownloadButtonController;
protected TitleButtonController rightDownloadButtonController;
protected List<Pair<TitleButtonController, TitleButtonController>> additionalButtonsControllers;
protected TitleProgressController titleProgressController;
protected TopToolbarController toolbarController;
@ -356,6 +357,10 @@ public abstract class MenuController extends BaseMenuController implements Colla
return rightDownloadButtonController;
}
public List<Pair<TitleButtonController, TitleButtonController>> getAdditionalButtonsControllers() {
return additionalButtonsControllers;
}
public TitleProgressController getTitleProgressController() {
return titleProgressController;
}

View file

@ -8,7 +8,10 @@ import android.net.Uri;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.util.Pair;
import net.osmand.aidl.contextmenu.AContextMenuButton;
import net.osmand.aidl.contextmenu.ContextMenuButtonsParams;
import net.osmand.aidl.maplayer.point.AMapPoint;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
@ -23,6 +26,9 @@ import net.osmand.util.Algorithms;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
public class AMapPointMenuController extends MenuController {
@ -33,10 +39,24 @@ public class AMapPointMenuController extends MenuController {
private Drawable pointDrawable;
public AMapPointMenuController(@NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull AMapPoint point) {
public AMapPointMenuController(@NonNull MapActivity mapActivity, @NonNull PointDescription pointDescription, @NonNull final AMapPoint point) {
super(new MenuBuilder(mapActivity), pointDescription, mapActivity);
this.point = point;
pointDrawable = getPointDrawable();
final OsmandApplication app = mapActivity.getMyApplication();
Map<String, ContextMenuButtonsParams> buttonsParamsMap = app.getAidlApi().getContextMenuButtonsParams();
if (!buttonsParamsMap.isEmpty()) {
additionalButtonsControllers = new ArrayList<>();
for (ContextMenuButtonsParams buttonsParams : buttonsParamsMap.values()) {
List<String> pointsIds = buttonsParams.getPointsIds();
if (((pointsIds == null || pointsIds.isEmpty()) || pointsIds.contains(point.getId())) || buttonsParams.getLayerId().equals(point.getLayerId())) {
long callbackId = buttonsParams.getCallbackId();
TitleButtonController leftButtonController = createAdditionButtonController(buttonsParams.getLeftButton(), callbackId);
TitleButtonController rightButtonController = createAdditionButtonController(buttonsParams.getRightButton(), callbackId);
additionalButtonsControllers.add(Pair.create(leftButtonController, rightButtonController));
}
}
}
}
@Override
@ -138,13 +158,39 @@ public class AMapPointMenuController extends MenuController {
return false;
}
private TitleButtonController createAdditionButtonController(final AContextMenuButton contextMenuButton, final long callbackId) {
MapActivity mapActivity = getMapActivity();
if (mapActivity == null || contextMenuButton == null) {
return null;
}
TitleButtonController titleButtonController = new TitleButtonController() {
@Override
public void buttonPressed() {
MapActivity mapActivity = getMapActivity();
if (mapActivity != null) {
int buttonId = contextMenuButton.getButtonId();
String pointId = point.getId();
String layerId = point.getLayerId();
mapActivity.getMyApplication().getAidlApi().contextMenuCallbackButtonClicked(callbackId, buttonId, pointId, layerId);
}
}
};
titleButtonController.caption = contextMenuButton.getLeftTextCaption();
titleButtonController.rightTextCaption = contextMenuButton.getRightTextCaption();
titleButtonController.leftIconId = getIconIdByName(contextMenuButton.getLeftIconName());
titleButtonController.rightIconId = getIconIdByName(contextMenuButton.getRightIconName());
titleButtonController.enabled = contextMenuButton.isEnabled();
titleButtonController.needColorizeIcon = contextMenuButton.isNeedColorizeIcon();
return titleButtonController;
}
private int getPointTypeIconId() {
MapActivity activity = getMapActivity();
if (activity != null) {
String iconName = point.getParams().get(AMapPoint.POINT_TYPE_ICON_NAME_PARAM);
if (!TextUtils.isEmpty(iconName)) {
OsmandApplication app = activity.getMyApplication();
return app.getResources().getIdentifier(iconName, "drawable", app.getPackageName());
return getIconIdByName(iconName);
}
}
if (!TextUtils.isEmpty(point.getShortName())) {
@ -153,6 +199,15 @@ public class AMapPointMenuController extends MenuController {
return NO_ICON;
}
private int getIconIdByName(String iconName) {
MapActivity activity = getMapActivity();
if (activity != null && !TextUtils.isEmpty(iconName)) {
OsmandApplication app = activity.getMyApplication();
return app.getResources().getIdentifier(iconName, "drawable", app.getPackageName());
}
return 0;
}
private float getPointSpeed() {
String speed = point.getParams().get(AMapPoint.POINT_SPEED_PARAM);
if (!TextUtils.isEmpty(speed)) {

View file

@ -0,0 +1,5 @@
package net.osmand.plus.mapcontextmenu.other;
public interface IContextMenuButtonListener {
void onContextMenuButtonClicked(int buttonId, String pointId, String layerId);
}