package cgeo.geocaching.apps.cache.navi; import cgeo.geocaching.CgeoApplication; import cgeo.geocaching.Geocache; import cgeo.geocaching.R; import cgeo.geocaching.Waypoint; import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.apps.AbstractAppFactory; import cgeo.geocaching.apps.App; import cgeo.geocaching.apps.cache.CacheBeaconApp; import cgeo.geocaching.apps.cache.WhereYouGoApp; import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationBikeApp; import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationDrivingApp; import cgeo.geocaching.apps.cache.navi.GoogleNavigationApp.GoogleNavigationWalkingApp; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.settings.Settings; import org.eclipse.jdt.annotation.Nullable; import android.app.Activity; import android.app.AlertDialog; import android.content.DialogInterface; 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, R.string.pref_navigation_menu_compass), /** The external radar app */ RADAR(new RadarApp(), 1, R.string.pref_navigation_menu_radar), /** The selected map */ INTERNAL_MAP(new InternalMap(), 2, R.string.pref_navigation_menu_internal_map), /** The internal static map activity, when stored */ STATIC_MAP(new StaticMapApp(), 3, R.string.pref_navigation_menu_static_map), /** The internal static map activity, when not yet stored */ DOWNLOAD_STATIC_MAPS(new DownloadStaticMapsApp(), 20, R.string.pref_navigation_menu_static_map_download), /** The external Locus app */ LOCUS(new LocusApp(), 4, R.string.pref_navigation_menu_locus), /** The external RMaps app */ RMAPS(new RMapsApp(), 5, R.string.pref_navigation_menu_rmaps), /** Google Maps */ GOOGLE_MAPS(new GoogleMapsApp(), 6, R.string.pref_navigation_menu_google_maps), /** Google Navigation */ GOOGLE_NAVIGATION(new GoogleNavigationDrivingApp(), 7, R.string.pref_navigation_menu_google_navigation), /** Google Streetview */ GOOGLE_STREETVIEW(new StreetviewApp(), 8, R.string.pref_navigation_menu_google_streetview), /** The external OruxMaps app */ ORUX_MAPS(new OruxMapsApp(), 9, R.string.pref_navigation_menu_oruxmaps), /** The external navigon app */ NAVIGON(new NavigonApp(), 10, R.string.pref_navigation_menu_navigon), /** The external Sygic app */ SYGIC(new SygicNavigationApp(), 11, R.string.pref_navigation_menu_sygic), /** * Google Navigation in walking mode */ GOOGLE_NAVIGATION_WALK(new GoogleNavigationWalkingApp(), 12, R.string.pref_navigation_menu_google_walk), /** * Google Navigation in walking mode */ GOOGLE_NAVIGATION_BIKE(new GoogleNavigationBikeApp(), 21, R.string.pref_navigation_menu_google_bike), /** * Google Maps Directions */ GOOGLE_MAPS_DIRECTIONS(new GoogleMapsDirectionApp(), 13, R.string.pref_navigation_menu_google_maps_directions), CACHE_BEACON(new CacheBeaconApp(), 14, R.string.pref_navigation_menu_cache_beacon), WHERE_YOU_GO(new WhereYouGoApp(), 16, R.string.pref_navigation_menu_where_you_go), PEBBLE(new PebbleApp(), 17, R.string.pref_navigation_menu_pebble), MAPSWITHME(new MapsWithMeApp(), 22, R.string.pref_navigation_menu_mapswithme); NavigationAppsEnum(final App app, final int id, final int preferenceKey) { this.app = app; this.id = id; this.preferenceKey = preferenceKey; } /** * The app instance to use */ public final App app; /** * The id - used in c:geo settings */ public final int id; /** * key of the related preference in the navigation menu preference screen, used for disabling the preference UI */ public final int preferenceKey; /* * 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, cgeo.geocaching.Geocache, cgeo.geocaching.Waypoint, 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 Geocache cache, final Waypoint 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, cgeo.geocaching.Geocache, cgeo.geocaching.Waypoint, Geopoint) */ public static void showNavigationMenu(final Activity activity, final Geocache cache, final Waypoint waypoint, final Geopoint destination, final boolean showInternalMap, final boolean showDefaultNavigation) { final List items = new ArrayList(); final int defaultNavigationTool = Settings.getDefaultNavigationTool(); for (final NavigationAppsEnum navApp : getInstalledNavigationApps()) { if ((showInternalMap || !(navApp.app instanceof InternalMap)) && (showDefaultNavigation || defaultNavigationTool != navApp.id)) { if (Settings.isUseNavigationApp(navApp)) { boolean add = false; if (cache != null && navApp.app instanceof CacheNavigationApp && navApp.app.isEnabled(cache)) { add = true; } if (waypoint != null && navApp.app instanceof WaypointNavigationApp && ((WaypointNavigationApp) navApp.app).isEnabled(waypoint)) { add = true; } if (destination != null && navApp.app instanceof GeopointNavigationApp) { add = true; } if (add) { items.add(navApp); } } } } if (items.size() == 1) { invokeNavigation(activity, cache, waypoint, destination, items.get(0).app); return; } /* * 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); final AlertDialog.Builder builder = new AlertDialog.Builder(activity); builder.setTitle(R.string.cache_menu_navigate); builder.setAdapter(adapter, new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int item) { final NavigationAppsEnum selectedItem = adapter.getItem(item); invokeNavigation(activity, cache, waypoint, destination, selectedItem.app); } }); final AlertDialog alert = builder.create(); alert.show(); } /** * Returns all installed navigation apps. * * @return */ public static List getInstalledNavigationApps() { final List installedNavigationApps = new ArrayList(); for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) { if (appEnum.app.isInstalled()) { installedNavigationApps.add(appEnum); } } return installedNavigationApps; } /** * Returns all installed navigation apps for default navigation. * * @return */ public static List getInstalledDefaultNavigationApps() { final List installedNavigationApps = new ArrayList(); for (final NavigationAppsEnum appEnum : NavigationAppsEnum.values()) { if (appEnum.app.isInstalled() && appEnum.app.isUsableAsDefaultNavigationApp()) { installedNavigationApps.add(appEnum); } } return installedNavigationApps; } /** * Handles menu selections for menu entries created with * {@link #showNavigationMenu(Activity, Geocache, Waypoint, Geopoint)}. * * @param item * @param activity * @param cache * @return */ public static boolean onMenuItemSelected(final MenuItem item, Activity activity, Geocache cache) { final App menuItem = getAppFromMenuItem(item); navigateCache(activity, cache, menuItem); return menuItem != null; } private static void navigateCache(Activity activity, Geocache cache, @Nullable App app) { if (app instanceof CacheNavigationApp) { final CacheNavigationApp cacheApp = (CacheNavigationApp) app; cacheApp.navigate(activity, cache); } } private static void navigateWaypoint(Activity activity, Waypoint waypoint, @Nullable App app) { if (app instanceof WaypointNavigationApp) { final WaypointNavigationApp waypointApp = (WaypointNavigationApp) app; waypointApp.navigate(activity, waypoint); } } private static void navigateGeopoint(Activity activity, Geopoint destination, App app) { if (app instanceof GeopointNavigationApp) { final GeopointNavigationApp geopointApp = (GeopointNavigationApp) app; geopointApp.navigate(activity, destination); } } @Nullable private static App getAppFromMenuItem(MenuItem item) { final int id = item.getItemId(); for (final NavigationAppsEnum navApp : NavigationAppsEnum.values()) { if (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, Geocache cache) { if (cache == null || cache.getCoords() == null) { ActivityMixin.showToast(activity, CgeoApplication.getInstance().getString(R.string.err_location_unknown)); return; } navigateCache(activity, cache, getDefaultNavigationApplication(defaultNavigation)); } private static App getDefaultNavigationApplication(int defaultNavigation) { if (defaultNavigation == 2) { return getNavigationAppForId(Settings.getDefaultNavigationTool2()); } return getNavigationAppForId(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, Waypoint waypoint) { if (waypoint == null || waypoint.getCoords() == null) { ActivityMixin.showToast(activity, CgeoApplication.getInstance().getString(R.string.err_location_unknown)); return; } navigateWaypoint(activity, waypoint, 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; } navigateGeopoint(activity, 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 App getDefaultNavigationApplication() { return getDefaultNavigationApplication(1); } private static App getNavigationAppForId(final int navigationAppId) { final List installedNavigationApps = getInstalledNavigationApps(); for (final NavigationAppsEnum navigationApp : installedNavigationApps) { if (navigationApp.id == navigationAppId) { 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; } private static void invokeNavigation(final Activity activity, final Geocache cache, final Waypoint waypoint, final Geopoint destination, final App app) { if (cache != null) { navigateCache(activity, cache, app); } else if (waypoint != null) { navigateWaypoint(activity, waypoint, app); } else { navigateGeopoint(activity, destination, app); } } }