Add list, delete and upload POI to Openstreetmap Offline POI edition activity
This commit is contained in:
parent
84ad4b24a4
commit
db007efb75
9 changed files with 351 additions and 14 deletions
7
OsmAnd/res/layout/local_openstreetmap_list_item.xml
Normal file
7
OsmAnd/res/layout/local_openstreetmap_list_item.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView android:id="@+id/local_openstreetmap_name" android:gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:layout_weight="1" android:textSize="20sp" android:layout_marginLeft="8dp"></TextView>
|
||||
</LinearLayout>
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView android:id="@+id/local_openstreetmap_category_name" android:gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content"
|
||||
android:textSize="21sp" android:layout_marginLeft="40dp"></TextView>
|
||||
|
||||
</LinearLayout>
|
|
@ -1,6 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8" standalone="no"?>
|
||||
<resources>
|
||||
<string name="local_openstreetmap_descr_title">Asynchrone Openstreetmap POI Edition:</string>
|
||||
<string name="local_openstreetmap_items"></string>
|
||||
<string name="local_openstreetmap_show_poi">Show POI on Map</string>
|
||||
<string name="local_openstreetmap_upload">Upload modification to OSM</string>
|
||||
<string name="local_openstreetmap_delete">Delete POI modification</string>
|
||||
<string name="local_openstreetmap_descr_title">Asynchrone Openstreetmap POI Edition:</string>
|
||||
<string name="local_openstreetmap_settings">Local Openstreetmap Points</string>
|
||||
<string name="local_openstreetmap_settings_descr">Local Points Saved in DB</string>
|
||||
|
||||
|
|
|
@ -15,21 +15,21 @@ import net.osmand.osm.Node;
|
|||
import net.osmand.osm.OSMSettings.OSMTagKey;
|
||||
import net.osmand.plus.R;
|
||||
import net.osmand.plus.OpenstreetmapsDbHelper;
|
||||
import net.osmand.plus.activities.MapActivity;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Xml;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class OpenstreetmapLocalUtil implements OpenstreetmapUtil {
|
||||
|
||||
private final MapActivity ctx;
|
||||
private final Context ctx;
|
||||
private final OpenstreetmapsDbHelper db;
|
||||
|
||||
public final static Log log = LogUtil.getLog(OpenstreetmapLocalUtil.class);
|
||||
|
||||
public OpenstreetmapLocalUtil(MapActivity uiContext){
|
||||
public OpenstreetmapLocalUtil(Context uiContext){
|
||||
this.ctx = uiContext;
|
||||
this.db = new OpenstreetmapsDbHelper(ctx);
|
||||
}
|
||||
|
|
|
@ -22,7 +22,10 @@ public class OpenstreetmapPoint implements Serializable {
|
|||
}
|
||||
|
||||
public String getName() {
|
||||
return entity.getTag(OSMTagKey.NAME.getValue());
|
||||
String ret = entity.getTag(OSMTagKey.NAME.getValue());
|
||||
if (ret == null)
|
||||
return "";
|
||||
return ret;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
|
@ -50,7 +53,10 @@ public class OpenstreetmapPoint implements Serializable {
|
|||
}
|
||||
|
||||
public String getOpeninghours() {
|
||||
return entity.getTag(OSMTagKey.OPENING_HOURS.getValue());
|
||||
String ret = entity.getTag(OSMTagKey.OPENING_HOURS.getValue());
|
||||
if (ret == null)
|
||||
return "";
|
||||
return entity.getTag(ret);
|
||||
}
|
||||
|
||||
public Node getEntity() {
|
||||
|
@ -88,4 +94,12 @@ public class OpenstreetmapPoint implements Serializable {
|
|||
public void setStored(boolean stored) {
|
||||
this.stored = stored;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return new StringBuffer("Openstreetmap Point ").append(this.getAction()).append(" ").append(this.getName())
|
||||
.append(" (").append(this.getId()).append("): [")
|
||||
.append(this.getType()).append("/").append(this.getSubtype())
|
||||
.append(" (").append(this.getLatitude()).append(", ").append(this.getLongitude())
|
||||
.append(")]").toString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ import org.apache.http.params.HttpParams;
|
|||
import org.xml.sax.SAXException;
|
||||
import org.xmlpull.v1.XmlSerializer;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Xml;
|
||||
import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
||||
|
@ -69,7 +71,8 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
|||
|
||||
private static final long NO_CHANGESET_ID = -1;
|
||||
|
||||
private final MapActivity ctx;
|
||||
private final Context ctx;
|
||||
private final View view;
|
||||
private EntityInfo entityInfo;
|
||||
|
||||
// reuse changeset
|
||||
|
@ -78,8 +81,9 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
|||
|
||||
public final static Log log = LogUtil.getLog(OpenstreetmapRemoteUtil.class);
|
||||
|
||||
public OpenstreetmapRemoteUtil(MapActivity uiContext){
|
||||
public OpenstreetmapRemoteUtil(Context uiContext, View view){
|
||||
this.ctx = uiContext;
|
||||
this.view = view;
|
||||
}
|
||||
|
||||
public EntityInfo getEntityInfo() {
|
||||
|
@ -367,6 +371,29 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
|||
}
|
||||
}
|
||||
|
||||
public EntityInfo loadNode(Node n) {
|
||||
long nodeId = n.getId() >> 1;
|
||||
try {
|
||||
String res = sendRequest(SITE_API + "api/0.6/node/"+nodeId, "GET", null, ctx.getString(R.string.loading_poi_obj) + nodeId, false); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if(res != null){
|
||||
OsmBaseStorage st = new OsmBaseStorage();
|
||||
st.parseOSM(new ByteArrayInputStream(res.getBytes("UTF-8")), null, null, true); //$NON-NLS-1$
|
||||
EntityId id = new Entity.EntityId(EntityType.NODE, nodeId);
|
||||
Node entity = (Node) st.getRegisteredEntities().get(id);
|
||||
entityInfo = st.getRegisteredEntityInfo().get(id);
|
||||
return entityInfo;
|
||||
}
|
||||
|
||||
} catch (IOException e) {
|
||||
log.error("Loading node failed " + nodeId, e); //$NON-NLS-1$
|
||||
Toast.makeText(ctx, ctx.getResources().getString(R.string.error_io_error), Toast.LENGTH_LONG).show();
|
||||
} catch (SAXException e) {
|
||||
log.error("Loading node failed " + nodeId, e); //$NON-NLS-1$
|
||||
Toast.makeText(ctx, ctx.getResources().getString(R.string.error_io_error), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Node loadNode(Amenity n) {
|
||||
if(n.getId() % 2 == 1){
|
||||
// that's way id
|
||||
|
@ -399,7 +426,7 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil {
|
|||
}
|
||||
|
||||
private void showWarning(final String msg){
|
||||
ctx.getMapView().post(new Runnable(){
|
||||
view.post(new Runnable(){
|
||||
@Override
|
||||
public void run() {
|
||||
Toast.makeText(ctx, msg, Toast.LENGTH_LONG).show();
|
||||
|
|
|
@ -70,6 +70,28 @@ public class OpenstreetmapsDbHelper extends SQLiteOpenHelper {
|
|||
return false;
|
||||
}
|
||||
|
||||
public boolean deleteOpenstreetmap(OpenstreetmapPoint p) {
|
||||
checkOpenstreetmapPoints();
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
if (db != null) {
|
||||
db.execSQL("DELETE FROM " + OPENSTREETMAP_TABLE_NAME +
|
||||
" WHERE " + OPENSTREETMAP_COL_ID + " = ? AND " +
|
||||
OPENSTREETMAP_COL_NAME + " = ? AND " +
|
||||
OPENSTREETMAP_COL_TYPE + " = ? AND " +
|
||||
OPENSTREETMAP_COL_SUBTYPE + " = ? AND " +
|
||||
OPENSTREETMAP_COL_LAT + " = ? AND " +
|
||||
OPENSTREETMAP_COL_LON + " = ? AND " +
|
||||
OPENSTREETMAP_COL_ACTION + " = ? AND " +
|
||||
OPENSTREETMAP_COL_COMMENT + " = ? AND " +
|
||||
OPENSTREETMAP_COL_OPENINGHOURS + " = ?",
|
||||
new Object[] { p.getId(), p.getName(), p.getType(), p.getSubtype(), p.getLatitude(), p.getLongitude(), OpenstreetmapRemoteUtil.stringAction.get(p.getAction()), p.getComment(), p.getOpeninghours() }); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
cachedOpenstreetmapPoints.remove(p);
|
||||
p.setStored(false);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkOpenstreetmapPoints(){
|
||||
SQLiteDatabase db = getWritableDatabase();
|
||||
if (db != null) {
|
||||
|
@ -86,11 +108,14 @@ public class OpenstreetmapsDbHelper extends SQLiteOpenHelper {
|
|||
|
||||
entity.putTag(query.getString(2), query.getString(3));
|
||||
entity.putTag(OSMTagKey.NAME.getValue(), name);
|
||||
entity.putTag(OSMTagKey.OPENING_HOURS.getValue(), query.getString(8));
|
||||
String openingHours = query.getString(8);
|
||||
if (openingHours != null && openingHours.length() > 0)
|
||||
entity.putTag(OSMTagKey.OPENING_HOURS.getValue(), openingHours);
|
||||
p.setEntity(entity);
|
||||
p.setStored(true);
|
||||
p.setAction(query.getString(6));
|
||||
p.setComment(query.getString(7));
|
||||
cachedOpenstreetmapPoints.add(p);
|
||||
} while (query.moveToNext());
|
||||
}
|
||||
query.close();
|
||||
|
|
|
@ -75,7 +75,7 @@ public class EditingPOIActivity implements DialogProvider {
|
|||
if(!settings.isInternetConnectionAvailable(true)){
|
||||
this.openstreetmapUtil = new OpenstreetmapLocalUtil(ctx);
|
||||
} else {
|
||||
this.openstreetmapUtil = new OpenstreetmapRemoteUtil(ctx);
|
||||
this.openstreetmapUtil = new OpenstreetmapRemoteUtil(ctx, ctx.getMapView());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,15 +1,44 @@
|
|||
package net.osmand.plus.activities;
|
||||
|
||||
import android.app.ExpandableListActivity;
|
||||
import android.app.AlertDialog;
|
||||
import android.app.AlertDialog.Builder;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.widget.BaseExpandableListAdapter;
|
||||
import android.widget.ExpandableListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.ExpandableListView.ExpandableListContextMenuInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import net.osmand.OpenstreetmapPoint;
|
||||
import net.osmand.OpenstreetmapUtil;
|
||||
import net.osmand.OpenstreetmapRemoteUtil;
|
||||
import net.osmand.LogUtil;
|
||||
import net.osmand.osm.EntityInfo;
|
||||
import net.osmand.plus.AmenityIndexRepositoryOdb;
|
||||
import net.osmand.plus.OpenstreetmapsDbHelper;
|
||||
import net.osmand.plus.OsmandSettings;
|
||||
import net.osmand.plus.R;
|
||||
|
||||
import android.app.ExpandableListActivity;
|
||||
import android.os.Bundle;
|
||||
|
||||
public class LocalOpenstreetmapActivity extends ExpandableListActivity {
|
||||
|
||||
private LocalOpenstreetmapAdapter listAdapter;
|
||||
|
||||
private OsmandSettings settings;
|
||||
|
||||
private OpenstreetmapsDbHelper db;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -17,6 +46,229 @@ public class LocalOpenstreetmapActivity extends ExpandableListActivity {
|
|||
|
||||
setContentView(R.layout.local_openstreetmap);
|
||||
settings = OsmandSettings.getOsmandSettings(this);
|
||||
listAdapter = new LocalOpenstreetmapAdapter();
|
||||
|
||||
getExpandableListView().setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v, ContextMenuInfo menuInfo) {
|
||||
long packedPos = ((ExpandableListContextMenuInfo)menuInfo).packedPosition;
|
||||
int group = ExpandableListView.getPackedPositionGroup(packedPos);
|
||||
int child = ExpandableListView.getPackedPositionChild(packedPos);
|
||||
if (child >= 0 && group >= 0) {
|
||||
final OpenstreetmapPoint point = (OpenstreetmapPoint) listAdapter.getChild(group, child);
|
||||
showContextMenu(point);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
setListAdapter(listAdapter);
|
||||
|
||||
db = new OpenstreetmapsDbHelper(this);
|
||||
List<OpenstreetmapPoint> l = db.getOpenstreetmapPoints();
|
||||
android.util.Log.d(LogUtil.TAG, "List of POI " + l.size() + " length");
|
||||
for (OpenstreetmapPoint p : l) {
|
||||
listAdapter.addOpenstreetmapPoint(p);
|
||||
}
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
private void showContextMenu(final OpenstreetmapPoint info) {
|
||||
Builder builder = new AlertDialog.Builder(this);
|
||||
final List<Integer> menu = new ArrayList<Integer>();
|
||||
|
||||
menu.add(R.string.local_openstreetmap_show_poi);
|
||||
menu.add(R.string.local_openstreetmap_upload);
|
||||
menu.add(R.string.local_openstreetmap_delete);
|
||||
|
||||
String[] values = new String[menu.size()];
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = getString(menu.get(i));
|
||||
}
|
||||
builder.setItems(values, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
int resId = menu.get(which);
|
||||
if (info != null) {
|
||||
if (resId == R.string.local_openstreetmap_show_poi) {
|
||||
OsmandSettings settings = OsmandSettings.getOsmandSettings(LocalOpenstreetmapActivity.this);
|
||||
settings.setMapLocationToShow(info.getLatitude(), info.getLongitude(), settings.getLastKnownMapZoom());
|
||||
MapActivity.launchMapActivityMoveToTop(LocalOpenstreetmapActivity.this);
|
||||
} else if (resId == R.string.local_openstreetmap_delete) {
|
||||
listAdapter.delete(info);
|
||||
} else if (resId == R.string.local_openstreetmap_upload) {
|
||||
OpenstreetmapRemoteUtil remote = new OpenstreetmapRemoteUtil(LocalOpenstreetmapActivity.this,
|
||||
LocalOpenstreetmapActivity.this.getWindow().getDecorView());
|
||||
EntityInfo entityInfo = null;
|
||||
if (OpenstreetmapUtil.Action.CREATE != info.getAction()) {
|
||||
entityInfo = remote.loadNode(info.getEntity());
|
||||
}
|
||||
if (remote.commitNodeImpl(info.getAction(), info.getEntity(), entityInfo, info.getComment())) {
|
||||
listAdapter.delete(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
builder.show();
|
||||
}
|
||||
|
||||
|
||||
protected class LocalOpenstreetmapAdapter extends BaseExpandableListAdapter {
|
||||
Map<String, List<OpenstreetmapPoint>> data = new LinkedHashMap<String, List<OpenstreetmapPoint>>();
|
||||
List<String> category = new ArrayList<String>();
|
||||
List<String> filterCategory = null;
|
||||
|
||||
|
||||
public LocalOpenstreetmapAdapter() {
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
data.clear();
|
||||
category.clear();
|
||||
filterCategory = null;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void delete(OpenstreetmapPoint i) {
|
||||
final AmenityIndexRepositoryOdb repo = ((OsmandApplication) getApplication()).getResourceManager().getUpdatablePoiDb();
|
||||
android.util.Log.d(LogUtil.TAG, "Delete " + i);
|
||||
db.deleteOpenstreetmap(i);
|
||||
String c = i.getType();
|
||||
if(c != null){
|
||||
data.get(c).remove(i);
|
||||
// We need to re-insert the POI if it is a delete or modify
|
||||
repo.deleteAmenities(i.getId() << 1);
|
||||
repo.clearCache();
|
||||
}
|
||||
listAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void cancelFilter(){
|
||||
filterCategory = null;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void filterCategories(String... types) {
|
||||
List<String> filter = new ArrayList<String>();
|
||||
List<String> source = filterCategory == null ? category : filterCategory;
|
||||
for (String info : source) {
|
||||
for (String ts : types) {
|
||||
if (info.compareTo(ts) == 0) {
|
||||
filter.add(info);
|
||||
}
|
||||
}
|
||||
}
|
||||
filterCategory = filter;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
public void addOpenstreetmapPoint(OpenstreetmapPoint info) {
|
||||
int found = -1;
|
||||
// search from end
|
||||
for (int i = category.size() - 1; i >= 0; i--) {
|
||||
String cat = category.get(i);
|
||||
if (cat.compareTo(info.getType()) == 0) {
|
||||
found = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found == -1) {
|
||||
found = category.size();
|
||||
category.add(info.getType());
|
||||
}
|
||||
if (!data.containsKey(category.get(found))) {
|
||||
data.put(category.get(found), new ArrayList<OpenstreetmapPoint>());
|
||||
}
|
||||
data.get(category.get(found)).add(info);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OpenstreetmapPoint getChild(int groupPosition, int childPosition) {
|
||||
String cat = filterCategory != null ? filterCategory.get(groupPosition) : category.get(groupPosition);
|
||||
return data.get(cat).get(childPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getChildId(int groupPosition, int childPosition) {
|
||||
// it would be unusable to have 10000 local indexes
|
||||
return groupPosition * 10000 + childPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildView(int groupPosition, int childPosition, boolean isLastChild, View convertView, ViewGroup parent) {
|
||||
View v = convertView;
|
||||
final OpenstreetmapPoint child = (OpenstreetmapPoint) getChild(groupPosition, childPosition);
|
||||
if (v == null ) {
|
||||
LayoutInflater inflater = getLayoutInflater();
|
||||
v = inflater.inflate(net.osmand.plus.R.layout.local_openstreetmap_list_item, parent, false);
|
||||
}
|
||||
TextView viewName = ((TextView) v.findViewById(R.id.local_openstreetmap_name));
|
||||
viewName.setText("(" + child.getSubtype() + ") " + child.getName());
|
||||
if (child.getAction() == OpenstreetmapUtil.Action.CREATE) {
|
||||
viewName.setTextColor(Color.GREEN);
|
||||
} else if (child.getAction() == OpenstreetmapUtil.Action.MODIFY) {
|
||||
viewName.setTextColor(Color.MAGENTA);
|
||||
} else if (child.getAction() == OpenstreetmapUtil.Action.DELETE) {
|
||||
viewName.setTextColor(Color.RED);
|
||||
}
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getGroupView(int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
|
||||
View v = convertView;
|
||||
String group = getGroup(groupPosition);
|
||||
if (v == null) {
|
||||
LayoutInflater inflater = getLayoutInflater();
|
||||
v = inflater.inflate(net.osmand.plus.R.layout.local_openstreetmap_list_item_category, parent, false);
|
||||
}
|
||||
StringBuilder t = new StringBuilder(group);
|
||||
TextView nameView = ((TextView) v.findViewById(R.id.local_openstreetmap_category_name));
|
||||
t.append(" [").append(getChildrenCount(groupPosition));
|
||||
if(getString(R.string.local_openstreetmap_items).length() > 0){
|
||||
t.append(" ").append(getString(R.string.local_openstreetmap_items));
|
||||
}
|
||||
if(getString(R.string.local_openstreetmap_items).length() > 0){
|
||||
t.append(" ").append(getString(R.string.local_openstreetmap_items));
|
||||
}
|
||||
List<OpenstreetmapPoint> list = data.get(group);
|
||||
t.append("]");
|
||||
nameView.setText(t.toString());
|
||||
|
||||
return v;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildrenCount(int groupPosition) {
|
||||
String cat = filterCategory != null ? filterCategory.get(groupPosition) : category.get(groupPosition);
|
||||
return data.get(cat).size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroup(int groupPosition) {
|
||||
return filterCategory == null ? category.get(groupPosition) : filterCategory.get(groupPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupCount() {
|
||||
return filterCategory == null ? category.size() : filterCategory.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getGroupId(int groupPosition) {
|
||||
return groupPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChildSelectable(int groupPosition, int childPosition) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue