diff options
Diffstat (limited to 'main')
68 files changed, 767 insertions, 481 deletions
diff --git a/main/lint.xml b/main/lint.xml index c3e66b2..a420bfa 100644 --- a/main/lint.xml +++ b/main/lint.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <lint> <issue id="ContentDescription" severity="ignore" /> + <issue id="DuplicateIds" severity="error" /> + <issue id="DuplicateIncludedIds" severity="error" /> <issue id="ExportedContentProvider" severity="ignore" /> <issue id="InvalidPackage" severity="ignore" /> <issue id="MissingTranslation" severity="ignore" /> diff --git a/main/project/findbugs/exclusions.xml b/main/project/findbugs/exclusions.xml index e7dc744..c48983e 100644 --- a/main/project/findbugs/exclusions.xml +++ b/main/project/findbugs/exclusions.xml @@ -17,7 +17,10 @@ <!-- irrelevant findings --> <Match> - <Bug pattern="SE_COMPARATOR_SHOULD_BE_SERIALIZABLE" /> + <Or> + <Bug pattern="ST_WRITE_TO_STATIC_FROM_INSTANCE_METHOD"/> + <Bug pattern="SE_COMPARATOR_SHOULD_BE_SERIALIZABLE" /> + </Or> </Match> <Match> <Bug pattern="DM_STRING_CTOR" /> @@ -26,5 +29,9 @@ <Class name="~.*TextUtils"></Class> </Or> </Match> + <Match> + <Bug pattern="DMI_HARDCODED_ABSOLUTE_FILENAME"/> + <Class name="~.*LocalStorage"/> + </Match> </FindBugsFilter>
\ No newline at end of file diff --git a/main/res/drawable-hdpi/ic_menu_globe.png b/main/res/drawable-hdpi/ic_menu_globe.png Binary files differdeleted file mode 100644 index 1c870fe..0000000 --- a/main/res/drawable-hdpi/ic_menu_globe.png +++ /dev/null diff --git a/main/res/drawable-ldpi/ic_menu_globe.png b/main/res/drawable-ldpi/ic_menu_globe.png Binary files differdeleted file mode 100644 index b096a9e..0000000 --- a/main/res/drawable-ldpi/ic_menu_globe.png +++ /dev/null diff --git a/main/res/drawable-mdpi/ic_menu_globe.png b/main/res/drawable-mdpi/ic_menu_globe.png Binary files differdeleted file mode 100644 index cd283ab..0000000 --- a/main/res/drawable-mdpi/ic_menu_globe.png +++ /dev/null diff --git a/main/res/menu/cache_list_context.xml b/main/res/menu/cache_list_context.xml new file mode 100644 index 0000000..2767a2e --- /dev/null +++ b/main/res/menu/cache_list_context.xml @@ -0,0 +1,49 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/menu_default_navigation" + android:icon="@drawable/ic_menu_compass" + android:title="@string/cache_menu_navigate"> <!-- will be replaced --> + </item> + <item + android:id="@+id/menu_navigate" + android:icon="@drawable/ic_menu_mapmode" + android:title="@string/cache_menu_navigate"> + </item> + <item + android:id="@+id/menu_cache_details" + android:title="@string/cache_menu_details"> + </item> + <item + android:id="@+id/menu_log_visit_offline" + android:icon="@drawable/ic_menu_edit" + android:title="@string/cache_menu_visit_offline"> + </item> + <item + android:id="@+id/menu_log_visit" + android:icon="@drawable/ic_menu_edit" + android:title="@string/cache_menu_visit"> + </item> + <item + android:id="@+id/menu_drop_cache" + android:title="@string/cache_offline_drop"> + </item> + <item + android:id="@+id/menu_move_to_list" + android:title="@string/cache_menu_move_list"> + </item> + <item + android:id="@+id/menu_export" + android:title="@string/export"> + </item> + <item + android:id="@+id/menu_refresh" + android:title="@string/cache_menu_refresh"> + </item> + <item + android:id="@+id/menu_store_cache" + android:title="@string/cache_offline_store"> + </item> + +</menu>
\ No newline at end of file diff --git a/main/res/menu/cache_list_options.xml b/main/res/menu/cache_list_options.xml new file mode 100644 index 0000000..6618f3e --- /dev/null +++ b/main/res/menu/cache_list_options.xml @@ -0,0 +1,114 @@ +<?xml version="1.0" encoding="utf-8"?> +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <item + android:id="@+id/menu_filter" + android:icon="@drawable/ic_menu_filter" + android:title="@string/caches_filter"> + </item> + <item + android:id="@+id/menu_sort" + android:icon="@drawable/ic_menu_sort_alphabetically" + android:title="@string/caches_sort"> + </item> + <item + android:id="@+id/menu_switch_select_mode" + android:icon="@drawable/ic_menu_agenda" + android:title="@string/caches_select_mode"> + </item> + <item + android:id="@+id/menu_invert_selection" + android:icon="@drawable/ic_menu_mark" + android:title="@string/caches_select_invert"> + </item> + <item + android:id="@+id/submenu_manage" + android:icon="@drawable/ic_menu_save" + android:title="@string/caches_manage"> + <menu> + <item + android:id="@+id/menu_drop_caches" + android:title="@string/caches_drop_all"> + </item> + <item + android:id="@+id/menu_drop_caches_and_list" + android:title="@string/caches_drop_all_and_list"> + </item> + <item + android:id="@+id/menu_refresh_stored" + android:title="@string/cache_offline_refresh"> + </item> + <item + android:id="@+id/menu_move_to_list" + android:title="@string/cache_menu_move_list"> + </item> + <item + android:id="@+id/menu_delete_events" + android:title="@string/caches_delete_events"> + </item> + <item + android:id="@+id/menu_clear_offline_logs" + android:title="@string/caches_clear_offlinelogs"> + </item> + <item + android:id="@+id/menu_import_gpx" + android:title="@string/gpx_import_title"> + </item> + <item + android:id="@+id/menu_import_web" + android:title="@string/web_import_title"> + </item> + <item + android:id="@+id/menu_export" + android:title="@string/export"> + </item> + <item + android:id="@+id/menu_remove_from_history" + android:title="@string/cache_clear_history"> + </item> + </menu> + </item> + <item + android:id="@+id/menu_refresh_stored_top" + android:icon="@drawable/ic_menu_set_as" + android:title="@string/cache_offline_refresh"> + </item> + <item + android:id="@+id/menu_cache_list_app" + android:icon="@drawable/ic_menu_mapmode" + android:title="@null" + android:visible="false"> + </item> + <item + android:id="@+id/submenu_cache_list_app" + android:icon="@drawable/ic_menu_mapmode" + android:title="@string/caches_on_map" + android:visible="false"> + <menu > + </menu> + </item> + <item + android:id="@+id/submenu_manage_lists" + android:icon="@drawable/ic_menu_more" + android:title="@string/list_menu"> + <menu> + <item + android:id="@+id/menu_create_list" + android:title="@string/list_menu_create"> + </item> + <item + android:id="@+id/menu_drop_list" + android:title="@string/list_menu_drop"> + </item> + <item + android:id="@+id/menu_rename_list" + android:title="@string/list_menu_rename"> + </item> + <item + android:id="@+id/menu_switch_list" + android:title="@string/list_menu_change"> + </item> + </menu> + </item> + +</menu>
\ No newline at end of file diff --git a/main/res/menu/abstract_popup_activity.xml b/main/res/menu/cache_options.xml index 855a756..d2951f4 100644 --- a/main/res/menu/abstract_popup_activity.xml +++ b/main/res/menu/cache_options.xml @@ -12,6 +12,11 @@ android:title="@string/cache_menu_navigate"> </item> <item + android:id="@+id/menu_calendar" + android:icon="@drawable/ic_menu_agenda" + android:title="@string/cache_menu_event"> + </item> + <item android:id="@+id/menu_log_visit_offline" android:icon="@drawable/ic_menu_edit" android:title="@string/cache_menu_visit_offline"> @@ -31,5 +36,10 @@ android:icon="@drawable/ic_menu_info_details" android:title="@string/cache_menu_browser"> </item> - + <item + android:id="@+id/menu_share" + android:icon="@drawable/ic_menu_share" + android:title="@string/cache_menu_share"> + </item> + </menu>
\ No newline at end of file diff --git a/main/res/values/ids.xml b/main/res/values/ids.xml new file mode 100644 index 0000000..4e02973 --- /dev/null +++ b/main/res/values/ids.xml @@ -0,0 +1,27 @@ +<?xml version="1.0" encoding="utf-8"?> +<resources> + + <item name="cache_list_app_map" type="id"/> + <item name="cache_list_app_locus_show" type="id"/> + <item name="cache_list_app_locus_export" type="id"/> + <item name="cache_app_sygic" type="id"/> + <item name="cache_app_compass" type="id"/> + <item name="cache_app_cache_beacon" type="id"/> + <item name="cache_app_google_maps_direction" type="id"/> + <item name="cache_app_google_maps" type="id"/> + <item name="cache_app_whereyougo" type="id"/> + <item name="cache_app_gcc" type="id"/> + <item name="cache_app_radar" type="id"/> + <item name="cache_app_internal_map" type="id"/> + <item name="cache_app_navigon" type="id"/> + <item name="cache_app_orux_maps" type="id"/> + <item name="cache_app_street_view" type="id"/> + <item name="cache_app_rmaps" type="id"/> + <item name="cache_app_google_navigation_walk" type="id"/> + <item name="cache_app_google_navigation_drive" type="id"/> + <item name="cache_app_google_navigation_bike" type="id"/> + <item name="cache_app_download_static_maps" type="id"/> + <item name="cache_app_show_static_maps" type="id"/> + <item name="cache_app_locus" type="id"/> + +</resources>
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/AbstractPopupActivity.java b/main/src/cgeo/geocaching/AbstractPopupActivity.java index 02f89a6..5b9b509 100644 --- a/main/src/cgeo/geocaching/AbstractPopupActivity.java +++ b/main/src/cgeo/geocaching/AbstractPopupActivity.java @@ -2,7 +2,6 @@ package cgeo.geocaching; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; -import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.gcvote.GCVote; @@ -17,9 +16,7 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; -import android.content.Intent; import android.graphics.Rect; -import android.net.Uri; import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; @@ -31,7 +28,7 @@ import android.widget.Button; import android.widget.ImageView; import android.widget.TextView; -public abstract class AbstractPopupActivity extends AbstractActivity { +public abstract class AbstractPopupActivity extends AbstractActivity implements CacheMenuHandler.ActivityInterface { protected Geocache cache = null; protected String geocode = null; @@ -110,11 +107,8 @@ public abstract class AbstractPopupActivity extends AbstractActivity { geocode = cache.getGeocode(); } - private void showInBrowser() { - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(cache.getUrl()))); - } - - protected abstract void navigateTo(); + @Override + public abstract void navigateTo(); @Override public void onCreate(Bundle savedInstanceState) { @@ -150,31 +144,17 @@ public abstract class AbstractPopupActivity extends AbstractActivity { @Override public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.abstract_popup_activity, menu); + CacheMenuHandler.addMenuItems(this, menu, cache); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { - final int menuItem = item.getItemId(); - - switch (menuItem) { - case R.id.menu_default_navigation: - navigateTo(); - return true; - case R.id.menu_navigate: - showNavigationMenu(); - return true; - case R.id.menu_caches_around: - cachesAround(); - return true; - case R.id.menu_show_in_browser: - showInBrowser(); - return true; - default: - if (LoggingUI.onMenuItemSelected(item, this, cache)) { - return true; - } + if (CacheMenuHandler.onMenuItemSelected(item, this, cache)) { + return true; + } + if (LoggingUI.onMenuItemSelected(item, this, cache)) { + return true; } return true; @@ -191,12 +171,7 @@ public abstract class AbstractPopupActivity extends AbstractActivity { super.onPrepareOptionsMenu(menu); try { - final boolean visible = getCoordinates() != null; - menu.findItem(R.id.menu_default_navigation).setVisible(visible); - menu.findItem(R.id.menu_navigate).setVisible(visible); - menu.findItem(R.id.menu_caches_around).setVisible(visible); - - menu.findItem(R.id.menu_default_navigation).setTitle(NavigationAppFactory.getDefaultNavigationApplication().getName()); + CacheMenuHandler.onPrepareOptionsMenu(menu, cache); LoggingUI.onPrepareOptionsMenu(menu, cache); } catch (final RuntimeException e) { // nothing @@ -227,7 +202,8 @@ public abstract class AbstractPopupActivity extends AbstractActivity { return super.onTouchEvent(event); } - protected abstract void showNavigationMenu(); + @Override + public abstract void showNavigationMenu(); protected abstract void startDefaultNavigation2(); @@ -270,7 +246,8 @@ public abstract class AbstractPopupActivity extends AbstractActivity { }); } - private void cachesAround() { + @Override + public void cachesAround() { final Geopoint coords = getCoordinates(); if (coords == null) { showToast(res.getString(R.string.err_location_unknown)); diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index f9aae24..dc98a79 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -3,7 +3,6 @@ package cgeo.geocaching; import butterknife.InjectView; import butterknife.Views; -import cgeo.calendar.ICalendar; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.AbstractViewPagerActivity; import cgeo.geocaching.activity.Progress; @@ -16,12 +15,10 @@ import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.WaypointType; -import cgeo.geocaching.geopoint.GeopointFormatter; import cgeo.geocaching.geopoint.Units; import cgeo.geocaching.list.StoredList; import cgeo.geocaching.network.HtmlImage; import cgeo.geocaching.network.Network; -import cgeo.geocaching.network.Parameters; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.ui.AbstractCachingPageViewCreator; import cgeo.geocaching.ui.AnchorAwareLinkMovementMethod; @@ -65,8 +62,6 @@ import android.app.ProgressDialog; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; -import android.content.pm.PackageManager; -import android.content.pm.ResolveInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Typeface; @@ -90,7 +85,6 @@ import android.util.TypedValue; import android.view.ContextMenu; import android.view.Menu; import android.view.MenuItem; -import android.view.SubMenu; import android.view.View; import android.view.View.OnClickListener; import android.view.View.OnLongClickListener; @@ -122,13 +116,7 @@ import java.util.regex.Pattern; * * e.g. details, description, logs, waypoints, inventory... */ -public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> { - - private static final int MENU_SHARE = 12; - private static final int MENU_CALENDAR = 11; - private static final int MENU_CACHES_AROUND = 10; - private static final int MENU_BROWSER = 7; - private static final int MENU_DEFAULT_NAVIGATION = 13; +public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailActivity.Page> implements CacheMenuHandler.ActivityInterface { private static final int MESSAGE_FAILED = -1; private static final int MESSAGE_SUCCEEDED = 1; @@ -354,15 +342,18 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc final int viewId = view.getId(); switch (viewId) { case R.id.value: // coordinates, gc-code, name + assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); final String itemTitle = (String) ((TextView) ((View) view.getParent()).findViewById(R.id.name)).getText(); buildDetailsContextMenu(menu, itemTitle, true); break; case R.id.shortdesc: + assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); buildDetailsContextMenu(menu, res.getString(R.string.cache_description), false); break; case R.id.longdesc: + assert view instanceof TextView; // combine short and long description final String shortDesc = cache.getShortDescription(); if (StringUtils.isBlank(shortDesc)) { @@ -373,14 +364,17 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc buildDetailsContextMenu(menu, res.getString(R.string.cache_description), false); break; case R.id.personalnote: + assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); buildDetailsContextMenu(menu, res.getString(R.string.cache_personal_note), true); break; case R.id.hint: + assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); buildDetailsContextMenu(menu, res.getString(R.string.cache_hint), false); break; case R.id.log: + assert view instanceof TextView; clickedItemText = ((TextView) view).getText(); buildDetailsContextMenu(menu, res.getString(R.string.cache_logs), false); break; @@ -513,59 +507,29 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public boolean onCreateOptionsMenu(Menu menu) { - if (null != cache) { - menu.add(0, MENU_DEFAULT_NAVIGATION, 0, NavigationAppFactory.getDefaultNavigationApplication().getName()).setIcon(R.drawable.ic_menu_compass); // default navigation tool - - final SubMenu subMenu = menu.addSubMenu(0, 0, 0, res.getString(R.string.cache_menu_navigate)).setIcon(R.drawable.ic_menu_mapmode); - NavigationAppFactory.addMenuItems(subMenu, cache); - - menu.add(0, MENU_CALENDAR, 0, res.getString(R.string.cache_menu_event)).setIcon(R.drawable.ic_menu_agenda); // add event to calendar - LoggingUI.addMenuItems(this, menu, cache); - menu.add(0, MENU_CACHES_AROUND, 0, res.getString(R.string.cache_menu_around)).setIcon(R.drawable.ic_menu_rotate); // caches around - menu.add(0, MENU_BROWSER, 0, res.getString(R.string.cache_menu_browser)).setIcon(R.drawable.ic_menu_globe); // browser - menu.add(0, MENU_SHARE, 0, res.getString(R.string.cache_menu_share)).setIcon(R.drawable.ic_menu_share); // share cache - } + CacheMenuHandler.addMenuItems(this, menu, cache); return true; } @Override public boolean onPrepareOptionsMenu(Menu menu) { - if (cache != null) { - menu.findItem(MENU_DEFAULT_NAVIGATION).setVisible(null != cache.getCoords()); - menu.findItem(MENU_CALENDAR).setVisible(cache.canBeAddedToCalendar()); - menu.findItem(MENU_CACHES_AROUND).setVisible(null != cache.getCoords() && cache.supportsCachesAround()); - menu.findItem(MENU_BROWSER).setVisible(cache.canOpenInBrowser()); - LoggingUI.onPrepareOptionsMenu(menu, cache); - } + CacheMenuHandler.onPrepareOptionsMenu(menu, cache); + LoggingUI.onPrepareOptionsMenu(menu, cache); return super.onPrepareOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { + if (CacheMenuHandler.onMenuItemSelected(item, this, cache)) { + return true; + } + final int menuItem = item.getItemId(); switch (menuItem) { case 0: // no menu selected, but a new sub menu shown return false; - case MENU_DEFAULT_NAVIGATION: - startDefaultNavigation(); - return true; - case MENU_BROWSER: - cache.openInBrowser(this); - return true; - case MENU_CACHES_AROUND: - CacheListActivity.startActivityCoordinates(this, cache.getCoords()); - return true; - case MENU_CALENDAR: - addToCalendarWithIntent(); - return true; - case MENU_SHARE: - if (cache != null) { - cache.shareCache(this, res); - return true; - } - return false; default: if (NavigationAppFactory.onMenuItemSelected(item, this, cache)) { return true; @@ -699,80 +663,6 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc } /** - * Indicates whether the specified action can be used as an intent. This - * method queries the package manager for installed packages that can - * respond to an intent with the specified action. If no suitable package is - * found, this method returns false. - * - * @param context - * The application's environment. - * @param action - * The Intent action to check for availability. - * @param uri - * The Intent URI to check for availability. - * - * @return True if an Intent with the specified action can be sent and - * responded to, false otherwise. - */ - private static boolean isIntentAvailable(Context context, String action, Uri uri) { - final PackageManager packageManager = context.getPackageManager(); - final Intent intent; - if (uri == null) { - intent = new Intent(action); - } else { - intent = new Intent(action, uri); - } - final List<ResolveInfo> list = packageManager.queryIntentActivities(intent, - PackageManager.MATCH_DEFAULT_ONLY); - return !list.isEmpty(); - } - - private void addToCalendarWithIntent() { - - final boolean calendarAddOnAvailable = isIntentAvailable(this, ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST)); - - if (calendarAddOnAvailable) { - final Parameters params = new Parameters( - ICalendar.PARAM_NAME, cache.getName(), - ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()), - ICalendar.PARAM_HIDDEN_DATE, String.valueOf(cache.getHiddenDate().getTime()), - ICalendar.PARAM_URL, StringUtils.defaultString(cache.getUrl()), - ICalendar.PARAM_COORDS, cache.getCoords() == null ? "" : cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECMINUTE_RAW), - ICalendar.PARAM_LOCATION, StringUtils.defaultString(cache.getLocation()), - ICalendar.PARAM_SHORT_DESC, StringUtils.defaultString(cache.getShortDescription()), - ICalendar.PARAM_START_TIME_MINUTES, StringUtils.defaultString(cache.guessEventTimeMinutes()) - ); - - startActivity(new Intent(ICalendar.INTENT, - Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST + "?" + params.toString()))); - } else { - // Inform user the calendar add-on is not installed and let them get it from Google Play - new AlertDialog.Builder(this) - .setTitle(res.getString(R.string.addon_missing_title)) - .setMessage(new StringBuilder(res.getString(R.string.helper_calendar_missing)) - .append(' ') - .append(res.getString(R.string.addon_download_prompt)) - .toString()) - .setPositiveButton(getString(android.R.string.yes), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - final Intent intent = new Intent(Intent.ACTION_VIEW); - intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI)); - startActivity(intent); - } - }) - .setNegativeButton(getString(android.R.string.no), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int id) { - dialog.cancel(); - } - }) - .create() - .show(); - } - } - - /** * Tries to navigate to the {@link Geocache} of this activity. */ private void startDefaultNavigation() { @@ -1779,6 +1669,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc private final View shortDescView; public LoadDescriptionTask(final String description, final View descriptionView, final View loadingIndicatorView, final View shortDescView) { + assert descriptionView instanceof IndexOutOfBoundsAvoidingTextView; this.descriptionString = description; this.descriptionView = (IndexOutOfBoundsAvoidingTextView) descriptionView; this.loadingIndicatorView = loadingIndicatorView; @@ -2480,4 +2371,19 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc personalNoteView.setVisibility(View.GONE); } } + + @Override + public void navigateTo() { + startDefaultNavigation(); + } + + @Override + public void showNavigationMenu() { + NavigationAppFactory.showNavigationMenu(this, cache, null, null); + } + + @Override + public void cachesAround() { + CacheListActivity.startActivityCoordinates(this, cache.getCoords()); + } } diff --git a/main/src/cgeo/geocaching/CacheListActivity.java b/main/src/cgeo/geocaching/CacheListActivity.java index 848518d..6c6cd35 100644 --- a/main/src/cgeo/geocaching/CacheListActivity.java +++ b/main/src/cgeo/geocaching/CacheListActivity.java @@ -45,6 +45,7 @@ import cgeo.geocaching.utils.Log; import cgeo.geocaching.utils.RunnableWithArgument; import ch.boye.httpclientandroidlib.HttpResponse; + import org.apache.commons.collections4.CollectionUtils; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; @@ -68,7 +69,6 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuItem; -import android.view.SubMenu; import android.view.View; import android.widget.AdapterView.AdapterContextMenuInfo; import android.widget.ListView; @@ -85,34 +85,6 @@ import java.util.Set; public class CacheListActivity extends AbstractListActivity implements FilteredActivity, LoaderManager.LoaderCallbacks<SearchResult> { private static final int MAX_LIST_ITEMS = 1000; - private static final int MENU_REFRESH_STORED = 2; - private static final int MENU_CACHE_DETAILS = 4; - private static final int MENU_DROP_CACHES = 5; - private static final int MENU_IMPORT_GPX = 6; - private static final int MENU_CREATE_LIST = 7; - private static final int MENU_DROP_LIST = 8; - private static final int MENU_INVERT_SELECTION = 9; - private static final int MENU_SWITCH_LIST = 17; - private static final int MENU_IMPORT_WEB = 21; - private static final int MENU_EXPORT = 22; - private static final int MENU_REMOVE_FROM_HISTORY = 23; - private static final int MENU_DROP_CACHE = 24; - private static final int MENU_MOVE_TO_LIST = 25; - private static final int MENU_REFRESH = 26; - private static final int MENU_SWITCH_SELECT_MODE = 52; - private static final int SUBMENU_SHOW_MAP = 54; - private static final int SUBMENU_MANAGE_LISTS = 55; - private static final int SUBMENU_MANAGE_OFFLINE = 56; - private static final int MENU_SORT = 57; - private static final int SUBMENU_MANAGE_HISTORY = 60; - private static final int MENU_RENAME_LIST = 64; - private static final int MENU_DROP_CACHES_AND_LIST = 65; - private static final int MENU_DEFAULT_NAVIGATION = 66; - private static final int MENU_NAVIGATION = 69; - private static final int MENU_STORE_CACHE = 73; - private static final int MENU_FILTER = 74; - private static final int MENU_DELETE_EVENTS = 75; - private static final int MENU_CLEAR_OFFLINE_LOGS = 76; private static final int MSG_DONE = -1; private static final int MSG_RESTART_GEO_AND_DIR = -2; @@ -162,10 +134,6 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA }; private ContextMenuInfo lastMenuInfo; private String contextMenuGeocode = ""; - /** - * the navigation menu item for the cache list (not the context menu!), or <code>null</code> - */ - private MenuItem navigationMenu; // FIXME: This method has mostly been replaced by the loaders. But it still contains a license agreement check. public void handleCachesLoaded() { @@ -531,132 +499,80 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA @Override public boolean onCreateOptionsMenu(Menu menu) { - menu.add(0, MENU_FILTER, 0, res.getString(R.string.caches_filter)).setIcon(R.drawable.ic_menu_filter); - - if (type != CacheListType.HISTORY) { - menu.add(0, MENU_SORT, 0, res.getString(R.string.caches_sort)).setIcon(R.drawable.ic_menu_sort_alphabetically); - } - - menu.add(0, MENU_SWITCH_SELECT_MODE, 0, res.getString(R.string.caches_select_mode)).setIcon(R.drawable.ic_menu_agenda); - menu.add(0, MENU_INVERT_SELECTION, 0, res.getString(R.string.caches_select_invert)).setIcon(R.drawable.ic_menu_mark); - if (type == CacheListType.OFFLINE) { - final SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_OFFLINE, 0, res.getString(R.string.caches_manage)).setIcon(R.drawable.ic_menu_save); - subMenu.add(0, MENU_DROP_CACHES, 0, res.getString(R.string.caches_drop_all)); // delete saved caches - subMenu.add(0, MENU_DROP_CACHES_AND_LIST, 0, res.getString(R.string.caches_drop_all_and_list)); - subMenu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)); // download details for all caches - subMenu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); - subMenu.add(0, MENU_DELETE_EVENTS, 0, res.getString(R.string.caches_delete_events)); - subMenu.add(0, MENU_CLEAR_OFFLINE_LOGS, 0, res.getString(R.string.caches_clear_offlinelogs)); - - //TODO: add submenu/AlertDialog and use R.string.gpx_import_title - subMenu.add(0, MENU_IMPORT_GPX, 0, res.getString(R.string.gpx_import_title)); - if (Settings.getWebDeviceCode() != null) { - subMenu.add(0, MENU_IMPORT_WEB, 0, res.getString(R.string.web_import_title)); - } - - subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches - } else { - if (type == CacheListType.HISTORY) { - final SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_HISTORY, 0, res.getString(R.string.caches_manage)).setIcon(R.drawable.ic_menu_save); - subMenu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); // export caches - subMenu.add(0, MENU_REMOVE_FROM_HISTORY, 0, res.getString(R.string.cache_clear_history)); // remove from history - subMenu.add(0, MENU_CLEAR_OFFLINE_LOGS, 0, res.getString(R.string.caches_clear_offlinelogs)); - menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.cache_offline_refresh)).setIcon(R.drawable.ic_menu_set_as); - } else { - menu.add(0, MENU_REFRESH_STORED, 0, res.getString(R.string.caches_store_offline)).setIcon(R.drawable.ic_menu_set_as); // download details for all caches - } - } + getMenuInflater().inflate(R.menu.cache_list_options, menu); - navigationMenu = CacheListAppFactory.addMenuItems(menu, this, res); - - if (type == CacheListType.OFFLINE) { - final SubMenu subMenu = menu.addSubMenu(0, SUBMENU_MANAGE_LISTS, 0, res.getString(R.string.list_menu)).setIcon(R.drawable.ic_menu_more); - subMenu.add(0, MENU_CREATE_LIST, 0, res.getString(R.string.list_menu_create)); - subMenu.add(0, MENU_DROP_LIST, 0, res.getString(R.string.list_menu_drop)); - subMenu.add(0, MENU_RENAME_LIST, 0, res.getString(R.string.list_menu_rename)); - subMenu.add(0, MENU_SWITCH_LIST, 0, res.getString(R.string.list_menu_change)); - } + CacheListAppFactory.addMenuItems(menu, this, res); return true; } private static void setVisible(final Menu menu, final int itemId, final boolean visible) { - final MenuItem item = menu.findItem(itemId); - if (item != null) { - item.setVisible(visible); - } + menu.findItem(itemId).setVisible(visible); } @Override public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); + final boolean isHistory = type == CacheListType.HISTORY; + final boolean isOffline = type == CacheListType.OFFLINE; + final boolean isEmpty = cacheList.isEmpty(); + final boolean isConcrete = isConcreteList(); + try { if (adapter.isSelectMode()) { - menu.findItem(MENU_SWITCH_SELECT_MODE).setTitle(res.getString(R.string.caches_select_mode_exit)) + menu.findItem(R.id.menu_switch_select_mode).setTitle(res.getString(R.string.caches_select_mode_exit)) .setIcon(R.drawable.ic_menu_clear_playlist); - menu.findItem(MENU_INVERT_SELECTION).setVisible(true); } else { - menu.findItem(MENU_SWITCH_SELECT_MODE).setTitle(res.getString(R.string.caches_select_mode)) + menu.findItem(R.id.menu_switch_select_mode).setTitle(res.getString(R.string.caches_select_mode)) .setIcon(R.drawable.ic_menu_agenda); - menu.findItem(MENU_INVERT_SELECTION).setVisible(false); } - - final boolean isEmpty = cacheList.isEmpty(); - final boolean isConcrete = isConcreteList(); - - setVisible(menu, MENU_SWITCH_SELECT_MODE, !isEmpty); - setVisible(menu, SUBMENU_MANAGE_HISTORY, !isEmpty); - setVisible(menu, SUBMENU_SHOW_MAP, !isEmpty); - setVisible(menu, MENU_SORT, !isEmpty); - setVisible(menu, MENU_REFRESH_STORED, !isEmpty && (isConcrete || type != CacheListType.OFFLINE)); - setVisible(menu, MENU_DROP_CACHES, !isEmpty); - setVisible(menu, MENU_DROP_CACHES_AND_LIST, isConcrete && !isEmpty); - setVisible(menu, MENU_DELETE_EVENTS, isConcrete && !isEmpty && containsEvents()); - setVisible(menu, MENU_MOVE_TO_LIST, !isEmpty); - setVisible(menu, MENU_EXPORT, !isEmpty); - setVisible(menu, MENU_REMOVE_FROM_HISTORY, !isEmpty); - setVisible(menu, MENU_CLEAR_OFFLINE_LOGS, !isEmpty && containsOfflineLogs()); - - if (navigationMenu != null) { - navigationMenu.setVisible(!isEmpty); + menu.findItem(R.id.menu_invert_selection).setVisible(adapter.isSelectMode()); + + + setVisible(menu, R.id.menu_switch_select_mode, !isEmpty); + setVisible(menu, R.id.submenu_manage, isOffline || isHistory); + setVisible(menu, R.id.submenu_manage_lists, isOffline); + + setVisible(menu, R.id.menu_sort, !isEmpty && !isHistory); + setVisible(menu, R.id.menu_refresh_stored, !isEmpty && (isConcrete || type != CacheListType.OFFLINE)); + setVisible(menu, R.id.menu_drop_caches, !isEmpty && isOffline); + setVisible(menu, R.id.menu_drop_caches_and_list, isConcrete && !isEmpty && isOffline); + setVisible(menu, R.id.menu_delete_events, isConcrete && !isEmpty && containsEvents()); + setVisible(menu, R.id.menu_move_to_list, isOffline && !isEmpty); + setVisible(menu, R.id.menu_export, !isEmpty && (isHistory || isOffline)); + setVisible(menu, R.id.menu_remove_from_history, !isEmpty && isHistory); + setVisible(menu, R.id.menu_clear_offline_logs, !isEmpty && containsOfflineLogs() && (isHistory || isOffline)); + setVisible(menu, R.id.menu_import_web, isOffline && Settings.getWebDeviceCode() != null); + setVisible(menu, R.id.menu_import_gpx, isOffline); + setVisible(menu, R.id.menu_refresh_stored_top, !isOffline); + + if (!isOffline && !isHistory) { + menu.findItem(R.id.menu_refresh_stored_top).setTitle(R.string.caches_store_offline); } final boolean hasSelection = adapter != null && adapter.getCheckedCount() > 0; final boolean isNonDefaultList = isConcrete && listId != StoredList.STANDARD_LIST_ID; - if (type == CacheListType.OFFLINE || type == CacheListType.HISTORY) { // only offline list - setMenuItemLabel(menu, MENU_DROP_CACHES, R.string.caches_drop_selected, R.string.caches_drop_all); - setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_refresh_selected, R.string.caches_refresh_all); - setMenuItemLabel(menu, MENU_MOVE_TO_LIST, R.string.caches_move_selected, R.string.caches_move_all); + if (isOffline || type == CacheListType.HISTORY) { // only offline list + setMenuItemLabel(menu, R.id.menu_drop_caches, R.string.caches_drop_selected, R.string.caches_drop_all); + setMenuItemLabel(menu, R.id.menu_refresh_stored, R.string.caches_refresh_selected, R.string.caches_refresh_all); + setMenuItemLabel(menu, R.id.menu_move_to_list, R.string.caches_move_selected, R.string.caches_move_all); } else { // search and global list (all other than offline and history) - setMenuItemLabel(menu, MENU_REFRESH_STORED, R.string.caches_store_selected, R.string.caches_store_offline); - } - if (type == CacheListType.OFFLINE) { - menu.findItem(MENU_DROP_CACHES_AND_LIST).setVisible(!hasSelection && isNonDefaultList && !adapter.isFiltered()); + setMenuItemLabel(menu, R.id.menu_refresh_stored, R.string.caches_store_selected, R.string.caches_store_offline); } - MenuItem item = menu.findItem(MENU_DROP_LIST); - if (item != null) { - item.setVisible(isNonDefaultList); - } - item = menu.findItem(MENU_RENAME_LIST); - if (item != null) { - item.setVisible(isNonDefaultList); - } + menu.findItem(R.id.menu_drop_caches_and_list).setVisible(isOffline && !hasSelection && isNonDefaultList && !adapter.isFiltered()); + + menu.findItem(R.id.menu_drop_list).setVisible(isNonDefaultList); + menu.findItem(R.id.menu_rename_list).setVisible(isNonDefaultList); final boolean multipleLists = DataStore.getLists().size() >= 2; - item = menu.findItem(MENU_SWITCH_LIST); - if (item != null) { - item.setVisible(multipleLists); - } - item = menu.findItem(MENU_MOVE_TO_LIST); - if (item != null) { - item.setVisible(!isEmpty); - } + menu.findItem(R.id.menu_switch_list).setVisible(multipleLists); + menu.findItem(R.id.menu_move_to_list).setVisible(!isEmpty); - setMenuItemLabel(menu, MENU_REMOVE_FROM_HISTORY, R.string.cache_remove_from_history, R.string.cache_clear_history); - setMenuItemLabel(menu, MENU_EXPORT, R.string.export, R.string.export); + setMenuItemLabel(menu, R.id.menu_remove_from_history, R.string.cache_remove_from_history, R.string.cache_clear_history); + setMenuItemLabel(menu, R.id.menu_export, R.string.export, R.string.export); } catch (final RuntimeException e) { Log.e("CacheListActivity.onPrepareOptionsMenu", e); } @@ -697,51 +613,51 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA @Override public boolean onOptionsItemSelected(MenuItem item) { - final int itemId = item.getItemId(); - switch (itemId) { - case MENU_SWITCH_SELECT_MODE: + switch (item.getItemId()) { + case R.id.menu_switch_select_mode: adapter.switchSelectMode(); invalidateOptionsMenuCompatible(); return true; - case MENU_REFRESH_STORED: + case R.id.menu_refresh_stored_top: + case R.id.menu_refresh_stored: refreshStored(adapter.getCheckedOrAllCaches()); invalidateOptionsMenuCompatible(); return true; - case MENU_DROP_CACHES: + case R.id.menu_drop_caches: dropStored(false); invalidateOptionsMenuCompatible(); return false; - case MENU_DROP_CACHES_AND_LIST: + case R.id.menu_drop_caches_and_list: dropStored(true); invalidateOptionsMenuCompatible(); return true; - case MENU_IMPORT_GPX: + case R.id.menu_import_gpx: importGpx(); invalidateOptionsMenuCompatible(); return false; - case MENU_CREATE_LIST: + case R.id.menu_create_list: new StoredList.UserInterface(this).promptForListCreation(getListSwitchingRunnable(), newListName); invalidateOptionsMenuCompatible(); return false; - case MENU_DROP_LIST: + case R.id.menu_drop_list: removeList(true); invalidateOptionsMenuCompatible(); return false; - case MENU_RENAME_LIST: + case R.id.menu_rename_list: renameList(); return false; - case MENU_INVERT_SELECTION: + case R.id.menu_invert_selection: adapter.invertSelection(); invalidateOptionsMenuCompatible(); return false; - case MENU_SWITCH_LIST: + case R.id.menu_switch_list: selectList(); invalidateOptionsMenuCompatible(); return false; - case MENU_FILTER: + case R.id.menu_filter: showFilterMenu(null); return true; - case MENU_SORT: + case R.id.menu_sort: final CacheComparator oldComparator = adapter.getCacheComparator(); new ComparatorUserInterface(this).selectComparator(oldComparator, new RunnableWithArgument<CacheComparator>() { @Override @@ -758,25 +674,25 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA } }); return true; - case MENU_IMPORT_WEB: + case R.id.menu_import_web: importWeb(); return false; - case MENU_EXPORT: + case R.id.menu_export: ExportFactory.showExportMenu(adapter.getCheckedOrAllCaches(), this); return false; - case MENU_REMOVE_FROM_HISTORY: + case R.id.menu_remove_from_history: removeFromHistoryCheck(); invalidateOptionsMenuCompatible(); return false; - case MENU_MOVE_TO_LIST: + case R.id.menu_move_to_list: moveCachesToOtherList(); invalidateOptionsMenuCompatible(); return true; - case MENU_DELETE_EVENTS: + case R.id.menu_delete_events: deletePastEvents(); invalidateOptionsMenuCompatible(); return true; - case MENU_CLEAR_OFFLINE_LOGS: + case R.id.menu_clear_offline_logs: clearOfflineLogs(); invalidateOptionsMenuCompatible(); return true; @@ -846,21 +762,21 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA contextMenuGeocode = cache.getGeocode(); - if (cache.getCoords() != null) { - menu.add(0, MENU_DEFAULT_NAVIGATION, 0, NavigationAppFactory.getDefaultNavigationApplication().getName()); - menu.add(1, MENU_NAVIGATION, 0, res.getString(R.string.cache_menu_navigate)).setIcon(R.drawable.ic_menu_mapmode); - LoggingUI.addMenuItems(this, menu, cache); - menu.add(0, MENU_CACHE_DETAILS, 0, res.getString(R.string.cache_menu_details)); - } - if (cache.isOffline()) { - menu.add(0, MENU_DROP_CACHE, 0, res.getString(R.string.cache_offline_drop)); - menu.add(0, MENU_MOVE_TO_LIST, 0, res.getString(R.string.cache_menu_move_list)); - menu.add(0, MENU_EXPORT, 0, res.getString(R.string.export)); - menu.add(0, MENU_REFRESH, 0, res.getString(R.string.cache_menu_refresh)); - } - else { - menu.add(0, MENU_STORE_CACHE, 0, res.getString(R.string.cache_offline_store)); - } + getMenuInflater().inflate(R.menu.cache_list_context, menu); + + menu.findItem(R.id.menu_default_navigation).setTitle(NavigationAppFactory.getDefaultNavigationApplication().getName()); + final boolean hasCoords = cache.getCoords() != null; + menu.findItem(R.id.menu_default_navigation).setVisible(hasCoords); + menu.findItem(R.id.menu_navigate).setVisible(hasCoords); + menu.findItem(R.id.menu_cache_details).setVisible(hasCoords); + final boolean isOffline = cache.isOffline(); + menu.findItem(R.id.menu_drop_cache).setVisible(isOffline); + menu.findItem(R.id.menu_move_to_list).setVisible(isOffline); + menu.findItem(R.id.menu_export).setVisible(isOffline); + menu.findItem(R.id.menu_refresh).setVisible(isOffline); + menu.findItem(R.id.menu_store_cache).setVisible(!isOffline); + + LoggingUI.onPrepareOptionsMenu(menu, cache); } private void moveCachesToOtherList() { @@ -901,18 +817,17 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA return true; } - final int id = item.getItemId(); - switch (id) { - case MENU_DEFAULT_NAVIGATION: + switch (item.getItemId()) { + case R.id.menu_default_navigation: NavigationAppFactory.startDefaultNavigationApplication(1, this, cache); break; - case MENU_NAVIGATION: + case R.id.menu_navigate: NavigationAppFactory.showNavigationMenu(this, cache, null, null); break; - case MENU_CACHE_DETAILS: + case R.id.menu_cache_details: CacheDetailActivity.startActivity(this, cache.getGeocode(), cache.getName()); break; - case MENU_DROP_CACHE: + case R.id.menu_drop_cache: cache.drop(new Handler() { @Override public void handleMessage(Message msg) { @@ -921,7 +836,7 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA } }); break; - case MENU_MOVE_TO_LIST: + case R.id.menu_move_to_list: new StoredList.UserInterface(this).promptForListSelection(R.string.cache_menu_move_list, new RunnableWithArgument<Integer>() { @Override @@ -932,11 +847,11 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA } }, true, listId, newListName); break; - case MENU_STORE_CACHE: - case MENU_REFRESH: + case R.id.menu_store_cache: + case R.id.menu_refresh: refreshStored(Collections.singletonList(cache)); break; - case MENU_EXPORT: + case R.id.menu_export: ExportFactory.showExportMenu(Collections.singletonList(cache), this); return false; default: @@ -1734,6 +1649,8 @@ public class CacheListActivity extends AbstractListActivity implements FilteredA case NEXT_PAGE: loader = new NextPageGeocacheListLoader(app, search); break; + default: + throw new IllegalStateException(); } setTitle(title); showProgress(true); diff --git a/main/src/cgeo/geocaching/CacheMenuHandler.java b/main/src/cgeo/geocaching/CacheMenuHandler.java new file mode 100644 index 0000000..9326a73 --- /dev/null +++ b/main/src/cgeo/geocaching/CacheMenuHandler.java @@ -0,0 +1,126 @@ +package cgeo.geocaching; + +import cgeo.calendar.ICalendar; +import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; +import cgeo.geocaching.geopoint.GeopointFormatter; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.ui.AbstractUIFactory; +import cgeo.geocaching.utils.ProcessUtils; + +import org.apache.commons.lang3.StringUtils; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.net.Uri; +import android.view.Menu; +import android.view.MenuItem; + +/** + * Shared menu handling for all activities having menu items related to a cache. + * + */ +public class CacheMenuHandler extends AbstractUIFactory { + + /** + * Methods to be implemented by the activity to react to the cache menu selections. + * + */ + protected interface ActivityInterface { + public void navigateTo(); + + public void showNavigationMenu(); + + public void cachesAround(); + + } + + public static boolean onMenuItemSelected(MenuItem item, CacheMenuHandler.ActivityInterface activityInterface, Geocache cache) { + assert activityInterface instanceof Activity; + final Activity activity = (Activity) activityInterface; + switch (item.getItemId()) { + case R.id.menu_default_navigation: + activityInterface.navigateTo(); + return true; + case R.id.menu_navigate: + activityInterface.showNavigationMenu(); + return true; + case R.id.menu_caches_around: + activityInterface.cachesAround(); + return true; + case R.id.menu_show_in_browser: + cache.openInBrowser(activity); + return true; + case R.id.menu_share: + cache.shareCache(activity, res); + return true; + case R.id.menu_calendar: + addToCalendarWithIntent(activity, cache); + return true; + default: + return false; + } + } + + public static void onPrepareOptionsMenu(final Menu menu, final Geocache cache) { + final boolean hasCoords = cache.getCoords() != null; + menu.findItem(R.id.menu_default_navigation).setVisible(hasCoords); + menu.findItem(R.id.menu_navigate).setVisible(hasCoords); + menu.findItem(R.id.menu_caches_around).setVisible(hasCoords && cache.supportsCachesAround()); + menu.findItem(R.id.menu_calendar).setVisible(cache.canBeAddedToCalendar()); + menu.findItem(R.id.menu_show_in_browser).setVisible(cache.canOpenInBrowser()); + + menu.findItem(R.id.menu_default_navigation).setTitle(NavigationAppFactory.getDefaultNavigationApplication().getName()); + } + + public static void addMenuItems(Activity activity, Menu menu, Geocache cache) { + activity.getMenuInflater().inflate(R.menu.cache_options, menu); + onPrepareOptionsMenu(menu, cache); + } + + private static void addToCalendarWithIntent(final Activity activity, final Geocache cache) { + final boolean calendarAddOnAvailable = ProcessUtils.isIntentAvailable(ICalendar.INTENT, Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST)); + + if (calendarAddOnAvailable) { + final Parameters params = new Parameters( + ICalendar.PARAM_NAME, cache.getName(), + ICalendar.PARAM_NOTE, StringUtils.defaultString(cache.getPersonalNote()), + ICalendar.PARAM_HIDDEN_DATE, String.valueOf(cache.getHiddenDate().getTime()), + ICalendar.PARAM_URL, StringUtils.defaultString(cache.getUrl()), + ICalendar.PARAM_COORDS, cache.getCoords() == null ? "" : cache.getCoords().format(GeopointFormatter.Format.LAT_LON_DECMINUTE_RAW), + ICalendar.PARAM_LOCATION, StringUtils.defaultString(cache.getLocation()), + ICalendar.PARAM_SHORT_DESC, StringUtils.defaultString(cache.getShortDescription()), + ICalendar.PARAM_START_TIME_MINUTES, StringUtils.defaultString(cache.guessEventTimeMinutes()) + ); + + activity.startActivity(new Intent(ICalendar.INTENT, + Uri.parse(ICalendar.URI_SCHEME + "://" + ICalendar.URI_HOST + "?" + params.toString()))); + } else { + // Inform user the calendar add-on is not installed and let them get it from Google Play + new AlertDialog.Builder(activity) + .setTitle(res.getString(R.string.addon_missing_title)) + .setMessage(new StringBuilder(res.getString(R.string.helper_calendar_missing)) + .append(' ') + .append(res.getString(R.string.addon_download_prompt)) + .toString()) + .setPositiveButton(activity.getString(android.R.string.yes), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + final Intent intent = new Intent(Intent.ACTION_VIEW); + intent.setData(Uri.parse(ICalendar.CALENDAR_ADDON_URI)); + activity.startActivity(intent); + } + }) + .setNegativeButton(activity.getString(android.R.string.no), new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }) + .create() + .show(); + } + } + +} diff --git a/main/src/cgeo/geocaching/CachePopup.java b/main/src/cgeo/geocaching/CachePopup.java index 683ebe7..020c604 100644 --- a/main/src/cgeo/geocaching/CachePopup.java +++ b/main/src/cgeo/geocaching/CachePopup.java @@ -71,7 +71,7 @@ public class CachePopup extends AbstractPopupActivity { } @Override - protected void showNavigationMenu() { + public void showNavigationMenu() { NavigationAppFactory.showNavigationMenu(this, cache, null, null); } @@ -216,7 +216,7 @@ public class CachePopup extends AbstractPopupActivity { } @Override - protected void navigateTo() { + public void navigateTo() { NavigationAppFactory.startDefaultNavigationApplication(1, this, cache); } diff --git a/main/src/cgeo/geocaching/CompassActivity.java b/main/src/cgeo/geocaching/CompassActivity.java index b7bed7d..a176b7d 100644 --- a/main/src/cgeo/geocaching/CompassActivity.java +++ b/main/src/cgeo/geocaching/CompassActivity.java @@ -4,16 +4,20 @@ import butterknife.InjectView; import butterknife.Views; import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.Units; import cgeo.geocaching.maps.CGeoMap; import cgeo.geocaching.settings.Settings; import cgeo.geocaching.speech.SpeechService; import cgeo.geocaching.ui.CompassView; +import cgeo.geocaching.ui.Formatter; +import cgeo.geocaching.ui.LoggingUI; import cgeo.geocaching.utils.GeoDirHandler; import cgeo.geocaching.utils.Log; import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.Nullable; import android.content.Context; import android.content.Intent; @@ -34,6 +38,8 @@ import java.util.List; public class CompassActivity extends AbstractActivity { + private static final int COORDINATES_OFFSET = 10; + @InjectView(R.id.nav_type) protected TextView navType; @InjectView(R.id.nav_accuracy) protected TextView navAccuracy; @InjectView(R.id.nav_satellites) protected TextView navSatellites; @@ -49,8 +55,11 @@ public class CompassActivity extends AbstractActivity { private static final String EXTRAS_GEOCODE = "geocode"; private static final String EXTRAS_CACHE_INFO = "cacheinfo"; private static final List<IWaypoint> coordinates = new ArrayList<IWaypoint>(); - private static final int COORDINATES_OFFSET = 10; - private static final int REQUEST_TTS_DATA_CHECK = 1; + + /** + * Destination of the compass, or null (if the compass is used for a waypoint only). + */ + private @Nullable Geocache cache = null; private Geopoint dstCoords = null; private float cacheHeading = 0; private String title = null; @@ -70,7 +79,11 @@ public class CompassActivity extends AbstractActivity { // get parameters Bundle extras = getIntent().getExtras(); if (extras != null) { - title = extras.getString(EXTRAS_GEOCODE); + final String geocode = extras.getString(EXTRAS_GEOCODE); + if (StringUtils.isNotEmpty(geocode)) { + cache = DataStore.loadCache(geocode, LoadFlags.LOAD_CACHE_OR_DB); + } + title = geocode; final String name = extras.getString(EXTRAS_NAME); dstCoords = extras.getParcelable(EXTRAS_COORDS); info = extras.getString(EXTRAS_CACHE_INFO); @@ -105,7 +118,7 @@ public class CompassActivity extends AbstractActivity { public void onResume() { super.onResume(); - // sensor & geolocation manager + // sensor and geolocation manager geoDirHandler.startGeoAndDir(); } @@ -158,6 +171,9 @@ public class CompassActivity extends AbstractActivity { } else { menu.findItem(R.id.menu_select_destination).setVisible(false); } + if (cache != null) { + LoggingUI.addMenuItems(this, menu, cache); + } return true; } @@ -200,6 +216,9 @@ public class CompassActivity extends AbstractActivity { SpeechService.stopService(this); return true; default: + if (LoggingUI.onMenuItemSelected(item, this, cache)) { + return true; + } int coordinatesIndex = id - COORDINATES_OFFSET; if (coordinatesIndex >= 0 && coordinatesIndex < coordinates.size()) { final IWaypoint coordinate = coordinates.get(coordinatesIndex); @@ -326,4 +345,9 @@ public class CompassActivity extends AbstractActivity { CompassActivity.startActivity(context, geocode, displayedName, coords, coordinatesWithType, null); } + public static void startActivity(final Context context, final Geocache cache) { + startActivity(context, cache.getGeocode(), cache.getName(), cache.getCoords(), null, + Formatter.formatCacheInfoShort(cache)); + } + } diff --git a/main/src/cgeo/geocaching/GeoDataProvider.java b/main/src/cgeo/geocaching/GeoDataProvider.java index f615630..73aefce 100644 --- a/main/src/cgeo/geocaching/GeoDataProvider.java +++ b/main/src/cgeo/geocaching/GeoDataProvider.java @@ -272,6 +272,7 @@ class GeoDataProvider extends MemorySubject<IGeoData> { public void onGpsStatusChanged(final int event) { boolean changed = false; switch (event) { + case GpsStatus.GPS_EVENT_FIRST_FIX: case GpsStatus.GPS_EVENT_SATELLITE_STATUS: { final GpsStatus status = geoManager.getGpsStatus(null); int visible = 0; @@ -303,6 +304,8 @@ class GeoDataProvider extends MemorySubject<IGeoData> { changed = true; } break; + default: + throw new IllegalStateException(); } if (changed) { diff --git a/main/src/cgeo/geocaching/WaypointPopup.java b/main/src/cgeo/geocaching/WaypointPopup.java index c33bbb5..acd3d9b 100644 --- a/main/src/cgeo/geocaching/WaypointPopup.java +++ b/main/src/cgeo/geocaching/WaypointPopup.java @@ -94,7 +94,7 @@ public class WaypointPopup extends AbstractPopupActivity { } @Override - protected void navigateTo() { + public void navigateTo() { NavigationAppFactory.startDefaultNavigationApplication(1, this, waypoint); } @@ -119,7 +119,7 @@ public class WaypointPopup extends AbstractPopupActivity { } @Override - protected void showNavigationMenu() { + public void showNavigationMenu() { NavigationAppFactory.showNavigationMenu(this, null, waypoint, null); } diff --git a/main/src/cgeo/geocaching/apps/AbstractApp.java b/main/src/cgeo/geocaching/apps/AbstractApp.java index d861542..494e245 100644 --- a/main/src/cgeo/geocaching/apps/AbstractApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractApp.java @@ -1,7 +1,7 @@ package cgeo.geocaching.apps; -import cgeo.geocaching.Geocache; import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.Geocache; import cgeo.geocaching.utils.ProcessUtils; import org.apache.commons.lang3.StringUtils; @@ -13,16 +13,21 @@ public abstract class AbstractApp implements App { private final String packageName; private final String intent; private final String name; + /** + * a unique id, defined in res/values/ids.xml + */ + private final int id; - protected AbstractApp(final String name, final String intent, + protected AbstractApp(final String name, final int id, final String intent, final String packageName) { this.name = name; + this.id = id; this.intent = intent; this.packageName = packageName; } - protected AbstractApp(final String name, final String intent) { - this(name, intent, null); + protected AbstractApp(final String name, final int id, final String intent) { + this(name, id, intent, null); } @Override @@ -38,7 +43,7 @@ public abstract class AbstractApp implements App { } @Override - public boolean isDefaultNavigationApp() { + public boolean isUsableAsDefaultNavigationApp() { return true; } @@ -49,7 +54,7 @@ public abstract class AbstractApp implements App { @Override public int getId() { - return getName().hashCode(); + return id; } protected static String getString(int ressourceId) { diff --git a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java index 2db8918..c2715c8 100644 --- a/main/src/cgeo/geocaching/apps/AbstractLocusApp.java +++ b/main/src/cgeo/geocaching/apps/AbstractLocusApp.java @@ -1,9 +1,8 @@ package cgeo.geocaching.apps; +import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.Geocache; -import cgeo.geocaching.R; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.WaypointType; @@ -16,7 +15,6 @@ import menion.android.locus.addon.publiclib.geoData.PointGeocachingDataWaypoint; import menion.android.locus.addon.publiclib.geoData.PointsData; import android.app.Activity; -import android.content.Intent; import android.location.Location; import java.text.SimpleDateFormat; @@ -30,15 +28,10 @@ import java.util.Locale; * @see <a href="http://forum.asamm.cz/viewtopic.php?f=29&t=767">Locus forum</a> */ public abstract class AbstractLocusApp extends AbstractApp { - private static final String INTENT = Intent.ACTION_VIEW; private static final SimpleDateFormat ISO8601DATE = new SimpleDateFormat("yyyy-MM-dd'T'", Locale.US); - protected AbstractLocusApp() { - super(getString(R.string.caches_map_locus), INTENT); - } - - protected AbstractLocusApp(final String text, final String intent) { - super(text, intent); + protected AbstractLocusApp(final String text, int id, final String intent) { + super(text, id, intent); } @Override @@ -48,7 +41,7 @@ public abstract class AbstractLocusApp extends AbstractApp { /** * Display a list of caches / waypoints in Locus - * + * * @param objectsToShow * which caches/waypoints to show * @param withCacheWaypoints diff --git a/main/src/cgeo/geocaching/apps/App.java b/main/src/cgeo/geocaching/apps/App.java index bc99526..7e70581 100644 --- a/main/src/cgeo/geocaching/apps/App.java +++ b/main/src/cgeo/geocaching/apps/App.java @@ -5,14 +5,20 @@ import cgeo.geocaching.Geocache; public interface App { public boolean isInstalled(); - public boolean isDefaultNavigationApp(); + /** + * Whether or not an application can be used as the default navigation. + */ + public boolean isUsableAsDefaultNavigationApp(); public String getName(); + /** + * @return the unique ID of the application, defined in res/values/ids.xml + */ int getId(); /** - * whether or not the app can be used with the given cache (may depend on properties of the cache) + * Whether or not the app can be used with the given cache (may depend on properties of the cache). * * @param cache * @return diff --git a/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java b/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java index fd7d4b5..c4f2723 100644 --- a/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java +++ b/main/src/cgeo/geocaching/apps/cache/AbstractGeneralApp.java @@ -9,8 +9,8 @@ import android.content.Intent; abstract class AbstractGeneralApp extends AbstractApp implements CacheNavigationApp { - protected AbstractGeneralApp(String name, String packageName) { - super(name, null, packageName); + protected AbstractGeneralApp(final String name, final int id, final String packageName) { + super(name, id, null, packageName); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/CacheBeaconApp.java b/main/src/cgeo/geocaching/apps/cache/CacheBeaconApp.java index 9cfafb4..34c9074 100644 --- a/main/src/cgeo/geocaching/apps/cache/CacheBeaconApp.java +++ b/main/src/cgeo/geocaching/apps/cache/CacheBeaconApp.java @@ -7,7 +7,7 @@ import cgeo.geocaching.enumerations.CacheAttribute; public class CacheBeaconApp extends AbstractGeneralApp { public CacheBeaconApp() { - super(getString(R.string.cache_menu_cachebeacon), "de.fun2code.android.cachebeacon"); + super(getString(R.string.cache_menu_cachebeacon), R.id.cache_app_cache_beacon, "de.fun2code.android.cachebeacon"); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/GccApp.java b/main/src/cgeo/geocaching/apps/cache/GccApp.java index 0bbc2dd..4423977 100644 --- a/main/src/cgeo/geocaching/apps/cache/GccApp.java +++ b/main/src/cgeo/geocaching/apps/cache/GccApp.java @@ -10,7 +10,7 @@ public class GccApp extends AbstractGeneralApp { private static final String PACKAGE_PRO = "eisbehr.gcc.pro"; public GccApp() { - super(getString(R.string.cache_menu_gcc), null); + super(getString(R.string.cache_menu_gcc), R.id.cache_app_gcc, null); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java b/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java index 39e1963..79a5975 100644 --- a/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java +++ b/main/src/cgeo/geocaching/apps/cache/WhereYouGoApp.java @@ -1,12 +1,12 @@ package cgeo.geocaching.apps.cache; -import cgeo.geocaching.R; import cgeo.geocaching.Geocache; +import cgeo.geocaching.R; import cgeo.geocaching.enumerations.CacheType; public class WhereYouGoApp extends AbstractGeneralApp { public WhereYouGoApp() { - super(getString(R.string.cache_menu_whereyougo), "menion.android.whereyougo"); + super(getString(R.string.cache_menu_whereyougo), R.id.cache_app_whereyougo, "menion.android.whereyougo"); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java index 7542e24..75ea056 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractPointNavigationApp.java @@ -14,12 +14,12 @@ import android.app.Activity; */ abstract class AbstractPointNavigationApp extends AbstractApp implements CacheNavigationApp, WaypointNavigationApp, GeopointNavigationApp { - protected AbstractPointNavigationApp(String name, String intent) { - super(name, intent); + protected AbstractPointNavigationApp(final String name, final int id, final String intent) { + super(name, id, intent); } - protected AbstractPointNavigationApp(String name, String intent, String packageName) { - super(name, intent, packageName); + protected AbstractPointNavigationApp(final String name, final int id, final String intent, final String packageName) { + super(name, id, intent, packageName); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java index d5c9435..c42c2a2 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/AbstractStaticMapsApp.java @@ -1,12 +1,12 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.DataStore; import cgeo.geocaching.Geocache; import cgeo.geocaching.ILogable; import cgeo.geocaching.R; import cgeo.geocaching.StaticMapsActivity; import cgeo.geocaching.StaticMapsProvider; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.DataStore; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.AbstractApp; @@ -15,8 +15,8 @@ import org.apache.commons.lang3.StringUtils; import android.app.Activity; abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigationApp, WaypointNavigationApp { - protected AbstractStaticMapsApp(String name) { - super(name, null); + protected AbstractStaticMapsApp(final String name, final int id) { + super(name, id, null); } @Override @@ -25,7 +25,7 @@ abstract class AbstractStaticMapsApp extends AbstractApp implements CacheNavigat } @Override - public boolean isDefaultNavigationApp() { + public boolean isUsableAsDefaultNavigationApp() { return false; } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java index 47010df..03d2220 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/CompassApp.java @@ -1,18 +1,17 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.CompassActivity; import cgeo.geocaching.Geocache; import cgeo.geocaching.R; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.CompassActivity; import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.ui.Formatter; import android.app.Activity; class CompassApp extends AbstractPointNavigationApp { CompassApp() { - super(getString(R.string.compass_title), null); + super(getString(R.string.compass_title), R.id.cache_app_compass, null); } @Override @@ -33,8 +32,7 @@ class CompassApp extends AbstractPointNavigationApp { @Override public void navigate(Activity activity, Geocache cache) { - CompassActivity.startActivity(activity, cache.getGeocode(), cache.getName(), cache.getCoords(), null, - Formatter.formatCacheInfoShort(cache)); + CompassActivity.startActivity(activity, cache); } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/apps/cache/navi/DownloadStaticMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/DownloadStaticMapsApp.java index bc422d4..19b5e02 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/DownloadStaticMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/DownloadStaticMapsApp.java @@ -9,7 +9,7 @@ import android.app.Activity; class DownloadStaticMapsApp extends AbstractStaticMapsApp { DownloadStaticMapsApp() { - super(getString(R.string.cache_menu_download_map_static)); + super(getString(R.string.cache_menu_download_map_static), R.id.cache_app_download_static_maps); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java index 4cbfa00..60d6e31 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsApp.java @@ -12,7 +12,7 @@ import android.net.Uri; class GoogleMapsApp extends AbstractPointNavigationApp { GoogleMapsApp() { - super(getString(R.string.cache_menu_map_ext), null); + super(getString(R.string.cache_menu_map_ext), R.id.cache_app_google_maps, null); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java index a5b9a94..c4351bb 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleMapsDirectionApp.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.maps.MapProviderFactory; import cgeo.geocaching.utils.Log; @@ -14,7 +14,7 @@ import android.net.Uri; public class GoogleMapsDirectionApp extends AbstractPointNavigationApp { protected GoogleMapsDirectionApp() { - super(getString(R.string.cache_menu_maps_directions), null); + super(getString(R.string.cache_menu_maps_directions), R.id.cache_app_google_maps_direction, null); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java index a3532a5..902eebf 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/GoogleNavigationApp.java @@ -12,8 +12,8 @@ abstract class GoogleNavigationApp extends AbstractPointNavigationApp { private final String mode; - protected GoogleNavigationApp(final int nameResourceId, final String mode) { - super(getString(nameResourceId), null); + protected GoogleNavigationApp(final int nameResourceId, final int id, final String mode) { + super(getString(nameResourceId), id, null); this.mode = mode; } @@ -36,19 +36,19 @@ abstract class GoogleNavigationApp extends AbstractPointNavigationApp { static class GoogleNavigationWalkingApp extends GoogleNavigationApp { GoogleNavigationWalkingApp() { - super(R.string.cache_menu_navigation_walk, "w"); + super(R.string.cache_menu_navigation_walk, R.id.cache_app_google_navigation_walk, "w"); } } static class GoogleNavigationDrivingApp extends GoogleNavigationApp { GoogleNavigationDrivingApp() { - super(R.string.cache_menu_navigation_drive, "d"); + super(R.string.cache_menu_navigation_drive, R.id.cache_app_google_navigation_drive, "d"); } } static class GoogleNavigationBikeApp extends GoogleNavigationApp { GoogleNavigationBikeApp() { - super(R.string.cache_menu_navigation_bike, "b"); + super(R.string.cache_menu_navigation_bike, R.id.cache_app_google_navigation_bike, "b"); } } }
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java index cdf14f0..540b025 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/InternalMap.java @@ -12,7 +12,7 @@ import android.app.Activity; class InternalMap extends AbstractPointNavigationApp { InternalMap() { - super(getString(R.string.cache_menu_map), null); + super(getString(R.string.cache_menu_map), R.id.cache_app_internal_map, null); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java index 8b64ac8..b60d78a 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/LocusApp.java @@ -1,15 +1,24 @@ package cgeo.geocaching.apps.cache.navi; + import cgeo.geocaching.Geocache; +import cgeo.geocaching.R; import cgeo.geocaching.Waypoint; import cgeo.geocaching.apps.AbstractLocusApp; import android.app.Activity; +import android.content.Intent; import java.util.Collections; class LocusApp extends AbstractLocusApp implements CacheNavigationApp, WaypointNavigationApp { + private static final String INTENT = Intent.ACTION_VIEW; + + protected LocusApp() { + super(getString(R.string.caches_map_locus), R.id.cache_app_locus, INTENT); + } + @Override public boolean isEnabled(Waypoint waypoint) { return waypoint.getCoords() != null; diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java index c10da58..ce42e36 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigationAppFactory.java @@ -216,7 +216,7 @@ public final class NavigationAppFactory extends AbstractAppFactory { public static List<NavigationAppsEnum> getInstalledDefaultNavigationApps() { final List<NavigationAppsEnum> installedNavigationApps = new ArrayList<NavigationAppsEnum>(); for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) { - if (appEnum.app.isInstalled() && appEnum.app.isDefaultNavigationApp()) { + if (appEnum.app.isInstalled() && appEnum.app.isUsableAsDefaultNavigationApp()) { installedNavigationApps.add(appEnum); } } diff --git a/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java b/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java index 7966733..da988aa 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/NavigonApp.java @@ -13,7 +13,7 @@ class NavigonApp extends AbstractPointNavigationApp { private static final String INTENT_EXTRA_KEY_LONGITUDE = "longitude"; NavigonApp() { - super(getString(R.string.cache_menu_navigon), INTENT); + super(getString(R.string.cache_menu_navigon), R.id.cache_app_navigon, INTENT); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java index 24ef81b..5d645f7 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/OruxMapsApp.java @@ -11,7 +11,7 @@ class OruxMapsApp extends AbstractPointNavigationApp { private static final String INTENT = "com.oruxmaps.VIEW_MAP_ONLINE"; OruxMapsApp() { - super(getString(R.string.cache_menu_oruxmaps), INTENT); + super(getString(R.string.cache_menu_oruxmaps), R.id.cache_app_orux_maps, INTENT); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java index b203aeb..82d144e 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/RMapsApp.java @@ -16,7 +16,7 @@ class RMapsApp extends AbstractPointNavigationApp { private static final String INTENT = "com.robert.maps.action.SHOW_POINTS"; RMapsApp() { - super(getString(R.string.cache_menu_rmaps), INTENT); + super(getString(R.string.cache_menu_rmaps), R.id.cache_app_rmaps, INTENT); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java b/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java index b01539c..ffa6650 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/RadarApp.java @@ -12,7 +12,7 @@ class RadarApp extends AbstractPointNavigationApp { private static final String PACKAGE_NAME = "com.eclipsim.gpsstatus2"; RadarApp() { - super(getString(R.string.cache_menu_radar), INTENT, PACKAGE_NAME); + super(getString(R.string.cache_menu_radar), R.id.cache_app_radar, INTENT, PACKAGE_NAME); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java b/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java index 1dd57a3..9e1b3f0 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/StaticMapApp.java @@ -1,15 +1,15 @@ package cgeo.geocaching.apps.cache.navi; +import cgeo.geocaching.Geocache; import cgeo.geocaching.R; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.Geocache; import android.app.Activity; class StaticMapApp extends AbstractStaticMapsApp { StaticMapApp() { - super(getString(R.string.cache_menu_map_static)); + super(getString(R.string.cache_menu_map_static), R.id.cache_app_show_static_maps); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java b/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java index df67e43..7294a40 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/StreetviewApp.java @@ -17,7 +17,7 @@ class StreetviewApp extends AbstractPointNavigationApp { private static final boolean INSTALLED = ProcessUtils.isInstalled(PACKAGE_NAME_STREET_VIEW); StreetviewApp() { - super(getString(R.string.cache_menu_streetview), null); + super(getString(R.string.cache_menu_streetview), R.id.cache_app_street_view, null); } @Override diff --git a/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java b/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java index e30bfc1..76b7f0e 100644 --- a/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java +++ b/main/src/cgeo/geocaching/apps/cache/navi/SygicNavigationApp.java @@ -17,7 +17,7 @@ public class SygicNavigationApp extends AbstractPointNavigationApp { private static final String PACKAGE = "com.sygic.aura"; SygicNavigationApp() { - super(getString(R.string.cache_menu_sygic), null, PACKAGE); + super(getString(R.string.cache_menu_sygic), R.id.cache_app_sygic, null, PACKAGE); } @Override diff --git a/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java index 49d75d7..6411758 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/AbstractLocusCacheListApp.java @@ -16,8 +16,8 @@ abstract class AbstractLocusCacheListApp extends AbstractLocusApp implements Cac private boolean export; - public AbstractLocusCacheListApp(boolean export) { - super(getString(export ? R.string.caches_map_locus_export : R.string.caches_map_locus), Intent.ACTION_VIEW); + public AbstractLocusCacheListApp(final int id, boolean export) { + super(getString(export ? R.string.caches_map_locus_export : R.string.caches_map_locus), id, Intent.ACTION_VIEW); this.export = export; } diff --git a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java index 551bc9d..4df9d26 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java +++ b/main/src/cgeo/geocaching/apps/cachelist/CacheListAppFactory.java @@ -29,35 +29,45 @@ public final class CacheListAppFactory extends AbstractAppFactory { * @param menu * @param activity * @param res - * @return the added menu item (also for a sub menu, then the menu item in the parent menu is returned) */ - public static MenuItem addMenuItems(final Menu menu, final Activity activity, final Resources res) { + public static void addMenuItems(final Menu menu, final Activity activity, final Resources res) { + final List<CacheListApp> activeApps = getActiveApps(); + if (activeApps.isEmpty()) { + return; + } + if (activeApps.size() == 1) { + final MenuItem subItem = menu.findItem(R.id.menu_cache_list_app); + subItem.setVisible(true); + subItem.setTitle(activeApps.get(0).getName()); + } else { + final MenuItem subItem = menu.findItem(R.id.submenu_cache_list_app); + subItem.setVisible(true); + final SubMenu subMenu = subItem.getSubMenu(); + for (final CacheListApp app : activeApps) { + subMenu.add(0, app.getId(), 0, app.getName()); + } + } + } + + private static List<CacheListApp> getActiveApps() { final List<CacheListApp> activeApps = new ArrayList<CacheListApp>(LazyHolder.apps.length); for (final CacheListApp app : LazyHolder.apps) { if (app.isInstalled()) { activeApps.add(app); } } - // use a new sub menu, if more than one app is available - switch (activeApps.size()) { - case 0: - return null; - case 1: - return menu.add(0, activeApps.get(0).getId(), 0, - activeApps.get(0).getName()).setIcon(R.drawable.ic_menu_mapmode); - default: - final SubMenu subMenu = menu.addSubMenu(0, 101, 0, - res.getString(R.string.caches_on_map)).setIcon(R.drawable.ic_menu_mapmode); - for (final CacheListApp app : activeApps) { - subMenu.add(0, app.getId(), 0, app.getName()); - } - return subMenu.getItem(); - } + return activeApps; } public static boolean onMenuItemSelected(final MenuItem item, final List<Geocache> caches, final Activity activity, final SearchResult search) { - final CacheListApp app = (CacheListApp) getAppFromMenuItem(item, LazyHolder.apps); + CacheListApp app; + if (item.getItemId() == R.id.menu_cache_list_app) { + app = getActiveApps().get(0); + } + else { + app = (CacheListApp) getAppFromMenuItem(item, LazyHolder.apps); + } if (app != null) { try { boolean result = app.invoke(caches, activity, search); diff --git a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java index 38fb499..9216bc0 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java +++ b/main/src/cgeo/geocaching/apps/cachelist/InternalCacheListMap.java @@ -1,8 +1,8 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.Geocache; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Geocache; import cgeo.geocaching.apps.AbstractApp; import cgeo.geocaching.maps.CGeoMap; @@ -13,7 +13,7 @@ import java.util.List; class InternalCacheListMap extends AbstractApp implements CacheListApp { InternalCacheListMap() { - super(getString(R.string.cache_menu_map), null); + super(getString(R.string.cache_menu_map), R.id.cache_list_app_map, null); } @Override diff --git a/main/src/cgeo/geocaching/apps/cachelist/LocusExportCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/LocusExportCacheListApp.java index ef97be0..adaa849 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/LocusExportCacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/LocusExportCacheListApp.java @@ -1,9 +1,11 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.R; + final class LocusExportCacheListApp extends AbstractLocusCacheListApp { public LocusExportCacheListApp() { - super(true); + super(R.id.cache_list_app_locus_export, true); } } diff --git a/main/src/cgeo/geocaching/apps/cachelist/LocusShowCacheListApp.java b/main/src/cgeo/geocaching/apps/cachelist/LocusShowCacheListApp.java index 4b018f9..32c5cb6 100644 --- a/main/src/cgeo/geocaching/apps/cachelist/LocusShowCacheListApp.java +++ b/main/src/cgeo/geocaching/apps/cachelist/LocusShowCacheListApp.java @@ -1,9 +1,11 @@ package cgeo.geocaching.apps.cachelist; +import cgeo.geocaching.R; + final class LocusShowCacheListApp extends AbstractLocusCacheListApp { public LocusShowCacheListApp() { - super(false); + super(R.id.cache_list_app_locus_show, false); } } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index 54e3447..3fdc11b 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -6,6 +6,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.Trackable; import cgeo.geocaching.connector.capability.ILogin; import cgeo.geocaching.connector.capability.ISearchByCenter; +import cgeo.geocaching.connector.capability.ISearchByKeyword; import cgeo.geocaching.connector.capability.ISearchByViewPort; import cgeo.geocaching.connector.gc.GCConnector; import cgeo.geocaching.connector.oc.OCApiConnector; @@ -60,6 +61,8 @@ public final class ConnectorFactory { private static final ISearchByCenter[] searchByCenterConns; + private static final ISearchByKeyword[] searchByKeywordConns; + static { final List<ISearchByViewPort> vpConns = new ArrayList<ISearchByViewPort>(); for (final IConnector conn : CONNECTORS) { @@ -77,6 +80,15 @@ public final class ConnectorFactory { } } searchByCenterConns = centerConns.toArray(new ISearchByCenter[centerConns.size()]); + + final List<ISearchByKeyword> keywordConns = new ArrayList<ISearchByKeyword>(); + for (final IConnector conn : CONNECTORS) { + // GCConnector is handled specially, omit it here! + if (conn instanceof ISearchByKeyword && !(conn instanceof GCConnector)) { + keywordConns.add((ISearchByKeyword) conn); + } + } + searchByKeywordConns = keywordConns.toArray(new ISearchByKeyword[keywordConns.size()]); } public static IConnector[] getConnectors() { @@ -87,6 +99,10 @@ public final class ConnectorFactory { return searchByCenterConns; } + public static ISearchByKeyword[] getSearchByKeywordConnectors() { + return searchByKeywordConns; + } + public static ILogin[] getActiveLiveConnectors() { final List<ILogin> liveConns = new ArrayList<ILogin>(); for (final IConnector conn : CONNECTORS) { diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java index 3fdd61f..91dd094 100644 --- a/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java +++ b/main/src/cgeo/geocaching/connector/capability/ISearchByCenter.java @@ -1,14 +1,13 @@ package cgeo.geocaching.connector.capability; import cgeo.geocaching.SearchResult; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.geopoint.Geopoint; /** * connector capability for online searching caches around a center coordinate, sorted by distance * */ -public interface ISearchByCenter { +public interface ISearchByCenter extends IConnector { public SearchResult searchByCenter(final Geopoint center); - - public boolean isActivated(); } diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java b/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java index c3d6bba..4c16049 100644 --- a/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java +++ b/main/src/cgeo/geocaching/connector/capability/ISearchByGeocode.java @@ -1,12 +1,13 @@ package cgeo.geocaching.connector.capability; import cgeo.geocaching.SearchResult; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.utils.CancellableHandler; /** * connector capability of searching online for a cache by geocode - * + * */ -public interface ISearchByGeocode { +public interface ISearchByGeocode extends IConnector { public SearchResult searchByGeocode(final String geocode, final String guid, final CancellableHandler handler); } diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java b/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java new file mode 100644 index 0000000..09b2423 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/capability/ISearchByKeyword.java @@ -0,0 +1,12 @@ +package cgeo.geocaching.connector.capability; + +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.connector.IConnector; + +/** + * connector capability of searching online for a cache by name + * + */ +public interface ISearchByKeyword extends IConnector { + public SearchResult searchByName(final String name); +} diff --git a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java index f1bd2ce..4954017 100644 --- a/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java +++ b/main/src/cgeo/geocaching/connector/capability/ISearchByViewPort.java @@ -1,10 +1,9 @@ package cgeo.geocaching.connector.capability; import cgeo.geocaching.SearchResult; +import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.geopoint.Viewport; -public interface ISearchByViewPort { +public interface ISearchByViewPort extends IConnector { public SearchResult searchByViewport(final Viewport viewport, final String[] tokens); - - public boolean isActivated(); } diff --git a/main/src/cgeo/geocaching/connector/gc/GCParser.java b/main/src/cgeo/geocaching/connector/gc/GCParser.java index c0090b3..778006f 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCParser.java +++ b/main/src/cgeo/geocaching/connector/gc/GCParser.java @@ -1642,7 +1642,7 @@ public abstract class GCParser { // TODO: we should update our log data structure to be able to record // proper coordinates, and make them clickable. In the meantime, it is // better to integrate those coordinates into the text rather than not - // display them as all. + // display them at all. final String latLon = entry.getString("LatLonString"); final LogEntry logDone = new LogEntry( entry.getString("UserName"), diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java index 8f38641..b1b9088 100644 --- a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java +++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java @@ -8,6 +8,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.connector.ILoggingManager; import cgeo.geocaching.connector.capability.ILogin; import cgeo.geocaching.connector.capability.ISearchByCenter; +import cgeo.geocaching.connector.capability.ISearchByKeyword; import cgeo.geocaching.connector.capability.ISearchByViewPort; import cgeo.geocaching.connector.oc.UserInfo.UserInfoStatus; import cgeo.geocaching.geopoint.Geopoint; @@ -20,7 +21,7 @@ import org.apache.commons.lang3.StringUtils; import android.content.Context; import android.os.Handler; -public class OCApiLiveConnector extends OCApiConnector implements ISearchByCenter, ISearchByViewPort, ILogin { +public class OCApiLiveConnector extends OCApiConnector implements ISearchByCenter, ISearchByViewPort, ILogin, ISearchByKeyword { private final String cS; private final int isActivePrefKeyId; @@ -152,4 +153,10 @@ public class OCApiLiveConnector extends OCApiConnector implements ISearchByCente public boolean isLoggedIn() { return userInfo.getStatus() == UserInfoStatus.SUCCESSFUL; } + + @Override + public SearchResult searchByName(final String name) { + final Geopoint currentPos = CgeoApplication.getInstance().currentGeo().getCoords(); + return new SearchResult(OkapiClient.getCachesNamed(currentPos, name, this)); + } } diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java index 309969e..fcc81e0 100644 --- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java @@ -1,12 +1,12 @@ package cgeo.geocaching.connector.oc; +import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.DataStore; import cgeo.geocaching.Geocache; import cgeo.geocaching.Image; import cgeo.geocaching.LogEntry; import cgeo.geocaching.R; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; import cgeo.geocaching.connector.LogResult; @@ -81,7 +81,6 @@ final class OkapiClient { private static final String CACHE_LATEST_LOGS = "latest_logs"; private static final String CACHE_IMAGE_URL = "url"; private static final String CACHE_IMAGE_CAPTION = "caption"; - private static final String CACHE_IMAGE_IS_SPOILER = "is_spoiler"; private static final String CACHE_IMAGES = "images"; private static final String CACHE_HINT = "hint"; private static final String CACHE_DESCRIPTION = "description"; @@ -116,8 +115,9 @@ final class OkapiClient { private static final String SERVICE_CACHE_ADDITIONAL_CURRENT_FIELDS = "gc_code|attribution_note"; private static final String SERVICE_CACHE_ADDITIONAL_L3_FIELDS = "is_watched|my_notes"; - private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest"; + private static final String METHOD_SEARCH_ALL = "services/caches/search/all"; private static final String METHOD_SEARCH_BBOX = "services/caches/search/bbox"; + private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest"; private static final String METHOD_RETRIEVE_CACHES = "services/caches/geocaches"; public static Geocache getCache(final String geoCode) { @@ -152,6 +152,27 @@ final class OkapiClient { return requestCaches(connector, params, valueMap); } + public static List<Geocache> getCachesNamed(final Geopoint center, final String namePart, final OCApiConnector connector) { + final Map<String, String> valueMap = new LinkedHashMap<String, String>(); + final Parameters params; + + // search around current position, if there is a position + if (center != null) { + final String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + SEPARATOR + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center); + params = new Parameters("search_method", METHOD_SEARCH_NEAREST); + valueMap.put("center", centerString); + valueMap.put("limit", "20"); + } + else { + params = new Parameters("search_method", METHOD_SEARCH_ALL); + valueMap.put("limit", "20"); + } + + // full wildcard search, maybe we need to change this after some testing and evaluation + valueMap.put("name", "*" + namePart + "*"); + return requestCaches(connector, params, valueMap); + } + private static List<Geocache> requestCaches(final OCApiConnector connector, final Parameters params, final Map<String, String> valueMap) { addFilterParams(valueMap, connector); params.add("search_params", new JSONObject(valueMap).toString()); @@ -166,7 +187,9 @@ final class OkapiClient { return parseCaches(data); } - // Assumes level 3 OAuth + /** + * Assumes level 3 OAuth. + */ public static List<Geocache> getCachesBBox(final Viewport viewport, final OCApiConnector connector) { if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) { @@ -318,6 +341,7 @@ final class OkapiClient { final JSONObject imageResponse = images.getJSONObject(i); final String title = imageResponse.getString(CACHE_IMAGE_CAPTION); final String url = absoluteUrl(imageResponse.getString(CACHE_IMAGE_URL), cache.getGeocode()); + // all images are added as spoiler images, although OKAPI has spoiler and non spoiler images cache.addSpoiler(new Image(url, title)); } } diff --git a/main/src/cgeo/geocaching/files/LocalStorage.java b/main/src/cgeo/geocaching/files/LocalStorage.java index 40684f8..edbecf6 100644 --- a/main/src/cgeo/geocaching/files/LocalStorage.java +++ b/main/src/cgeo/geocaching/files/LocalStorage.java @@ -7,6 +7,7 @@ import cgeo.geocaching.utils.Log; import ch.boye.httpclientandroidlib.Header; import ch.boye.httpclientandroidlib.HttpResponse; + import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import org.eclipse.jdt.annotation.Nullable; @@ -37,6 +38,7 @@ import java.util.List; */ public final class LocalStorage { + private static final String FILE_SYSTEM_TABLE_PATH = "/system/etc/vold.fstab"; public static final String HEADER_LAST_MODIFIED = "last-modified"; public static final String HEADER_ETAG = "etag"; @@ -424,7 +426,7 @@ public final class LocalStorage { String extStorage = Environment.getExternalStorageDirectory().getAbsolutePath(); List<File> storages = new ArrayList<File>(); storages.add(new File(extStorage)); - File file = new File("/system/etc/vold.fstab"); + File file = new File(FILE_SYSTEM_TABLE_PATH); if (file.canRead()) { Reader fr = null; BufferedReader br = null; diff --git a/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java b/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java index adfc423..c8132e7 100644 --- a/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java +++ b/main/src/cgeo/geocaching/loaders/KeywordGeocacheListLoader.java @@ -1,8 +1,10 @@ package cgeo.geocaching.loaders; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.settings.Settings; +import cgeo.geocaching.connector.ConnectorFactory; +import cgeo.geocaching.connector.capability.ISearchByKeyword; import cgeo.geocaching.connector.gc.GCParser; +import cgeo.geocaching.settings.Settings; import android.content.Context; @@ -17,7 +19,18 @@ public class KeywordGeocacheListLoader extends AbstractSearchLoader { @Override public SearchResult runSearch() { - return GCParser.searchByKeyword(keyword, Settings.getCacheType(), Settings.isShowCaptcha(), this); + SearchResult searchResult = new SearchResult(); + if (Settings.isGCConnectorActive()) { + searchResult = GCParser.searchByKeyword(keyword, Settings.getCacheType(), Settings.isShowCaptcha(), this); + } + + for (ISearchByKeyword connector : ConnectorFactory.getSearchByKeywordConnectors()) { + if (connector.isActivated()) { + searchResult.addSearchResult(connector.searchByName(keyword)); + } + } + + return searchResult; } } diff --git a/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java b/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java index 8ca0fa5..dc1a5df 100644 --- a/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java +++ b/main/src/cgeo/geocaching/loaders/RemoveFromHistoryLoader.java @@ -2,9 +2,9 @@ package cgeo.geocaching.loaders; import cgeo.geocaching.DataStore; import cgeo.geocaching.SearchResult; -import cgeo.geocaching.settings.Settings; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.settings.Settings; import android.content.Context; @@ -15,7 +15,7 @@ public class RemoveFromHistoryLoader extends AbstractSearchLoader { public RemoveFromHistoryLoader(Context context, String[] selected, Geopoint coords) { super(context); - this.selected = selected; + this.selected = selected.clone(); this.coords = coords; } diff --git a/main/src/cgeo/geocaching/maps/CGeoMap.java b/main/src/cgeo/geocaching/maps/CGeoMap.java index a32a669..0c62e65 100644 --- a/main/src/cgeo/geocaching/maps/CGeoMap.java +++ b/main/src/cgeo/geocaching/maps/CGeoMap.java @@ -1,14 +1,14 @@ package cgeo.geocaching.maps; +import cgeo.geocaching.CacheListActivity; import cgeo.geocaching.CgeoApplication; +import cgeo.geocaching.DataStore; import cgeo.geocaching.DirectionProvider; import cgeo.geocaching.Geocache; import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Waypoint; -import cgeo.geocaching.DataStore; -import cgeo.geocaching.CacheListActivity; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.gc.Login; @@ -1383,7 +1383,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto final private CancellableHandler handler; final private List<String> geocodes; final private int listId; - private long last = 0L; public LoadDetails(final CancellableHandler handler, final List<String> geocodes, final int listId) { this.handler = handler; @@ -1410,25 +1409,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto } if (!DataStore.isOffline(geocode, null)) { - if ((System.currentTimeMillis() - last) < 1500) { - try { - int delay = 1000 + (int) (Math.random() * 1000.0) - (int) (System.currentTimeMillis() - last); - if (delay < 0) { - delay = 500; - } - - sleep(delay); - } catch (InterruptedException e) { - // nothing - } - } - - if (handler.isCancelled()) { - Log.i("Stopped storing process."); - - break; - } - Geocache.storeCache(null, geocode, listId, false, handler); } } catch (Exception e) { @@ -1441,8 +1421,6 @@ public class CGeoMap extends AbstractMap implements OnMapDragListener, ViewFacto // FIXME: what does this yield() do here? yield(); - - last = System.currentTimeMillis(); } // we're done diff --git a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java index a94b988..f61e523 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/MapsforgeOverlay.java @@ -31,7 +31,7 @@ public class MapsforgeOverlay extends Overlay implements OverlayImpl { overlayBase = new ScaleOverlay(activityIn, this); break; default: - throw new IllegalArgumentException(); + throw new IllegalStateException(); } } diff --git a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java index bdaac98..8c9e0c3 100644 --- a/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java +++ b/main/src/cgeo/geocaching/maps/mapsforge/v024/MapsforgeOverlay.java @@ -29,6 +29,9 @@ public class MapsforgeOverlay extends Overlay implements OverlayImpl { break; case ScaleOverlay: overlayBase = new ScaleOverlay(activityIn, this); + break; + default: + throw new IllegalStateException(); } } diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java index 4ef8b62..c033660 100644 --- a/main/src/cgeo/geocaching/network/OAuth.java +++ b/main/src/cgeo/geocaching/network/OAuth.java @@ -3,7 +3,9 @@ package cgeo.geocaching.network; import cgeo.geocaching.utils.CryptUtils; import ch.boye.httpclientandroidlib.NameValuePair; + import org.apache.commons.lang3.StringUtils; +import org.eclipse.jdt.annotation.NonNull; import org.eclipse.jdt.annotation.Nullable; import java.util.ArrayList; @@ -31,11 +33,21 @@ public class OAuth { final List<String> paramsEncoded = new ArrayList<String>(); for (final NameValuePair nameValue : params) { - paramsEncoded.add(nameValue.getName() + "=" + Network.rfc3986URLEncode(nameValue.getValue())); + paramsEncoded.add(nameValue.getName() + "=" + OAuth.percentEncode(nameValue.getValue())); } final String keysPacked = consumerSecret + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them! - final String requestPacked = method + "&" + Network.rfc3986URLEncode((https ? "https" : "http") + "://" + host + path) + "&" + Network.rfc3986URLEncode(StringUtils.join(paramsEncoded.toArray(), '&')); + final String requestPacked = method + "&" + OAuth.percentEncode((https ? "https" : "http") + "://" + host + path) + "&" + OAuth.percentEncode(StringUtils.join(paramsEncoded.toArray(), '&')); params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked))); } + + /** + * percent encode following http://tools.ietf.org/html/rfc5849#section-3.6 + * + * @param url + * @return + */ + static String percentEncode(@NonNull String url) { + return StringUtils.replace(Network.rfc3986URLEncode(url), "*", "%2A"); + } } diff --git a/main/src/cgeo/geocaching/speech/SpeechService.java b/main/src/cgeo/geocaching/speech/SpeechService.java index baa843b..2a72bbf 100644 --- a/main/src/cgeo/geocaching/speech/SpeechService.java +++ b/main/src/cgeo/geocaching/speech/SpeechService.java @@ -1,8 +1,8 @@ package cgeo.geocaching.speech; +import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.DirectionProvider; import cgeo.geocaching.R; -import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.settings.Settings; @@ -177,7 +177,7 @@ public class SpeechService extends Service implements OnInitListener { if (intent != null) { target = intent.getParcelableExtra(EXTRA_TARGET_COORDS); } - return START_NOT_STICKY; + return START_NOT_STICKY; // service can be stopped by system, if under memory pressure } private void speak(final String text) { diff --git a/main/src/cgeo/geocaching/ui/CacheListAdapter.java b/main/src/cgeo/geocaching/ui/CacheListAdapter.java index be02eab..017eb51 100644 --- a/main/src/cgeo/geocaching/ui/CacheListAdapter.java +++ b/main/src/cgeo/geocaching/ui/CacheListAdapter.java @@ -517,6 +517,7 @@ public class CacheListAdapter extends ArrayAdapter<Geocache> { @Override public void onClick(View view) { + assert view instanceof CheckBox; final boolean checkNow = ((CheckBox) view).isChecked(); cache.setStatusChecked(checkNow); } diff --git a/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java index afadb33..299256c 100644 --- a/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java +++ b/main/src/cgeo/geocaching/ui/CoordinatesFormatSwitcher.java @@ -9,7 +9,7 @@ import android.widget.TextView; /** * view click listener to automatically switch different coordinate formats - * + * */ public class CoordinatesFormatSwitcher implements OnClickListener { @@ -29,6 +29,7 @@ public class CoordinatesFormatSwitcher implements OnClickListener { @Override public void onClick(View view) { + assert view instanceof TextView; position = (position + 1) % availableFormats.length; TextView textView = (TextView) view; // rotate coordinate formats on click diff --git a/main/src/cgeo/geocaching/ui/ImagesList.java b/main/src/cgeo/geocaching/ui/ImagesList.java index 9cca5b5..4eaf06d 100644 --- a/main/src/cgeo/geocaching/ui/ImagesList.java +++ b/main/src/cgeo/geocaching/ui/ImagesList.java @@ -156,6 +156,7 @@ public class ImagesList { } public void onCreateContextMenu(ContextMenu menu, View v) { + assert v instanceof ImageView; activity.getMenuInflater().inflate(R.menu.images_list_context, menu); final Resources res = activity.getResources(); menu.setHeaderTitle(res.getString(R.string.cache_image)); diff --git a/main/src/cgeo/geocaching/ui/LoggingUI.java b/main/src/cgeo/geocaching/ui/LoggingUI.java index 1423da2..30c719e 100644 --- a/main/src/cgeo/geocaching/ui/LoggingUI.java +++ b/main/src/cgeo/geocaching/ui/LoggingUI.java @@ -105,6 +105,8 @@ public class LoggingUI extends AbstractUIFactory { case CLEAR_LOG: cache.clearOfflineLog(); break; + default: + throw new IllegalStateException(); } } else { cache.logOffline(activity, logTypeEntry.logType); diff --git a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java index 91ce7e3..00d4c1a 100644 --- a/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java +++ b/main/src/cgeo/geocaching/ui/dialog/CoordinatesInputDialog.java @@ -3,13 +3,13 @@ package cgeo.geocaching.ui.dialog; import cgeo.geocaching.Geocache; import cgeo.geocaching.IGeoData; import cgeo.geocaching.R; -import cgeo.geocaching.settings.Settings; -import cgeo.geocaching.settings.Settings.CoordInputFormatEnum; import cgeo.geocaching.activity.AbstractActivity; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; +import cgeo.geocaching.settings.Settings; +import cgeo.geocaching.settings.Settings.CoordInputFormatEnum; import org.apache.commons.lang3.StringUtils; @@ -216,6 +216,8 @@ public class CoordinatesInputDialog extends NoTitleDialog { eLonSec.setText(addZeros(gp.getLonSec(), 2)); eLonSub.setText(addZeros(gp.getLonSecFrac(), 3)); break; + default: + throw new IllegalStateException(); } } @@ -227,6 +229,7 @@ public class CoordinatesInputDialog extends NoTitleDialog { @Override public void onClick(View view) { + assert view instanceof Button; final Button button = (Button) view; final CharSequence text = button.getText(); if (StringUtils.isBlank(text)) { diff --git a/main/src/cgeo/geocaching/utils/ProcessUtils.java b/main/src/cgeo/geocaching/utils/ProcessUtils.java index 737fb35..d80674b 100644 --- a/main/src/cgeo/geocaching/utils/ProcessUtils.java +++ b/main/src/cgeo/geocaching/utils/ProcessUtils.java @@ -8,6 +8,7 @@ import android.content.Intent; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.net.Uri; import java.util.List; @@ -70,10 +71,34 @@ public final class ProcessUtils { } public static boolean isIntentAvailable(final String intent) { - final PackageManager packageManager = CgeoApplication.getInstance().getPackageManager(); - final List<ResolveInfo> list = packageManager.queryIntentActivities( - new Intent(intent), PackageManager.MATCH_DEFAULT_ONLY); + return isIntentAvailable(intent, null); + } + /** + * Indicates whether the specified action can be used as an intent. This + * method queries the package manager for installed packages that can + * respond to an intent with the specified action. If no suitable package is + * found, this method returns false. + * + * @param action + * The Intent action to check for availability. + * @param uri + * The Intent URI to check for availability. + * + * @return True if an Intent with the specified action can be sent and + * responded to, false otherwise. + */ + public static boolean isIntentAvailable(final String action, final Uri uri) { + final PackageManager packageManager = CgeoApplication.getInstance().getPackageManager(); + final Intent intent; + if (uri == null) { + intent = new Intent(action); + } else { + intent = new Intent(action, uri); + } + final List<ResolveInfo> list = packageManager.queryIntentActivities(intent, + PackageManager.MATCH_DEFAULT_ONLY); return CollectionUtils.isNotEmpty(list); } + } |
