package cgeo.geocaching.apps.cache.navi; import cgeo.geocaching.R; import cgeo.geocaching.Settings; import cgeo.geocaching.cgCache; import cgeo.geocaching.cgWaypoint; import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.utils.Log; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; import android.view.Menu; import android.view.MenuItem; import android.widget.ArrayAdapter; import java.util.ArrayList; import java.util.List; public final class NavigationAppFactory extends AbstractAppFactory { public enum NavigationAppsEnum { /** The internal compass activity */ COMPASS(new CompassApp(), 0), /** The external radar app */ RADAR(new RadarApp(), 1), /** The selected map */ INTERNAL_MAP(new InternalMap(), 2), /** The internal static map activity */ STATIC_MAP(new StaticMapApp(), 3), /** The external Locus app */ DOWNLOAD_STATIC_MAPS(new DownloadStaticMapsApp(), 20), /** The external Locus app */ LOCUS(new LocusApp(), 4), /** The external RMaps app */ RMAPS(new RMapsApp(), 5), /** Google Maps */ GOOGLE_MAPS(new GoogleMapsApp(), 6), /** Google Navigation */ GOOGLE_NAVIGATION(new GoogleNavigationApp(), 7), /** Google Streetview */ GOOGLE_STREETVIEW(new StreetviewApp(), 8), /** The external OruxMaps app */ ORUX_MAPS(new OruxMapsApp(), 9), /** The external navigon app */ NAVIGON(new NavigonApp(), 10); NavigationAppsEnum(NavigationApp app, int id) { this.app = app; this.id = id; } /** * The app instance to use */ public final NavigationApp app; /** * The id - used in c:geo settings */ public final int id; /* * display app name in array adapter * * @see java.lang.Enum#toString() */ @Override public String toString() { return app.getName(); } } /** * Default way to handle selection of navigation tool.
* A dialog is created for tool selection and the selected tool is started afterwards. *

* Delegates to {@link #showNavigationMenu(Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} with * showInternalMap = true and showDefaultNavigation = false * * @param activity * @param cache * @param waypoint * @param destination */ public static void showNavigationMenu(final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint destination) { showNavigationMenu(activity, cache, waypoint, destination, true, false); } /** * Specialized way to handle selection of navigation tool.
* A dialog is created for tool selection and the selected tool is started afterwards. * * @param activity * @param cache * may be null * @param waypoint * may be null * @param destination * may be null * @param showInternalMap * should be false only when called from within the internal map * @param showDefaultNavigation * should be false by default * * @see #showNavigationMenu(Activity, cgCache, cgWaypoint, Geopoint) */ public static void showNavigationMenu(final Activity activity, final cgCache cache, final cgWaypoint waypoint, final Geopoint destination, final boolean showInternalMap, final boolean showDefaultNavigation) { final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(R.string.cache_menu_navigate); builder.setIcon(R.drawable.ic_menu_mapmode); final List items = new ArrayList(); final int defaultNavigationTool = Settings.getDefaultNavigationTool(); for (NavigationAppsEnum navApp : getInstalledNavigationApps()) { if ((showInternalMap || !(navApp.app instanceof InternalMap)) && (showDefaultNavigation || defaultNavigationTool != navApp.id)) { if (navApp.app.isEnabled(cache) || navApp.app.isEnabled(waypoint) || navApp.app.isEnabled(destination)) { items.add(navApp); } } } /* * Using an ArrayAdapter with list of NavigationAppsEnum items avoids * handling between mapping list positions allows us to do dynamic filtering of the list based on use case. */ final ArrayAdapter adapter = new ArrayAdapter(activity, android.R.layout.select_dialog_item, items); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int item) { NavigationAppsEnum selectedItem = adapter.getItem(item); selectedItem.app.invoke(activity, cache, waypoint, destination); } }); final AlertDialog alert = builder.create(); alert.show(); } /** * Returns all installed navigation apps. * * @return */ public static List getInstalledNavigationApps() { final List installedNavigationApps = new ArrayList(); for (NavigationAppsEnum appEnum : NavigationAppsEnum.values()) { if (appEnum.app.isInstalled()) { installedNavigationApps.add(appEnum); } } return installedNavigationApps; } /** * This offset is used to build unique menu ids to avoid collisions of ids in menus */ private static final int MENU_ITEM_OFFSET = 12345; /** * Adds the installed navigation tools to the given menu. * Use {@link #onMenuItemSelected(MenuItem, Activity, cgCache)} on * selection event to start the selected navigation tool. * * Only use this way if {@link #showNavigationMenu(Activity, cgCache, cgWaypoint, Geopoint, boolean, boolean)} is * not suitable for the given usecase. * * @param menu */ public static void addMenuItems(final Menu menu, final cgCache cache) { for (NavigationAppsEnum navApp : getInstalledNavigationApps()) { if (navApp.app.isEnabled(cache)) { menu.add(0, MENU_ITEM_OFFSET + navApp.id, 0, navApp.app.getName()); } } } public static void addMenuItems(final Menu menu, final cgWaypoint waypoint) { for (NavigationAppsEnum navApp : getInstalledNavigationApps()) { if (navApp.app.isEnabled(waypoint)) { menu.add(0, MENU_ITEM_OFFSET + navApp.id, 0, navApp.app.getName()); } } } /** * Handles menu selections for menu entries created with {@link #addMenuItems(Menu, cgCache)}. * * @param item * @param activity * @param cache * @return */ public static boolean onMenuItemSelected(final MenuItem item, Activity activity, cgCache cache) { return invokeApp(activity, cache, null, null, getAppFromMenuItem(item)); } public static boolean onMenuItemSelected(final MenuItem item, Activity activity, cgWaypoint waypoint) { return invokeApp(activity, null, waypoint, null, getAppFromMenuItem(item)); } private static boolean invokeApp(Activity activity, cgCache cache, cgWaypoint waypoint, final Geopoint destination, final NavigationApp app) { if (app == null) { return false; } if (cache == null && waypoint == null && destination == null) { return false; } try { return app.invoke(activity, cache, waypoint, destination); } catch (Exception e) { Log.e("NavigationAppFactory.onMenuItemSelected: " + e.toString()); } return false; } private static NavigationApp getAppFromMenuItem(MenuItem item) { final int id = item.getItemId(); for (NavigationAppsEnum navApp : NavigationAppsEnum.values()) { if (MENU_ITEM_OFFSET + navApp.id == id) { return navApp.app; } } return null; } /** * Starts the default navigation tool if correctly set and installed or the compass app as default fallback. * * @param defaultNavigation * * @param activity * @param cache */ public static void startDefaultNavigationApplication(int defaultNavigation, Activity activity, cgCache cache) { if (cache == null || cache.getCoords() == null) { ActivityMixin.showToast(activity, cgeoapplication.getInstance().getString(R.string.err_location_unknown)); return; } invokeApp(activity, cache, null, null, getDefaultNavigationApplication(defaultNavigation)); } private static NavigationApp getDefaultNavigationApplication(int defaultNavigation) { if (defaultNavigation == 2) { return getNavigationAppFromSetting(Settings.getDefaultNavigationTool2()); } return getNavigationAppFromSetting(Settings.getDefaultNavigationTool()); } /** * Starts the default navigation tool if correctly set and installed or the compass app as default fallback. * * @param activity * @param waypoint */ public static void startDefaultNavigationApplication(int defaultNavigation, Activity activity, cgWaypoint waypoint) { if (waypoint == null || waypoint.getCoords() == null) { ActivityMixin.showToast(activity, cgeoapplication.getInstance().getString(R.string.err_location_unknown)); return; } invokeApp(activity, null, waypoint, null, getDefaultNavigationApplication(defaultNavigation)); } /** * Starts the default navigation tool if correctly set and installed or the compass app as default fallback. * * @param activity * @param destination */ public static void startDefaultNavigationApplication(int defaultNavigation, Activity activity, final Geopoint destination) { if (destination == null) { ActivityMixin.showToast(activity, cgeoapplication.getInstance().getString(R.string.err_location_unknown)); return; } invokeApp(activity, null, null, destination, getDefaultNavigationApplication(defaultNavigation)); } /** * Returns the default navigation tool if correctly set and installed or the compass app as default fallback * * @return never null */ public static NavigationApp getDefaultNavigationApplication() { return getNavigationAppFromSetting(Settings.getDefaultNavigationTool()); } private static NavigationApp getNavigationAppFromSetting(final int defaultNavigationTool) { final List installedNavigationApps = getInstalledNavigationApps(); for (NavigationAppsEnum navigationApp : installedNavigationApps) { if (navigationApp.id == defaultNavigationTool) { return navigationApp.app; } } // default navigation tool wasn't set already or couldn't be found (not installed any more for example) return NavigationAppsEnum.COMPASS.app; } }