package net.osmand.plus.myplaces;
import android.app.Activity;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.TypedArray;
import android.graphics.Typeface;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.MenuItemCompat;
import android.support.v7.app.AlertDialog;
import android.support.v7.view.ActionMode;
import android.support.v7.widget.PopupMenu;
import android.support.v7.widget.SearchView;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ExpandableListView;
import android.widget.Filter;
import android.widget.Filterable;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;
import net.osmand.AndroidUtils;
import net.osmand.IndexConstants;
import net.osmand.plus.ContextMenuAdapter;
import net.osmand.plus.ContextMenuAdapter.ItemClickListener;
import net.osmand.plus.ContextMenuItem;
import net.osmand.plus.GPXDatabase.GpxDataItem;
import net.osmand.plus.GPXUtilities;
import net.osmand.plus.GPXUtilities.GPXFile;
import net.osmand.plus.GPXUtilities.GPXTrackAnalysis;
import net.osmand.plus.GPXUtilities.WptPt;
import net.osmand.plus.GpxSelectionHelper;
import net.osmand.plus.GpxSelectionHelper.SelectedGpxFile;
import net.osmand.plus.IconsCache;
import net.osmand.plus.OsmAndFormatter;
import net.osmand.plus.OsmandApplication;
import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.OsmandSettings;
import net.osmand.plus.R;
import net.osmand.plus.activities.MapActivity;
import net.osmand.plus.activities.OsmandActionBarActivity;
import net.osmand.plus.activities.OsmandBaseExpandableListAdapter;
import net.osmand.plus.activities.SavingTrackHelper;
import net.osmand.plus.activities.TrackActivity;
import net.osmand.plus.base.OsmandExpandableListFragment;
import net.osmand.plus.dialogs.DirectionsDialogs;
import net.osmand.plus.download.ui.LocalIndexesFragment;
import net.osmand.plus.download.ui.LocalIndexesFragment.RenameCallback;
import net.osmand.plus.helpers.AndroidUiHelper;
import net.osmand.plus.monitoring.OsmandMonitoringPlugin;
import net.osmand.plus.osmedit.OsmEditingPlugin;
import net.osmand.util.Algorithms;
import java.io.File;
import java.text.Collator;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.regex.Pattern;
public class AvailableGPXFragment extends OsmandExpandableListFragment {
public static final Pattern ILLEGAL_PATH_NAME_CHARACTERS = Pattern.compile("[?:\"*|<>]");
public static final int SEARCH_ID = -1;
// public static final int ACTION_ID = 0;
// protected static final int DELETE_ACTION_ID = 1;
private boolean selectionMode = false;
private List<GpxInfo> selectedItems = new ArrayList<>();
private Set<Integer> selectedGroups = new LinkedHashSet<>();
private ActionMode actionMode;
private LoadGpxTask asyncLoader;
private ProcessGpxTask asyncProcessor;
private GpxIndexesAdapter allGpxAdapter;
private static MessageFormat formatMb = new MessageFormat("{0, number,##.#} MB", Locale.US);
private ContextMenuAdapter optionsMenuAdapter;
private AsyncTask<GpxInfo, ?, ?> operationTask;
private GpxSelectionHelper selectedGpxHelper;
private OsmandApplication app;
private boolean updateEnable;
private GpxInfo currentRecording;
private boolean showOnMapMode;
private View currentGpxView;
private View footerView;
private boolean importing = false;
@Override
public void onAttach(Context activity) {
super.onAttach(activity);
this.app = (OsmandApplication) getActivity().getApplication();
final Collator collator = Collator.getInstance();
collator.setStrength(Collator.SECONDARY);
currentRecording = new GpxInfo(getMyApplication().getSavingTrackHelper().getCurrentGpx(), getString(R.string.shared_string_currently_recording_track));
currentRecording.currentlyRecordingTrack = true;
asyncLoader = new LoadGpxTask();
selectedGpxHelper = ((OsmandApplication) activity.getApplicationContext()).getSelectedGpxHelper();
allGpxAdapter = new GpxIndexesAdapter(getActivity());
setAdapter(allGpxAdapter);
}
public boolean isImporting() {
return importing;
}
public void startImport() {
this.importing = true;
}
public void finishImport(boolean success) {
if (success) {
reloadTracks();
}
this.importing = false;
}
private void startHandler() {
Handler updateCurrentRecordingTrack = new Handler();
updateCurrentRecordingTrack.postDelayed(new Runnable() {
@Override
public void run() {
if (getView() != null && updateEnable) {
updateCurrentTrack();
if (selectedGpxHelper.getSelectedCurrentRecordingTrack() != null) {
allGpxAdapter.notifyDataSetChanged();
}
startHandler();
}
}
}, 2000);
}
public List<GpxInfo> getSelectedItems() {
return selectedItems;
}
@Override
public void onResume() {
super.onResume();
if (!importing) {
if (asyncLoader == null || asyncLoader.getResult() == null) {
asyncLoader = new LoadGpxTask();
asyncLoader.execute(getActivity());
} else {
allGpxAdapter.refreshSelected();
allGpxAdapter.notifyDataSetChanged();
}
asyncProcessor = new ProcessGpxTask();
asyncProcessor.execute();
}
updateCurrentTrack();
updateEnable = true;
startHandler();
}
@Override
public void onPause() {
super.onPause();
updateEnable = false;
if (operationTask != null) {
operationTask.cancel(true);
}
if (asyncProcessor != null) {
asyncProcessor.cancel(false);
asyncProcessor = null;
}
}
public void updateCurrentTrack() {
final OsmandMonitoringPlugin plugin = OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class);
if (currentGpxView == null || plugin == null) {
return;
}
final boolean isRecording = app.getSettings().SAVE_GLOBAL_TRACK_TO_GPX.get();
ImageView icon = (ImageView) currentGpxView.findViewById(R.id.icon);
icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.monitoring_rec_big));
icon.setVisibility(selectionMode && showOnMapMode ? View.GONE : View.VISIBLE);
final boolean light = app.getSettings().isLightContent();
SavingTrackHelper sth = app.getSavingTrackHelper();
Button stop = (Button) currentGpxView.findViewById(R.id.action_button);
if (isRecording) {
currentGpxView.findViewById(R.id.segment_time_div).setVisibility(View.VISIBLE);
TextView segmentTime = (TextView) currentGpxView.findViewById(R.id.segment_time);
segmentTime.setText(OsmAndFormatter.getFormattedDurationShort((int)(sth.getDuration() / 1000)));
segmentTime.setVisibility(View.VISIBLE);
stop.setCompoundDrawablesWithIntrinsicBounds(app.getIconsCache()
.getIcon(R.drawable.ic_action_rec_stop, light ? R.color.color_dialog_buttons_light : R.color.color_dialog_buttons_dark), null, null, null);
stop.setText(app.getString(R.string.shared_string_control_stop));
stop.setContentDescription(app.getString(R.string.gpx_monitoring_stop));
} else {
currentGpxView.findViewById(R.id.segment_time_div).setVisibility(View.GONE);
currentGpxView.findViewById(R.id.segment_time).setVisibility(View.GONE);
stop.setCompoundDrawablesWithIntrinsicBounds(app.getIconsCache()
.getIcon(R.drawable.ic_action_rec_start, light ? R.color.color_dialog_buttons_light : R.color.color_dialog_buttons_dark), null, null, null);
stop.setText(app.getString(R.string.shared_string_record));
stop.setContentDescription(app.getString(R.string.gpx_monitoring_start));
}
stop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (isRecording) {
plugin.stopRecording();
updateCurrentTrack();
} else if (app.getLocationProvider().checkGPSEnabled(getActivity())) {
plugin.startGPXMonitoring(getActivity());
updateCurrentTrack();
}
}
});
Button save = (Button) currentGpxView.findViewById(R.id.save_button);
save.setCompoundDrawablesWithIntrinsicBounds(app.getIconsCache()
.getIcon(R.drawable.ic_action_gsave_dark, light ? R.color.color_dialog_buttons_light : R.color.color_dialog_buttons_dark), null, null, null);
save.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
plugin.saveCurrentTrack();
updateCurrentTrack();
}
});
if (sth.getPoints() > 0 || sth.getDistance() > 0) {
save.setVisibility(View.VISIBLE);
} else {
save.setVisibility(View.GONE);
}
save.setContentDescription(app.getString(R.string.save_current_track));
((TextView) currentGpxView.findViewById(R.id.points_count)).setText(String.valueOf(sth.getPoints()));
((TextView) currentGpxView.findViewById(R.id.distance))
.setText(OsmAndFormatter.getFormattedDistance(sth.getDistance(), app));
@SuppressWarnings("ConstantConditions")
final CheckBox checkbox = (CheckBox) currentGpxView.findViewById(R.id.check_local_index);
checkbox.setVisibility(selectionMode && showOnMapMode ? View.VISIBLE : View.GONE);
if (selectionMode && showOnMapMode) {
checkbox.setChecked(selectedItems.contains(currentRecording));
checkbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkbox.isChecked()) {
selectedItems.add(currentRecording);
} else {
selectedItems.remove(currentRecording);
}
updateSelectionMode(actionMode);
}
});
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.available_gpx, container, false);
listView = (ExpandableListView) v.findViewById(android.R.id.list);
setHasOptionsMenu(true);
if (OsmandPlugin.getEnabledPlugin(OsmandMonitoringPlugin.class) != null) {
currentGpxView = inflater.inflate(R.layout.current_gpx_item, null, false);
createCurrentTrackView();
currentGpxView.findViewById(R.id.current_track_info).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent newIntent = new Intent(getActivity(), getMyApplication().getAppCustomization().getTrackActivity());
newIntent.putExtra(TrackActivity.CURRENT_RECORDING, true);
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(newIntent);
}
});
listView.addHeaderView(currentGpxView);
/*
currentTrackView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openTrack(getActivity(), null);
}
});
*/
} else {
View headerView = inflater.inflate(R.layout.list_shadow_header, null, false);
listView.addHeaderView(headerView);
}
footerView = inflater.inflate(R.layout.list_shadow_footer, null, false);
listView.addFooterView(footerView);
if (this.adapter != null) {
listView.setAdapter(this.adapter);
}
return v;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
listView.setBackgroundColor(getResources().getColor(
app.getSettings().isLightContent() ? R.color.ctx_menu_info_view_bg_light
: R.color.ctx_menu_info_view_bg_dark));
}
public void createCurrentTrackView() {
ImageView distanceI = (ImageView) currentGpxView.findViewById(R.id.distance_icon);
distanceI.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_small_distance));
ImageView pointsI = (ImageView) currentGpxView.findViewById(R.id.points_icon);
pointsI.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_small_point));
updateCurrentTrack();
}
public static void openTrack(Activity a, final File f) {
Intent newIntent = new Intent(a, ((OsmandApplication) a.getApplication()).getAppCustomization().getTrackActivity());
// causes wrong position caching: newIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
if (f == null) {
newIntent.putExtra(TrackActivity.CURRENT_RECORDING, true);
} else {
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, f.getAbsolutePath());
}
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
a.startActivity(newIntent);
}
public void reloadTracks() {
asyncLoader = new LoadGpxTask();
asyncLoader.execute(getActivity());
if (asyncProcessor == null) {
asyncProcessor = new ProcessGpxTask();
asyncProcessor.execute();
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
menu.clear();
MenuItem mi = createMenuItem(menu, SEARCH_ID, R.string.search_poi_filter, R.drawable.ic_action_search_dark,
R.drawable.ic_action_search_dark, MenuItemCompat.SHOW_AS_ACTION_ALWAYS
| MenuItemCompat.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW);
SearchView searchView = new SearchView(getActivity());
FavoritesActivity.updateSearchView(getActivity(), searchView);
MenuItemCompat.setActionView(mi, searchView);
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextSubmit(String query) {
allGpxAdapter.getFilter().filter(query);
return true;
}
@Override
public boolean onQueryTextChange(String newText) {
allGpxAdapter.getFilter().filter(newText);
return true;
}
});
MenuItemCompat.setOnActionExpandListener(mi, new MenuItemCompat.OnActionExpandListener() {
@Override
public boolean onMenuItemActionExpand(MenuItem item) {
return true;
}
@Override
public boolean onMenuItemActionCollapse(MenuItem item) {
// Needed to hide intermediate progress bar after closing action mode
new Handler().postDelayed(new Runnable() {
public void run() {
hideProgressBar();
}
}, 100);
return true;
}
});
if (AndroidUiHelper.isOrientationPortrait(getActivity())) {
menu = ((FavoritesActivity) getActivity()).getClearToolbar(true).getMenu();
} else {
((FavoritesActivity) getActivity()).getClearToolbar(false);
}
((FavoritesActivity) getActivity()).updateListViewFooter(footerView);
// TODO Rewrite without ContextMenuAdapter
optionsMenuAdapter = new ContextMenuAdapter();
ItemClickListener listener = new ContextMenuAdapter.ItemClickListener() {
@Override
public boolean onContextMenuClick(ArrayAdapter<ContextMenuItem> adapter, final int itemId, int pos, boolean isChecked) {
if (itemId == R.string.local_index_mi_reload) {
reloadTracks();
} else if (itemId == R.string.shared_string_show_on_map) {
openShowOnMapMode();
} else if (itemId == R.string.shared_string_delete) {
openSelectionMode(itemId, R.drawable.ic_action_delete_dark, R.drawable.ic_action_delete_dark,
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
doAction(itemId);
}
});
} else if (itemId == R.string.gpx_add_track) {
addTrack();
}
return true;
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
optionsMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.gpx_add_track, getActivity())
.setIcon(R.drawable.ic_action_plus)
.setListener(listener).createItem());
}
optionsMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.shared_string_show_on_map, getActivity())
.setIcon(R.drawable.ic_show_on_map)
.setListener(listener).createItem());
optionsMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.shared_string_delete, getActivity())
.setIcon(R.drawable.ic_action_delete_dark).setListener(listener).createItem());
optionsMenuAdapter.addItem(new ContextMenuItem.ItemBuilder().setTitleId(R.string.local_index_mi_reload, getActivity())
.setIcon(R.drawable.ic_action_refresh_dark).setListener(listener).createItem());
OsmandPlugin.onOptionsMenuActivity(getActivity(), this, optionsMenuAdapter);
for (int j = 0; j < optionsMenuAdapter.length(); j++) {
final MenuItem item;
ContextMenuItem contextMenuItem = optionsMenuAdapter.getItem(j);
item = menu.add(0, contextMenuItem.getTitleId(), j + 1, contextMenuItem.getTitle());
MenuItemCompat.setShowAsAction(item, MenuItemCompat.SHOW_AS_ACTION_ALWAYS);
if (AndroidUiHelper.isOrientationPortrait(getActivity())) {
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
onOptionsItemSelected(item);
return true;
}
});
}
if (contextMenuItem.getIcon() != -1) {
item.setIcon(contextMenuItem.getIcon());
}
}
}
public void doAction(int actionResId) {
if (actionResId == R.string.shared_string_delete) {
operationTask = new DeleteGpxTask();
operationTask.execute(selectedItems.toArray(new GpxInfo[selectedItems.size()]));
} else {
operationTask = null;
}
if (actionMode != null) {
actionMode.finish();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int itemId = item.getItemId();
for (int i = 0; i < optionsMenuAdapter.length(); i++) {
ContextMenuItem contextMenuItem = optionsMenuAdapter.getItem(i);
if (itemId == contextMenuItem.getTitleId()) {
contextMenuItem.getItemClickListener().onContextMenuClick(null, itemId, i, false);
return true;
}
}
return super.onOptionsItemSelected(item);
}
private void addTrack() {
((FavoritesActivity) getActivity()).addTrack();
}
public void showProgressBar() {
((FavoritesActivity) getActivity()).setSupportProgressBarIndeterminateVisibility(true);
}
public void hideProgressBar() {
if (getActivity() != null) {
((FavoritesActivity) getActivity()).setSupportProgressBarIndeterminateVisibility(false);
}
}
private void updateSelectionMode(ActionMode m) {
if (selectedItems.size() > 0) {
m.setTitle(selectedItems.size() + " " + app.getString(R.string.shared_string_selected_lowercase));
} else {
m.setTitle("");
}
}
private void enableSelectionMode(boolean selectionMode) {
this.selectionMode = selectionMode;
if (AndroidUiHelper.isOrientationPortrait(getActivity())) {
((FavoritesActivity) getActivity()).setToolbarVisibility(!selectionMode &&
AndroidUiHelper.isOrientationPortrait(getActivity()));
((FavoritesActivity) getActivity()).updateListViewFooter(footerView);
}
}
private void openShowOnMapMode() {
enableSelectionMode(true);
showOnMapMode = true;
selectedItems.clear();
selectedGroups.clear();
final Set<GpxInfo> originalSelectedItems = allGpxAdapter.getSelectedGpx();
selectedItems.addAll(originalSelectedItems);
actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
enableSelectionMode(true);
updateSelectionMode(mode);
MenuItem it = menu.add(R.string.shared_string_show_on_map);
it.setIcon(R.drawable.ic_action_done);
MenuItemCompat.setShowAsAction(it, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM
| MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
updateCurrentTrack();
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
runSelection(false);
actionMode.finish();
allGpxAdapter.refreshSelected();
allGpxAdapter.notifyDataSetChanged();
return true;
}
private void runSelection(boolean showOnMap) {
operationTask = new SelectGpxTask(showOnMap);
originalSelectedItems.addAll(selectedItems);
operationTask.execute(originalSelectedItems.toArray(new GpxInfo[originalSelectedItems.size()]));
}
@Override
public void onDestroyActionMode(ActionMode mode) {
showOnMapMode = false;
enableSelectionMode(false);
updateCurrentTrack();
allGpxAdapter.notifyDataSetChanged();
}
});
allGpxAdapter.notifyDataSetChanged();
}
public void openSelectionMode(final int actionResId, int darkIcon, int lightIcon,
final DialogInterface.OnClickListener listener) {
final int actionIconId = !isLightActionBar() ? darkIcon : lightIcon;
String value = app.getString(actionResId);
if (value.endsWith("...")) {
value = value.substring(0, value.length() - 3);
}
final String actionButton = value;
if (allGpxAdapter.getGroupCount() == 0) {
Toast.makeText(getActivity(),
app.getString(R.string.local_index_no_items_to_do, actionButton.toLowerCase()), Toast.LENGTH_SHORT)
.show();
return;
}
enableSelectionMode(true);
selectedItems.clear();
selectedGroups.clear();
actionMode = getActionBarActivity().startSupportActionMode(new ActionMode.Callback() {
@Override
public boolean onCreateActionMode(ActionMode mode, Menu menu) {
enableSelectionMode(true);
MenuItem it = menu.add(actionResId);
if (actionIconId != 0) {
it.setIcon(actionIconId);
}
MenuItemCompat.setShowAsAction(it, MenuItemCompat.SHOW_AS_ACTION_IF_ROOM
| MenuItemCompat.SHOW_AS_ACTION_WITH_TEXT);
return true;
}
@Override
public boolean onPrepareActionMode(ActionMode mode, Menu menu) {
return false;
}
@Override
public boolean onActionItemClicked(ActionMode mode, MenuItem item) {
if (selectedItems.isEmpty()) {
Toast.makeText(getActivity(),
app.getString(R.string.local_index_no_items_to_do, actionButton.toLowerCase()),
Toast.LENGTH_SHORT).show();
return true;
}
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(getString(R.string.local_index_action_do, actionButton.toLowerCase(),
selectedItems.size()));
builder.setPositiveButton(actionButton, listener);
builder.setNegativeButton(R.string.shared_string_cancel, null);
builder.show();
return true;
}
@Override
public void onDestroyActionMode(ActionMode mode) {
enableSelectionMode(false);
allGpxAdapter.notifyDataSetChanged();
}
});
allGpxAdapter.notifyDataSetChanged();
}
private void showGpxOnMap(GpxInfo info) {
info.setGpx(GPXUtilities.loadGPXFile(app, info.file));
boolean e = true;
if (info.gpx != null) {
WptPt loc = info.gpx.findPointToShow();
OsmandSettings settings = getMyApplication().getSettings();
if (loc != null) {
settings.setMapLocationToShow(loc.lat, loc.lon, settings.getLastKnownMapZoom());
e = false;
getMyApplication().getSelectedGpxHelper().setGpxFileToDisplay(info.gpx);
MapActivity.launchMapActivityMoveToTop(getActivity());
}
}
if (e) {
Toast.makeText(getActivity(), R.string.gpx_file_is_empty, Toast.LENGTH_LONG).show();
}
}
private void collectDirs(File dir, List<File> dirs, File exclDir) {
File[] listFiles = dir.listFiles();
if (listFiles != null) {
Arrays.sort(listFiles);
for (File f : listFiles) {
if (f.isDirectory()) {
if (!exclDir.equals(f)) {
dirs.add(f);
}
collectDirs(f, dirs, exclDir);
}
}
}
}
private void moveGpx(final GpxInfo info) {
final ContextMenuAdapter menuAdapter = new ContextMenuAdapter();
ContextMenuItem.ItemBuilder itemBuilder = new ContextMenuItem.ItemBuilder();
final List<File> dirs = new ArrayList<>();
collectDirs(app.getAppPath(IndexConstants.GPX_INDEX_DIR), dirs, info.file.getParentFile());
if (!dirs.isEmpty()) {
if (!info.file.getParentFile().equals(app.getAppPath(IndexConstants.GPX_INDEX_DIR))) {
dirs.add(0, app.getAppPath(IndexConstants.GPX_INDEX_DIR));
}
String gpxDir = app.getAppPath(IndexConstants.GPX_INDEX_DIR).getPath();
int i = 0;
for (File dir : dirs) {
String dirName = dir.getPath();
if (dirName.startsWith(gpxDir)) {
if (dirName.length() == gpxDir.length()) {
dirName = dir.getName();
} else {
dirName = dirName.substring(gpxDir.length() + 1);
}
}
menuAdapter.addItem(itemBuilder.setTitle(Algorithms.capitalizeFirstLetter(dirName))
.setIcon(R.drawable.ic_action_folder_stroke).setTag(i).createItem());
i++;
}
menuAdapter.addItem(itemBuilder.setTitleId(R.string.add_new_folder, app)
.setIcon(R.drawable.map_zoom_in).setTag(-1).createItem());
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
final ArrayAdapter<ContextMenuItem> listAdapter =
menuAdapter.createListAdapter(getActivity(), app.getSettings().isLightContent());
builder.setTitle(R.string.select_gpx_folder);
builder.setAdapter(listAdapter, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ContextMenuItem item = menuAdapter.getItem(which);
int index = item.getTag();
if (index == -1) {
Activity a = getActivity();
AlertDialog.Builder b = new AlertDialog.Builder(a);
b.setTitle(R.string.add_new_folder);
final EditText editText = new EditText(a);
editText.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
Editable text = editText.getText();
if (text.length() >= 1) {
if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(text).find()) {
editText.setError(app.getString(R.string.file_name_containes_illegal_char));
}
}
}
});
int leftPadding = AndroidUtils.dpToPx(a, 24f);
int topPadding = AndroidUtils.dpToPx(a, 4f);
b.setView(editText, leftPadding, topPadding, leftPadding, topPadding);
// Behaviour will be overwritten later;
b.setPositiveButton(R.string.shared_string_ok, null);
b.setNegativeButton(R.string.shared_string_cancel, null);
final AlertDialog alertDialog = b.create();
alertDialog.setOnShowListener(new DialogInterface.OnShowListener() {
@Override
public void onShow(DialogInterface dialog) {
alertDialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener(
new View.OnClickListener() {
@Override
public void onClick(View v) {
String newName = editText.getText().toString();
if (ILLEGAL_PATH_NAME_CHARACTERS.matcher(newName).find()) {
Toast.makeText(app, R.string.file_name_containes_illegal_char,
Toast.LENGTH_LONG).show();
return;
}
File destFolder = new File(app.getAppPath(IndexConstants.GPX_INDEX_DIR), newName);
if (destFolder.exists()) {
Toast.makeText(app, R.string.file_with_name_already_exists,
Toast.LENGTH_LONG).show();
return;
} else if (destFolder.mkdirs()) {
File dest = new File(destFolder, info.fileName);
if (info.file.renameTo(dest)) {
app.getGpxDatabase().rename(info.file, dest);
asyncLoader = new LoadGpxTask();
asyncLoader.execute(getActivity());
} else {
Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
}
} else {
Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
}
alertDialog.dismiss();
}
});
}
});
alertDialog.show();
} else {
File dir = dirs.get(index);
File dest = new File(dir, info.file.getName());
if (dest.exists()) {
Toast.makeText(app, R.string.file_with_name_already_exists, Toast.LENGTH_LONG).show();
} else {
if (info.file.renameTo(dest)) {
app.getGpxDatabase().rename(info.file, dest);
asyncLoader = new LoadGpxTask();
asyncLoader.execute(getActivity());
} else {
Toast.makeText(app, R.string.file_can_not_be_moved, Toast.LENGTH_LONG).show();
}
}
}
}
});
builder.setNegativeButton(R.string.shared_string_cancel, null);
builder.create().show();
}
}
public class LoadGpxTask extends AsyncTask<Activity, GpxInfo, List<GpxInfo>> {
private List<GpxInfo> result;
@Override
protected List<GpxInfo> doInBackground(Activity... params) {
List<GpxInfo> result = new ArrayList<>();
loadGPXData(app.getAppPath(IndexConstants.GPX_INDEX_DIR), result, this);
return result;
}
public void loadFile(GpxInfo... loaded) {
publishProgress(loaded);
}
@Override
protected void onPreExecute() {
((OsmandActionBarActivity) getActivity()).setSupportProgressBarIndeterminateVisibility(true);
allGpxAdapter.clear();
}
@Override
protected void onProgressUpdate(GpxInfo... values) {
for (GpxInfo v : values) {
allGpxAdapter.addLocalIndexInfo(v);
}
allGpxAdapter.sort();
allGpxAdapter.notifyDataSetChanged();
}
public void setResult(List<GpxInfo> result) {
this.result = result;
allGpxAdapter.clear();
if (result != null) {
for (GpxInfo v : result) {
allGpxAdapter.addLocalIndexInfo(v);
}
allGpxAdapter.sort();
allGpxAdapter.refreshSelected();
allGpxAdapter.notifyDataSetChanged();
onPostExecute(result);
}
}
@Override
protected void onPostExecute(List<GpxInfo> result) {
this.result = result;
allGpxAdapter.refreshSelected();
if (getActivity() != null) {
((OsmandActionBarActivity) getActivity()).setSupportProgressBarIndeterminateVisibility(false);
}
if (allGpxAdapter.getGroupCount() > 0 &&
allGpxAdapter.isShowingSelection()) {
getExpandableListView().expandGroup(0);
}
}
private File[] listFilesSorted(File dir) {
File[] listFiles = dir.listFiles();
if (listFiles == null) {
return new File[0];
}
Arrays.sort(listFiles);
return listFiles;
}
private void loadGPXData(File mapPath, List<GpxInfo> result, LoadGpxTask loadTask) {
if (mapPath.canRead()) {
List<GpxInfo> progress = new ArrayList<>();
loadGPXFolder(mapPath, result, loadTask, progress, "");
if (!progress.isEmpty()) {
loadTask.loadFile(progress.toArray(new GpxInfo[progress.size()]));
}
}
}
private void loadGPXFolder(File mapPath, List<GpxInfo> result, LoadGpxTask loadTask, List<GpxInfo> progress,
String gpxSubfolder) {
for (File gpxFile : listFilesSorted(mapPath)) {
if (gpxFile.isDirectory()) {
String sub = gpxSubfolder.length() == 0 ? gpxFile.getName() : gpxSubfolder + "/"
+ gpxFile.getName();
loadGPXFolder(gpxFile, result, loadTask, progress, sub);
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(".gpx")) {
GpxInfo info = new GpxInfo();
info.subfolder = gpxSubfolder;
info.file = gpxFile;
result.add(info);
progress.add(info);
if (progress.size() > 7) {
loadTask.loadFile(progress.toArray(new GpxInfo[progress.size()]));
progress.clear();
}
}
}
}
public List<GpxInfo> getResult() {
return result;
}
}
protected class GpxIndexesAdapter extends OsmandBaseExpandableListAdapter implements Filterable {
Map<String, List<GpxInfo>> data = new LinkedHashMap<>();
List<String> category = new ArrayList<>();
List<GpxInfo> selected = new ArrayList<>();
int warningColor;
int defaultColor;
int corruptedColor;
private SearchFilter filter;
public GpxIndexesAdapter(Context ctx) {
warningColor = ContextCompat.getColor(ctx, R.color.color_warning);
TypedArray ta = ctx.getTheme().obtainStyledAttributes(new int[]{android.R.attr.textColorPrimary});
defaultColor = ta.getColor(0, ContextCompat.getColor(ctx, R.color.color_unknown));
ta.recycle();
}
public void refreshSelected() {
selected.clear();
selected.addAll(getSelectedGpx());
Collections.sort(selected, new Comparator<GpxInfo>() {
@Override
public int compare(GpxInfo i1, GpxInfo i2) {
return i1.getName().toLowerCase().compareTo(i2.getName().toLowerCase());
}
});
}
public Set<GpxInfo> getSelectedGpx() {
Set<GpxInfo> originalSelectedItems = new HashSet<>();
SelectedGpxFile track = selectedGpxHelper.getSelectedCurrentRecordingTrack();
if (track != null && track.getGpxFile() != null) {
if (track.getGpxFile().showCurrentTrack) {
originalSelectedItems.add(currentRecording);
}
}
for (List<GpxInfo> l : data.values()) {
if (l != null) {
for (GpxInfo g : l) {
SelectedGpxFile sgpx = selectedGpxHelper.getSelectedFileByName(g.getFileName());
if (sgpx != null) {
g.gpx = sgpx.getGpxFile();
originalSelectedItems.add(g);
}
}
}
}
return originalSelectedItems;
}
public void clear() {
data.clear();
category.clear();
selected.clear();
notifyDataSetChanged();
}
public void addLocalIndexInfo(GpxInfo info) {
String catName;
if (info.gpx != null && info.gpx.showCurrentTrack) {
catName = info.name;
} else {
// local_indexes_cat_gpx now obsolete in new UI screen which shows only GPX data
// catName = app.getString(R.string.local_indexes_cat_gpx) + " " + info.subfolder;
catName = "" + info.subfolder;
}
int found = -1;
// search from end
for (int i = category.size() - 1; i >= 0; i--) {
String cat = category.get(i);
if (Algorithms.objectEquals(catName, cat)) {
found = i;
break;
}
}
if (found == -1) {
found = category.size();
category.add(catName);
}
if (!data.containsKey(category.get(found))) {
data.put(category.get(found), new ArrayList<GpxInfo>());
}
data.get(category.get(found)).add(info);
}
public void sort() {
Collections.sort(category, new Comparator<String>() {
@Override
public int compare(String lhs, String rhs) {
return lhs.toLowerCase().compareTo(rhs.toLowerCase());
}
});
}
@Override
public GpxInfo getChild(int groupPosition, int childPosition) {
if (isSelectedGroup(groupPosition)) {
return selected.get(childPosition);
}
String cat = category.get(getGroupPosition(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(final int groupPosition, final int childPosition, boolean isLastChild,
View convertView, ViewGroup parent) {
View v = convertView;
final GpxInfo child = getChild(groupPosition, childPosition);
if (v == null) {
LayoutInflater inflater = getActivity().getLayoutInflater();
v = inflater.inflate(R.layout.dash_gpx_track_item, parent, false);
}
udpateGpxInfoView(v, child, app, false);
ImageView icon = (ImageView) v.findViewById(R.id.icon);
ImageButton options = (ImageButton) v.findViewById(R.id.options);
options.setImageDrawable(getMyApplication().getIconsCache().getThemedIcon(R.drawable.ic_overflow_menu_white));
options.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
openPopUpMenu(v, child);
}
});
final CheckBox checkbox = (CheckBox) v.findViewById(R.id.check_local_index);
checkbox.setVisibility(selectionMode ? View.VISIBLE : View.GONE);
if (selectionMode) {
checkbox.setChecked(selectedItems.contains(child));
checkbox.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (checkbox.isChecked()) {
selectedItems.add(child);
} else {
selectedItems.remove(child);
}
updateSelectionMode(actionMode);
}
});
icon.setVisibility(View.GONE);
options.setVisibility(View.GONE);
} else {
icon.setVisibility(View.VISIBLE);
options.setVisibility(View.VISIBLE);
}
final CompoundButton checkItem = (CompoundButton) v.findViewById(R.id.toggle_item);
if (isSelectedGroup(groupPosition)) {
v.findViewById(R.id.check_item).setVisibility(View.VISIBLE);
v.findViewById(R.id.options).setVisibility(View.GONE);
} else {
v.findViewById(R.id.check_item).setVisibility(View.GONE);
}
final boolean isChecked;
if (child.currentlyRecordingTrack) {
isChecked = selectedGpxHelper.getSelectedCurrentRecordingTrack() != null;
} else {
final SelectedGpxFile selectedGpxFile = selectedGpxHelper.getSelectedFileByName(child.getFileName());
isChecked = selectedGpxFile != null;
}
checkItem.setChecked(isChecked);
checkItem.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
selectedGpxHelper.selectGpxFile(child.gpx, !isChecked, false);
notifyDataSetChanged();
}
});
v.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onChildClick(null, v, groupPosition, childPosition, 0);
}
});
return v;
}
@Override
public View getGroupView(final int groupPosition, boolean isExpanded, View convertView, ViewGroup parent) {
View v = convertView;
String group = getGroup(groupPosition);
if (v == null) {
LayoutInflater inflater = getActivity().getLayoutInflater();
v = inflater.inflate(net.osmand.plus.R.layout.expandable_list_item_category, parent, false);
}
v.findViewById(R.id.group_divider).setVisibility(groupPosition == 0 ? View.GONE : View.VISIBLE);
StringBuilder t = new StringBuilder();
String groupName = group.replaceAll("_", " ").replace(".gpx", "");
if (groupName.length() == 0) {
groupName = getString(R.string.shared_string_tracks);
}
t.append(Algorithms.capitalizeFirstLetter(groupName));
boolean light = app.getSettings().isLightContent();
if (selectionMode) {
final CheckBox ch = (CheckBox) v.findViewById(R.id.toggle_item);
ch.setVisibility(View.VISIBLE);
ch.setChecked(selectedGroups.contains(groupPosition));
ch.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (ch.isChecked()) {
selectedItems.addAll(data.get(category.get(getGroupPosition(groupPosition))));
selectedGroups.add(groupPosition);
} else {
selectedItems.removeAll(data.get(category.get(getGroupPosition(groupPosition))));
selectedGroups.remove(groupPosition);
}
allGpxAdapter.notifyDataSetInvalidated();
updateSelectionMode(actionMode);
}
});
v.findViewById(R.id.category_icon).setVisibility(View.GONE);
} else {
final CheckBox ch = (CheckBox) v.findViewById(R.id.toggle_item);
ch.setVisibility(View.GONE);
if (isSelectedGroup(groupPosition)) {
setCategoryIcon(app, app.getIconsCache().getIcon(R.drawable.ic_map, R.color.osmand_orange), groupPosition, isExpanded, v, light);
} else {
setCategoryIcon(app, 0, groupPosition, isExpanded, v, light);
}
v.findViewById(R.id.category_icon).setVisibility(View.VISIBLE);
}
adjustIndicator(app, groupPosition, isExpanded, v, light);
TextView nameView = ((TextView) v.findViewById(R.id.category_name));
nameView.setText(t.toString());
return v;
}
@Override
public int getChildrenCount(int groupPosition) {
if (isSelectedGroup(groupPosition)) {
return selected.size();
}
return data.get(category.get(getGroupPosition(groupPosition))).size();
}
private int getGroupPosition(int groupPosition) {
return isShowingSelection() ? groupPosition - 1 : groupPosition;
}
private boolean isSelectedGroup(int groupPosition) {
return isShowingSelection() && groupPosition == 0;
}
public boolean isShowingSelection() {
return selected.size() > 0 && !selectionMode;
}
@Override
public String getGroup(int groupPosition) {
if (isSelectedGroup(groupPosition)) {
return app.getString(R.string.shared_string_visible);
}
return category.get(getGroupPosition(groupPosition));
}
@Override
public int getGroupCount() {
if (isShowingSelection()) {
return category.size() + 1;
}
return category.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;
}
@Override
public Filter getFilter() {
if (filter == null) {
filter = new SearchFilter();
}
return filter;
}
public void delete(GpxInfo g) {
int found = -1;
// search from end
for (int i = category.size() - 1; i >= 0; i--) {
String cat = category.get(i);
// local_indexes_cat_gpx now obsolete in new UI screen which shows only GPX data
// if (Algorithms.objectEquals(getActivity().getString(R.string.local_indexes_cat_gpx) + " " +
// g.subfolder, cat)) {
if (Algorithms.objectEquals("" + g.subfolder, cat)) {
found = i;
break;
}
}
if (found != -1) {
data.get(category.get(found)).remove(g);
}
}
}
private void openPopUpMenu(View v, final GpxInfo gpxInfo) {
IconsCache iconsCache = getMyApplication().getIconsCache();
final PopupMenu optionsMenu = new PopupMenu(getActivity(), v);
DirectionsDialogs.setupPopUpMenuIcon(optionsMenu);
MenuItem item = optionsMenu.getMenu().add(R.string.shared_string_show_on_map).setIcon(iconsCache.getThemedIcon(R.drawable.ic_show_on_map));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
showGpxOnMap(gpxInfo);
return true;
}
});
item = optionsMenu.getMenu().add(R.string.shared_string_move).setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_folder_stroke));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
moveGpx(gpxInfo);
return true;
}
});
item = optionsMenu.getMenu().add(R.string.shared_string_rename)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_edit_dark));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
LocalIndexesFragment.renameFile(getActivity(), gpxInfo.file, new RenameCallback() {
@Override
public void renamedTo(File file) {
app.getGpxDatabase().rename(gpxInfo.file, file);
asyncLoader = new LoadGpxTask();
asyncLoader.execute(getActivity());
}
});
return true;
}
});
item = optionsMenu.getMenu().add(R.string.shared_string_share)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_gshare_dark));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
final Uri fileUri = Uri.fromFile(gpxInfo.file);
final Intent sendIntent = new Intent(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_STREAM, fileUri);
sendIntent.setType("application/gpx+xml");
startActivity(sendIntent);
return true;
}
});
final OsmEditingPlugin osmEditingPlugin = OsmandPlugin.getEnabledPlugin(OsmEditingPlugin.class);
if (osmEditingPlugin != null && osmEditingPlugin.isActive()) {
item = optionsMenu.getMenu().add(R.string.shared_string_export).setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_export));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
osmEditingPlugin.sendGPXFiles(getActivity(), AvailableGPXFragment.this, gpxInfo);
return true;
}
});
}
item = optionsMenu.getMenu().add(R.string.shared_string_delete)
.setIcon(iconsCache.getThemedIcon(R.drawable.ic_action_delete_dark));
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem item) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage(R.string.recording_delete_confirm);
builder.setPositiveButton(R.string.shared_string_yes, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
operationTask = new DeleteGpxTask();
operationTask.execute(gpxInfo);
}
});
builder.setNegativeButton(R.string.shared_string_cancel, null);
builder.show();
return true;
}
});
optionsMenu.show();
}
public class DeleteGpxTask extends AsyncTask<GpxInfo, GpxInfo, String> {
@Override
protected String doInBackground(GpxInfo... params) {
int count = 0;
int total = 0;
for (GpxInfo info : params) {
if (!isCancelled() && (info.gpx == null || !info.gpx.showCurrentTrack)) {
boolean successfull;
successfull = Algorithms.removeAllFiles(info.file);
app.getGpxDatabase().remove(info.file);
total++;
if (successfull) {
count++;
publishProgress(info);
}
}
}
return app.getString(R.string.local_index_items_deleted, count, total);
}
@Override
protected void onProgressUpdate(GpxInfo... values) {
for (GpxInfo g : values) {
allGpxAdapter.delete(g);
}
allGpxAdapter.notifyDataSetChanged();
}
@Override
protected void onPreExecute() {
getActivity().setProgressBarIndeterminateVisibility(true);
}
@Override
protected void onPostExecute(String result) {
getActivity().setProgressBarIndeterminateVisibility(false);
Toast.makeText(getActivity(), result, Toast.LENGTH_LONG).show();
}
}
public class SelectGpxTask extends AsyncTask<GpxInfo, GpxInfo, String> {
private boolean showOnMap;
private WptPt toShow;
public SelectGpxTask(boolean showOnMap) {
this.showOnMap = showOnMap;
}
@Override
protected String doInBackground(GpxInfo... params) {
for (GpxInfo info : params) {
if (!isCancelled()) {
if (!info.currentlyRecordingTrack) {
info.setGpx(GPXUtilities.loadGPXFile(app, info.file));
}
publishProgress(info);
}
}
return "";
}
@Override
protected void onProgressUpdate(GpxInfo... values) {
for (GpxInfo g : values) {
final boolean visible = selectedItems.contains(g);
selectedGpxHelper.selectGpxFile(g.gpx, visible, false);
if (visible && toShow == null) {
toShow = g.gpx.findPointToShow();
}
}
allGpxAdapter.notifyDataSetInvalidated();
}
@Override
protected void onPreExecute() {
getActivity().setProgressBarIndeterminateVisibility(true);
}
@Override
protected void onPostExecute(String result) {
getActivity().setProgressBarIndeterminateVisibility(false);
allGpxAdapter.refreshSelected();
allGpxAdapter.notifyDataSetChanged();
if (showOnMap && toShow != null) {
getMyApplication().getSettings().setMapLocationToShow(toShow.lat, toShow.lon,
getMyApplication().getSettings().getLastKnownMapZoom());
MapActivity.launchMapActivityMoveToTop(getActivity());
}
}
}
public class ProcessGpxTask extends AsyncTask<Void, GpxDataItem, Void> {
private List<File> processedDataFiles = new ArrayList<>();
ProcessGpxTask() {
List<GpxDataItem> dataItems = app.getGpxDatabase().getItems();
for (GpxDataItem item : dataItems) {
processedDataFiles.add(item.getFile());
}
}
@Override
protected Void doInBackground(Void... params) {
File gpxPath = app.getAppPath(IndexConstants.GPX_INDEX_DIR);
if (gpxPath.canRead()) {
processGPXFolder(gpxPath, "");
}
return null;
}
private File[] listFilesSorted(File dir) {
File[] listFiles = dir.listFiles();
if (listFiles == null) {
return new File[0];
}
Arrays.sort(listFiles);
return listFiles;
}
private void processGPXFolder(File gpxPath, String gpxSubfolder) {
for (File gpxFile : listFilesSorted(gpxPath)) {
if (gpxFile.isDirectory()) {
String sub = gpxSubfolder.length() == 0 ?
gpxFile.getName() : gpxSubfolder + "/" + gpxFile.getName();
processGPXFolder(gpxFile, sub);
} else if (gpxFile.isFile() && gpxFile.getName().toLowerCase().endsWith(".gpx") && !processedDataFiles.contains(gpxFile)) {
GPXFile f = GPXUtilities.loadGPXFile(app, gpxFile);
GPXTrackAnalysis analysis = f.getAnalysis(gpxFile.lastModified());
GpxDataItem newItem = new GpxDataItem(gpxFile, analysis);
app.getGpxDatabase().add(newItem);
if (isCancelled()) {
break;
}
processedDataFiles.add(gpxFile);
publishProgress(newItem);
}
}
}
@Override
protected void onProgressUpdate(GpxDataItem... items) {
allGpxAdapter.notifyDataSetChanged();
}
@Override
protected void onPostExecute(Void aVoid) {
asyncProcessor = null;
}
}
private class SearchFilter extends Filter {
@Override
protected FilterResults performFiltering(CharSequence constraint) {
FilterResults results = new FilterResults();
final List<GpxInfo> raw = asyncLoader.getResult();
if (constraint == null || constraint.length() == 0 || raw == null) {
results.values = raw;
results.count = 1;
} else {
String cs = constraint.toString();
List<GpxInfo> res = new ArrayList<>();
for (GpxInfo r : raw) {
if (r.getName().toLowerCase().contains(cs)) {
res.add(r);
}
}
results.values = res;
results.count = res.size();
}
return results;
}
@SuppressWarnings("unchecked")
@Override
protected void publishResults(CharSequence constraint, FilterResults results) {
if (results.values != null) {
synchronized (allGpxAdapter) {
allGpxAdapter.clear();
for (GpxInfo i : ((List<GpxInfo>) results.values)) {
allGpxAdapter.addLocalIndexInfo(i);
}
allGpxAdapter.sort();
allGpxAdapter.refreshSelected();
}
allGpxAdapter.notifyDataSetChanged();
if (constraint != null && constraint.length() > 3) {
collapseTrees(10);
}
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (asyncLoader != null) {
asyncLoader.cancel(true);
}
}
@Override
public boolean onChildClick(ExpandableListView parent, View v, int groupPosition, int childPosition, long id) {
GpxInfo item = allGpxAdapter.getChild(groupPosition, childPosition);
if (!selectionMode) {
Intent newIntent = new Intent(getActivity(), getMyApplication().getAppCustomization().getTrackActivity());
// causes wrong position caching: newIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
if (item.currentlyRecordingTrack) {
newIntent.putExtra(TrackActivity.CURRENT_RECORDING, true);
} else {
newIntent.putExtra(TrackActivity.TRACK_FILE_NAME, item.file.getAbsolutePath());
}
newIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(newIntent);
// item.setExpanded(!item.isExpanded());
// if (item.isExpanded()) {
// descriptionLoader = new LoadLocalIndexDescriptionTask();
// descriptionLoader.execute(item);
// }
} else {
if (!selectedItems.contains(item)) {
selectedItems.add(item);
} else {
selectedItems.remove(item);
}
updateSelectionMode(actionMode);
}
allGpxAdapter.notifyDataSetInvalidated();
return true;
}
public static class GpxInfo {
public boolean currentlyRecordingTrack;
public GPXFile gpx;
public File file;
public String subfolder;
private String name = null;
private int sz = -1;
private String fileName = null;
private boolean corrupted;
public GpxInfo() {
}
public GpxInfo(GPXFile file, String name) {
this.gpx = file;
this.name = name;
}
public String getName() {
if (name == null) {
name = formatName(file.getName());
}
return name;
}
private String formatName(String name) {
int ext = name.lastIndexOf('.');
if (ext != -1) {
name = name.substring(0, ext);
}
return name.replace('_', ' ');
}
public boolean isCorrupted() {
return corrupted;
}
public int getSize() {
if (sz == -1) {
if (file == null) {
return -1;
}
sz = (int) ((file.length() + 512) >> 10);
}
return sz;
}
public long getFileDate() {
if (file == null) {
return 0;
}
return file.lastModified();
}
public void setGpx(GPXFile gpx) {
this.gpx = gpx;
}
public String getFileName() {
if (fileName != null) {
return fileName;
}
if (file == null) {
return "";
}
return fileName = file.getName();
}
}
public static void udpateGpxInfoView(View v, GpxInfo child, OsmandApplication app, boolean isDashItem) {
TextView viewName = ((TextView) v.findViewById(R.id.name));
if (!isDashItem) {
v.findViewById(R.id.divider_list).setVisibility(View.VISIBLE);
v.findViewById(R.id.divider_dash).setVisibility(View.GONE);
} else {
v.findViewById(R.id.divider_dash).setVisibility(View.VISIBLE);
v.findViewById(R.id.divider_list).setVisibility(View.GONE);
}
viewName.setText(child.getName());
GpxSelectionHelper selectedGpxHelper = app.getSelectedGpxHelper();
// ImageView icon = (ImageView) v.findViewById(!isDashItem? R.id.icon : R.id.show_on_map);
ImageView icon = (ImageView) v.findViewById(R.id.icon);
icon.setVisibility(View.VISIBLE);
icon.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_action_polygom_dark));
if (child.isCorrupted()) {
viewName.setTypeface(Typeface.DEFAULT, Typeface.ITALIC);
} else {
viewName.setTypeface(Typeface.DEFAULT, Typeface.NORMAL);
}
SelectedGpxFile sgpx = child.currentlyRecordingTrack ? selectedGpxHelper.getSelectedCurrentRecordingTrack() :
selectedGpxHelper.getSelectedFileByName(child.getFileName());
GPXTrackAnalysis analysis = null;
if (sgpx != null) {
icon.setImageDrawable(app.getIconsCache().getIcon(R.drawable.ic_action_polygom_dark, R.color.color_distance));
analysis = sgpx.getTrackAnalysis();
} else if (child.currentlyRecordingTrack) {
analysis = app.getSavingTrackHelper().getCurrentTrack().getTrackAnalysis();
} else {
GpxDataItem dataItem = child.file == null ? null : app.getGpxDatabase().getItem(child.file);
if (dataItem != null) {
analysis = dataItem.getAnalysis();
}
}
boolean sectionRead = analysis == null;
if (sectionRead) {
v.findViewById(R.id.read_section).setVisibility(View.GONE);
v.findViewById(R.id.unknown_section).setVisibility(View.VISIBLE);
String date = "";
String size = "";
if (child.getSize() >= 0) {
if (child.getSize() > 100) {
size = formatMb.format(new Object[]{(float) child.getSize() / (1 << 10)});
} else {
size = child.getSize() + " kB";
}
}
DateFormat df = app.getResourceManager().getDateFormat();
long fd = child.getFileDate();
if (fd > 0) {
date = (df.format(new Date(fd)));
}
TextView sizeText = (TextView) v.findViewById(R.id.date_and_size_details);
sizeText.setText(date + " \u2022 " + size);
} else {
v.findViewById(R.id.read_section).setVisibility(View.VISIBLE);
v.findViewById(R.id.unknown_section).setVisibility(View.GONE);
ImageView distanceI = (ImageView) v.findViewById(R.id.distance_icon);
distanceI.setVisibility(View.VISIBLE);
distanceI.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_small_distance));
ImageView pointsI = (ImageView) v.findViewById(R.id.points_icon);
pointsI.setVisibility(View.VISIBLE);
pointsI.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_small_point));
ImageView timeI = (ImageView) v.findViewById(R.id.time_icon);
timeI.setVisibility(View.VISIBLE);
timeI.setImageDrawable(app.getIconsCache().getThemedIcon(R.drawable.ic_small_time));
TextView time = (TextView) v.findViewById(R.id.time);
TextView distance = (TextView) v.findViewById(R.id.distance);
TextView pointsCount = (TextView) v.findViewById(R.id.points_count);
pointsCount.setText(analysis.wptPoints + "");
// if (analysis.totalDistanceMoving != 0) {
// distance.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistanceMoving, app));
// } else {
distance.setText(OsmAndFormatter.getFormattedDistance(analysis.totalDistance, app));
// }
if (analysis.isTimeSpecified()) {
// if (analysis.isTimeMoving()) {
// time.setText(Algorithms.formatDuration((int) (analysis.timeMoving / 1000)) + "");
// } else {
time.setText(Algorithms.formatDuration((int) (analysis.timeSpan / 1000), app.accessibilityEnabled()) + "");
// }
} else {
time.setText("");
}
}
TextView descr = ((TextView) v.findViewById(R.id.description));
descr.setVisibility(View.GONE);
v.findViewById(R.id.check_item).setVisibility(View.GONE);
}
}