diff options
| author | rsudev <rasch@munin-soft.de> | 2013-05-26 17:44:10 +0200 |
|---|---|---|
| committer | rsudev <rasch@munin-soft.de> | 2013-05-26 17:44:10 +0200 |
| commit | 8e2ec9dd830d9c5c370ae8aa77163c22364e47e0 (patch) | |
| tree | 2ed070f00896c636867b01f0c5dadf78ac2a828f /main/src/cgeo | |
| parent | ea5cfa107123deaf358bf75a7cf8835fc95acc8f (diff) | |
| download | cgeo-8e2ec9dd830d9c5c370ae8aa77163c22364e47e0.zip cgeo-8e2ec9dd830d9c5c370ae8aa77163c22364e47e0.tar.gz cgeo-8e2ec9dd830d9c5c370ae8aa77163c22364e47e0.tar.bz2 | |
Implements OKAPI access for oc.de
Enable OKAPI for opencaching.de
Enhance OKAPI to allow nearby and livemap searches
Enhance OKAPI to allow posting logs and watchlist changes
Diffstat (limited to 'main/src/cgeo')
27 files changed, 1475 insertions, 1327 deletions
diff --git a/main/src/cgeo/geocaching/CacheDetailActivity.java b/main/src/cgeo/geocaching/CacheDetailActivity.java index 273aa8c..2387622 100644 --- a/main/src/cgeo/geocaching/CacheDetailActivity.java +++ b/main/src/cgeo/geocaching/CacheDetailActivity.java @@ -1472,7 +1472,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { - handler.sendEmptyMessage(GCConnector.addToWatchlist(cache) ? 1 : -1); + handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).addToWatchlist(cache) ? 1 : -1); } } @@ -1486,7 +1486,7 @@ public class CacheDetailActivity extends AbstractViewPagerActivity<CacheDetailAc @Override public void run() { - handler.sendEmptyMessage(GCConnector.removeFromWatchlist(cache) ? 1 : -1); + handler.sendEmptyMessage(ConnectorFactory.getConnector(cache).removeFromWatchlist(cache) ? 1 : -1); } } diff --git a/main/src/cgeo/geocaching/Geocache.java b/main/src/cgeo/geocaching/Geocache.java index 5286d1c..e19d5e0 100644 --- a/main/src/cgeo/geocaching/Geocache.java +++ b/main/src/cgeo/geocaching/Geocache.java @@ -5,6 +5,7 @@ import cgeo.geocaching.activity.ActivityMixin; import cgeo.geocaching.activity.IAbstractActivity; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.ILoggingManager; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByGeocode; import cgeo.geocaching.connector.gc.GCConnector; @@ -558,6 +559,10 @@ public class Geocache implements ICache, IWaypoint { return getConnector().supportsLogging(); } + public boolean supportsLogImages() { + return getConnector().supportsLogImages(); + } + public boolean supportsOwnCoordinates() { return getConnector().supportsOwnCoordinates(); } @@ -566,6 +571,10 @@ public class Geocache implements ICache, IWaypoint { return getConnector().getCacheRealm(); } + public ILoggingManager getLoggingManager(Activity activity) { + return getConnector().getLoggingManager(activity, this); + } + @Override public float getDifficulty() { return difficulty; diff --git a/main/src/cgeo/geocaching/Settings.java b/main/src/cgeo/geocaching/Settings.java index b088415..65283da 100644 --- a/main/src/cgeo/geocaching/Settings.java +++ b/main/src/cgeo/geocaching/Settings.java @@ -40,8 +40,8 @@ import java.util.Locale; */ public final class Settings { - private static final String KEY_TEMP_TOKEN_SECRET = "temp-token-secret"; - private static final String KEY_TEMP_TOKEN_PUBLIC = "temp-token-public"; + private static final String KEY_TEMP_TWITTER_TOKEN_SECRET = "temp-token-secret"; + private static final String KEY_TEMP_TWITTER_TOKEN_PUBLIC = "temp-token-public"; private static final String KEY_HELP_SHOWN = "helper"; private static final String KEY_ANYLONGITUDE = "anylongitude"; private static final String KEY_ANYLATITUDE = "anylatitude"; @@ -112,8 +112,12 @@ public final class Settings { private static final String KEY_MAP_DIRECTORY = "mapDirectory"; private static final String KEY_CONNECTOR_GC_ACTIVE = "connectorGCActive"; private static final String KEY_CONNECTOR_OC_ACTIVE = "connectorOCActive"; - private static final String KEY_CONNECTOR_OC_USER = "connectorOCUser"; private static final String KEY_LOG_IMAGE_SCALE = "logImageScale"; + private static final String KEY_OCDE_TOKEN_SECRET = "ocde_tokensecret"; + private static final String KEY_OCDE_TOKEN_PUBLIC = "ocde_tokenpublic"; + private static final String KEY_TEMP_OCDE_TOKEN_SECRET = "ocde-temp-token-secret"; + private static final String KEY_TEMP_OCDE_TOKEN_PUBLIC = "ocde-temp-token-public"; + private final static int unitsMetric = 1; @@ -164,8 +168,8 @@ public final class Settings { final SharedPreferences old = cgeoapplication.getInstance().getSharedPreferences(oldPreferencesName, Context.MODE_PRIVATE); final Editor e = sharedPrefs.edit(); - e.putString(KEY_TEMP_TOKEN_SECRET, old.getString(KEY_TEMP_TOKEN_SECRET, null)); - e.putString(KEY_TEMP_TOKEN_PUBLIC, old.getString(KEY_TEMP_TOKEN_PUBLIC, null)); + e.putString(KEY_TEMP_TWITTER_TOKEN_SECRET, old.getString(KEY_TEMP_TWITTER_TOKEN_SECRET, null)); + e.putString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, old.getString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, null)); e.putBoolean(KEY_HELP_SHOWN, old.getInt(KEY_HELP_SHOWN, 0) != 0); e.putFloat(KEY_ANYLONGITUDE, old.getFloat(KEY_ANYLONGITUDE, 0)); e.putFloat(KEY_ANYLATITUDE, old.getFloat(KEY_ANYLATITUDE, 0)); @@ -340,26 +344,44 @@ public final class Settings { }); } - public static String getOCConnectorUserName() { - String ocConnectorUser = sharedPrefs.getString(KEY_CONNECTOR_OC_USER, null); - if (StringUtils.isBlank(ocConnectorUser)) { - return StringUtils.EMPTY; - } - return ocConnectorUser; + public static String getOCDETokenPublic() { + return sharedPrefs.getString(KEY_OCDE_TOKEN_PUBLIC, ""); } - public static boolean setOCConnectorUserName(final String userName) { - return editSharedSettings(new PrefRunnable() { + public static String getOCDETokenSecret() { + return sharedPrefs.getString(KEY_OCDE_TOKEN_SECRET, ""); + } + + public static void setOCDETokens(final String tokenPublic, final String tokenSecret, boolean enableOcDe) { + editSharedSettings(new PrefRunnable() { @Override public void edit(Editor edit) { - if (StringUtils.isBlank(userName)) { - edit.remove(KEY_CONNECTOR_OC_USER); - } else { - edit.putString(KEY_CONNECTOR_OC_USER, userName); + edit.putString(KEY_OCDE_TOKEN_PUBLIC, tokenPublic); + edit.putString(KEY_OCDE_TOKEN_SECRET, tokenSecret); + if (tokenPublic != null) { + edit.remove(KEY_TEMP_OCDE_TOKEN_PUBLIC); + edit.remove(KEY_TEMP_OCDE_TOKEN_SECRET); } } }); + setOCConnectorActive(enableOcDe); + } + + public static void setOCDETempTokens(final String tokenPublic, final String tokenSecret) { + editSharedSettings(new PrefRunnable() { + @Override + public void edit(Editor edit) { + edit.putString(KEY_TEMP_OCDE_TOKEN_PUBLIC, tokenPublic); + edit.putString(KEY_TEMP_OCDE_TOKEN_SECRET, tokenSecret); + } + }); + } + + public static ImmutablePair<String, String> getTempOCDEToken() { + String tokenPublic = sharedPrefs.getString(KEY_TEMP_OCDE_TOKEN_PUBLIC, null); + String tokenSecret = sharedPrefs.getString(KEY_TEMP_OCDE_TOKEN_SECRET, null); + return new ImmutablePair<String, String>(tokenPublic, tokenSecret); } public static boolean isGCvoteLogin() { @@ -1137,8 +1159,8 @@ public final class Settings { edit.putString(KEY_TWITTER_TOKEN_PUBLIC, tokenPublic); edit.putString(KEY_TWITTER_TOKEN_SECRET, tokenSecret); if (tokenPublic != null) { - edit.remove(KEY_TEMP_TOKEN_PUBLIC); - edit.remove(KEY_TEMP_TOKEN_SECRET); + edit.remove(KEY_TEMP_TWITTER_TOKEN_PUBLIC); + edit.remove(KEY_TEMP_TWITTER_TOKEN_SECRET); } } }); @@ -1149,15 +1171,15 @@ public final class Settings { editSharedSettings(new PrefRunnable() { @Override public void edit(Editor edit) { - edit.putString(KEY_TEMP_TOKEN_PUBLIC, tokenPublic); - edit.putString(KEY_TEMP_TOKEN_SECRET, tokenSecret); + edit.putString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, tokenPublic); + edit.putString(KEY_TEMP_TWITTER_TOKEN_SECRET, tokenSecret); } }); } public static ImmutablePair<String, String> getTempToken() { - String tokenPublic = sharedPrefs.getString(KEY_TEMP_TOKEN_PUBLIC, null); - String tokenSecret = sharedPrefs.getString(KEY_TEMP_TOKEN_SECRET, null); + String tokenPublic = sharedPrefs.getString(KEY_TEMP_TWITTER_TOKEN_PUBLIC, null); + String tokenSecret = sharedPrefs.getString(KEY_TEMP_TWITTER_TOKEN_SECRET, null); return new ImmutablePair<String, String>(tokenPublic, tokenSecret); } diff --git a/main/src/cgeo/geocaching/SettingsActivity.java b/main/src/cgeo/geocaching/SettingsActivity.java index 572ac10..aa163ad 100644 --- a/main/src/cgeo/geocaching/SettingsActivity.java +++ b/main/src/cgeo/geocaching/SettingsActivity.java @@ -5,6 +5,7 @@ import cgeo.geocaching.apps.cache.navi.NavigationAppFactory; import cgeo.geocaching.apps.cache.navi.NavigationAppFactory.NavigationAppsEnum; import cgeo.geocaching.compatibility.Compatibility; import cgeo.geocaching.connector.gc.Login; +import cgeo.geocaching.connector.oc.OCAuthorizationActivity; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.files.SimpleDirChooser; import cgeo.geocaching.maps.MapProviderFactory; @@ -169,7 +170,6 @@ public class SettingsActivity extends AbstractActivity { ((EditText) findViewById(R.id.username)).setText(""); ((EditText) findViewById(R.id.password)).setText(""); ((EditText) findViewById(R.id.passvote)).setText(""); - ((EditText) findViewById(R.id.oc_username)).setText(""); if (saveValues()) { showToast(res.getString(R.string.init_cleared)); @@ -251,10 +251,9 @@ public class SettingsActivity extends AbstractActivity { Settings.setOCConnectorActive(ocCheck.isChecked()); } }); - EditText ocUserEdit = (EditText) findViewById(R.id.oc_username); - if (ocUserEdit.getText().length() == 0) { - ocUserEdit.setText(Settings.getOCConnectorUserName()); - } + + Button checkOCUser = (Button) findViewById(R.id.register_oc_de); + checkOCUser.setOnClickListener(new OCDEAuthorizeCgeoListener()); // gcvote settings final ImmutablePair<String, String> gcvoteLogin = Settings.getGCvoteLogin(); @@ -838,7 +837,6 @@ public class SettingsActivity extends AbstractActivity { String signatureNew = ((EditText) findViewById(R.id.signature)).getText().toString(); String mapDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.map_directory)).getText().toString()); String themesDirectoryNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.themefolder)).getText().toString()); - String ocUserName = StringUtils.trimToEmpty(((EditText) findViewById(R.id.oc_username)).getText().toString()); String altitudeNew = StringUtils.trimToNull(((EditText) findViewById(R.id.altitude)).getText().toString()); int altitudeNewInt = parseNumber(altitudeNew, 0); @@ -852,7 +850,6 @@ public class SettingsActivity extends AbstractActivity { final boolean status4 = Settings.setAltCorrection(altitudeNewInt); final boolean status5 = Settings.setMapFileDirectory(mapDirectoryNew); final boolean status6 = Settings.setCustomRenderThemeBaseFolder(themesDirectoryNew); - final boolean status7 = Settings.setOCConnectorUserName(ocUserName); Settings.setShowWaypointsThreshold(waypointThreshold); String importNew = StringUtils.trimToEmpty(((EditText) findViewById(R.id.gpx_importdir)).getText().toString()); @@ -860,7 +857,7 @@ public class SettingsActivity extends AbstractActivity { Settings.setGpxImportDir(importNew); Settings.setGpxExportDir(exportNew); - return status1 && status2 && status3 && status4 && status5 && status6 && status7; + return status1 && status2 && status3 && status4 && status5 && status6; } /** @@ -929,6 +926,15 @@ public class SettingsActivity extends AbstractActivity { } } + private class OCDEAuthorizeCgeoListener implements View.OnClickListener { + + @Override + public void onClick(View v) { + Intent authIntent = new Intent(SettingsActivity.this, OCAuthorizationActivity.class); + startActivity(authIntent); + } + } + private class WebAuthListener implements View.OnClickListener { @Override diff --git a/main/src/cgeo/geocaching/VisitCacheActivity.java b/main/src/cgeo/geocaching/VisitCacheActivity.java index c19cceb..e99da8d 100644 --- a/main/src/cgeo/geocaching/VisitCacheActivity.java +++ b/main/src/cgeo/geocaching/VisitCacheActivity.java @@ -1,14 +1,13 @@ package cgeo.geocaching; -import cgeo.geocaching.connector.gc.GCParser; -import cgeo.geocaching.connector.gc.Login; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.ImageResult; +import cgeo.geocaching.connector.LogResult; import cgeo.geocaching.enumerations.LoadFlags; import cgeo.geocaching.enumerations.LogType; import cgeo.geocaching.enumerations.LogTypeTrackable; import cgeo.geocaching.enumerations.StatusCode; import cgeo.geocaching.gcvote.GCVote; -import cgeo.geocaching.loaders.UrlLoader; -import cgeo.geocaching.network.Parameters; import cgeo.geocaching.twitter.Twitter; import cgeo.geocaching.ui.Formatter; import cgeo.geocaching.ui.dialog.DateDialog; @@ -20,7 +19,6 @@ import cgeo.geocaching.utils.LogTemplateProvider.LogContext; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; import android.app.Activity; import android.app.AlertDialog; @@ -31,8 +29,6 @@ import android.content.DialogInterface.OnClickListener; import android.content.Intent; import android.net.Uri; import android.os.Bundle; -import android.support.v4.app.LoaderManager; -import android.support.v4.content.Loader; import android.util.SparseArray; import android.view.LayoutInflater; import android.view.Menu; @@ -51,7 +47,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; -public class VisitCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent, LoaderManager.LoaderCallbacks<String> { +public class VisitCacheActivity extends AbstractLoggingActivity implements DateDialog.DateDialogParent { static final String EXTRAS_GEOCODE = "geocode"; static final String EXTRAS_ID = "id"; @@ -71,7 +67,6 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD private String geocode = null; private String text = null; private List<LogType> possibleLogTypes = new ArrayList<LogType>(); - private String[] viewstates = null; private List<TrackableLog> trackables = null; private Button postButton = null; private CheckBox tweetCheck = null; @@ -79,6 +74,8 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD private boolean tbChanged = false; private SparseArray<TrackableLog> actionButtons; + private ILoggingManager loggingManager; + // Data to be saved while reconfiguring private double rating; private LogType typeSelected; @@ -87,30 +84,16 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD private String imageDescription; private Uri imageUri; - @Override - public Loader<String> onCreateLoader(final int id, final Bundle args) { - if (!Settings.isLogin()) { // allow offline logging - showToast(res.getString(R.string.err_login)); - return null; - } - return new UrlLoader(getBaseContext(), "http://www.geocaching.com/seek/log.aspx", new Parameters("ID", cacheid)); - } - @Override - public void onLoaderReset(final Loader<String> loader) { - // Nothing to do - } + public void onLoadFinished() { - @Override - public void onLoadFinished(final Loader<String> loader, final String page) { - if (page == null) { + if (loggingManager.hasLoaderError()) { showErrorLoadingData(); return; } - viewstates = Login.getViewstates(page); - trackables = GCParser.parseTrackableLog(page); - possibleLogTypes = GCParser.parseTypes(page); + trackables = loggingManager.getTrackables(); + possibleLogTypes = loggingManager.getPossibleLogTypes(); if (possibleLogTypes.isEmpty()) { showErrorLoadingData(); @@ -229,7 +212,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD if (!postButton.isEnabled()) { return res.getString(R.string.log_post_not_possible); } - if (typeSelected != LogType.FOUND_IT || !Settings.isGCvoteLogin()) { + if (typeSelected != LogType.FOUND_IT || !Settings.isGCvoteLogin() || !cache.supportsGCVote()) { return res.getString(R.string.log_post); } if (rating == 0) { @@ -295,7 +278,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } } updatePostButtonText(); - setImageButtonText(); + updateImageButton(); enablePostButton(false); final Button typeButton = (Button) findViewById(R.id.type); @@ -347,7 +330,9 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } }); - getSupportLoaderManager().initLoader(0, null, this); + loggingManager = cache.getLoggingManager(this); + + loggingManager.init(); } private void setDefaultValues() { @@ -393,7 +378,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD final EditText logView = (EditText) findViewById(R.id.log); logView.setText(StringUtils.EMPTY); - setImageButtonText(); + updateImageButton(); showToast(res.getString(R.string.info_log_cleared)); } @@ -433,7 +418,7 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD public boolean onPrepareOptionsMenu(Menu menu) { super.onPrepareOptionsMenu(menu); - final boolean voteAvailable = Settings.isGCvoteLogin() && typeSelected == LogType.FOUND_IT && StringUtils.isNotBlank(cache.getGuid()); + final boolean voteAvailable = Settings.isGCvoteLogin() && typeSelected == LogType.FOUND_IT && StringUtils.isNotBlank(cache.getGuid()) && cache.supportsGCVote(); menu.findItem(SUBMENU_VOTE).setVisible(voteAvailable); return true; @@ -536,11 +521,9 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD protected StatusCode doInBackgroundInternal(final String[] logTexts) { final String log = logTexts[0]; try { - final ImmutablePair<StatusCode, String> postResult = GCParser.postLog(geocode, cacheid, viewstates, typeSelected, - date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), - log, trackables); + final LogResult logResult = loggingManager.postLog(cache, typeSelected, date, log, trackables); - if (postResult.left == StatusCode.NO_ERROR) { + if (logResult.getPostLogResult() == StatusCode.NO_ERROR) { final LogEntry logNow = new LogEntry(date, typeSelected, log); cache.getLogs().add(0, logNow); @@ -560,17 +543,17 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD } if (StringUtils.isNotBlank(imageUri.getPath())) { - ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(postResult.right, imageCaption, imageDescription, imageUri); - final String uploadedImageUrl = imageResult.right; + ImageResult imageResult = loggingManager.postLogImage(logResult.getLogId(), imageCaption, imageDescription, imageUri); + final String uploadedImageUrl = imageResult.getImageUri(); if (StringUtils.isNotEmpty(uploadedImageUrl)) { logNow.addLogImage(new Image(uploadedImageUrl, imageCaption, imageDescription)); cgData.saveChangedCache(cache); } - return imageResult.left; + return imageResult.getPostResult(); } } - return postResult.left; + return logResult.getPostLogResult(); } catch (Exception e) { Log.e("cgeovisit.postLogFn", e); } @@ -705,14 +688,19 @@ public class VisitCacheActivity extends AbstractLoggingActivity implements DateD // Image capture failed, advise user showToast(getResources().getString(R.string.err_select_logimage_failed)); } - setImageButtonText(); + updateImageButton(); } } - private void setImageButtonText() { + private void updateImageButton() { final Button imageButton = (Button) findViewById(R.id.image_btn); - imageButton.setText(StringUtils.isNotBlank(imageUri.getPath()) ? + if (cache.supportsLogImages()) { + imageButton.setVisibility(View.VISIBLE); + imageButton.setText(StringUtils.isNotBlank(imageUri.getPath()) ? res.getString(R.string.log_image_edit) : res.getString(R.string.log_image_attach)); + } else { + imageButton.setVisibility(View.GONE); + } } } diff --git a/main/src/cgeo/geocaching/connector/AbstractConnector.java b/main/src/cgeo/geocaching/connector/AbstractConnector.java index 413291c..7b85e49 100644 --- a/main/src/cgeo/geocaching/connector/AbstractConnector.java +++ b/main/src/cgeo/geocaching/connector/AbstractConnector.java @@ -6,6 +6,8 @@ import cgeo.geocaching.geopoint.Geopoint; import org.apache.commons.lang3.StringUtils; +import android.app.Activity; + public abstract class AbstractConnector implements IConnector { @Override @@ -19,6 +21,16 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean addToWatchlist(Geocache cache) { + return false; + } + + @Override + public boolean removeFromWatchlist(Geocache cache) { + return false; + } + + @Override public boolean supportsOwnCoordinates() { return false; } @@ -54,6 +66,16 @@ public abstract class AbstractConnector implements IConnector { } @Override + public boolean supportsLogImages() { + return false; + } + + @Override + public ILoggingManager getLoggingManager(Activity activity, Geocache cache) { + return new NoLoggingManager(); + } + + @Override public String getLicenseText(final Geocache cache) { return null; } diff --git a/main/src/cgeo/geocaching/connector/ConnectorFactory.java b/main/src/cgeo/geocaching/connector/ConnectorFactory.java index 561bae2..50f56af 100644 --- a/main/src/cgeo/geocaching/connector/ConnectorFactory.java +++ b/main/src/cgeo/geocaching/connector/ConnectorFactory.java @@ -1,14 +1,15 @@ package cgeo.geocaching.connector; import cgeo.geocaching.ICache; +import cgeo.geocaching.R; import cgeo.geocaching.SearchResult; import cgeo.geocaching.Trackable; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByViewPort; import cgeo.geocaching.connector.gc.GCConnector; import cgeo.geocaching.connector.oc.OCApiConnector; +import cgeo.geocaching.connector.oc.OCApiLiveConnector; import cgeo.geocaching.connector.oc.OCConnector; -import cgeo.geocaching.connector.oc.OCXMLApiConnector; import cgeo.geocaching.connector.ox.OXConnector; import cgeo.geocaching.geopoint.Viewport; @@ -21,7 +22,7 @@ public final class ConnectorFactory { private static final UnknownConnector UNKNOWN_CONNECTOR = new UnknownConnector(); private static final IConnector[] connectors = new IConnector[] { GCConnector.getInstance(), - new OCXMLApiConnector("OpenCaching.DE", "www.opencaching.de", "OC"), + new OCApiLiveConnector("Opencaching.de", "www.opencaching.de", "OC", R.string.oc_de_okapi_consumer_key, R.string.oc_de_okapi_consumer_secret), new OCConnector("OpenCaching.CZ", "www.opencaching.cz", "OZ"), new OCApiConnector("OpenCaching.CO.UK", "www.opencaching.org.uk", "OK", "arU4okouc4GEjMniE2fq"), new OCConnector("OpenCaching.ES", "www.opencachingspain.es", "OC"), diff --git a/main/src/cgeo/geocaching/connector/IConnector.java b/main/src/cgeo/geocaching/connector/IConnector.java index 9169b4a..5d8edd9 100644 --- a/main/src/cgeo/geocaching/connector/IConnector.java +++ b/main/src/cgeo/geocaching/connector/IConnector.java @@ -5,6 +5,8 @@ import cgeo.geocaching.ICache; import cgeo.geocaching.enumerations.CacheRealm; import cgeo.geocaching.geopoint.Geopoint; +import android.app.Activity; + public interface IConnector { /** * get name for display (currently only used in links) @@ -45,6 +47,22 @@ public interface IConnector { public boolean supportsWatchList(); /** + * Add the cache to the watchlist + * + * @param cache + * @return True - success/False - failure + */ + public boolean addToWatchlist(Geocache cache); + + /** + * Remove the cache from the watchlist + * + * @param cache + * @return True - success/False - failure + */ + public boolean removeFromWatchlist(Geocache cache); + + /** * enable/disable favorite points controls in cache details * * @return @@ -59,6 +77,20 @@ public interface IConnector { public boolean supportsLogging(); /** + * enable/disable attaching image to log + * + * @return + */ + public boolean supportsLogImages(); + + /** + * Get an ILoggingManager to guide the logging process. + * + * @return + */ + public ILoggingManager getLoggingManager(Activity activity, Geocache cache); + + /** * get host name of the connector server for dynamic loading of data * * @return diff --git a/main/src/cgeo/geocaching/connector/ILoggingManager.java b/main/src/cgeo/geocaching/connector/ILoggingManager.java new file mode 100644 index 0000000..f0029f9 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/ILoggingManager.java @@ -0,0 +1,32 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.enumerations.LogType; + +import android.net.Uri; + +import java.util.Calendar; +import java.util.List; + +public interface ILoggingManager { + + LogResult postLog(Geocache cache, + LogType logType, + Calendar date, + String log, + List<TrackableLog> trackableLogs); + + ImageResult postLogImage(String logId, + String imageCaption, + String imageDescription, + Uri imageUri); + + public boolean hasLoaderError(); + + public List<TrackableLog> getTrackables(); + + public List<LogType> getPossibleLogTypes(); + + public void init(); +} diff --git a/main/src/cgeo/geocaching/connector/ImageResult.java b/main/src/cgeo/geocaching/connector/ImageResult.java new file mode 100644 index 0000000..9314cad --- /dev/null +++ b/main/src/cgeo/geocaching/connector/ImageResult.java @@ -0,0 +1,23 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.enumerations.StatusCode; + +public class ImageResult { + + private final StatusCode postResult; + private final String imageUri; + + public ImageResult(StatusCode postResult, String imageUri) { + this.postResult = postResult; + this.imageUri = imageUri; + } + + public StatusCode getPostResult() { + return postResult; + } + + public String getImageUri() { + return imageUri; + } + +} diff --git a/main/src/cgeo/geocaching/connector/LogResult.java b/main/src/cgeo/geocaching/connector/LogResult.java new file mode 100644 index 0000000..62111a4 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/LogResult.java @@ -0,0 +1,23 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.enumerations.StatusCode; + +public class LogResult { + + private final StatusCode postLogResult; + private final String logId; + + public LogResult(StatusCode postLogResult, String logId) { + this.postLogResult = postLogResult; + this.logId = logId; + } + + public StatusCode getPostLogResult() { + return postLogResult; + } + + public String getLogId() { + return logId; + } + +} diff --git a/main/src/cgeo/geocaching/connector/NoLoggingManager.java b/main/src/cgeo/geocaching/connector/NoLoggingManager.java new file mode 100644 index 0000000..bfea4ca --- /dev/null +++ b/main/src/cgeo/geocaching/connector/NoLoggingManager.java @@ -0,0 +1,46 @@ +package cgeo.geocaching.connector; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; + +import android.net.Uri; + +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public class NoLoggingManager implements ILoggingManager { + + @Override + public void init() { + // nothing to do + } + + @Override + public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) { + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) { + return new ImageResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public boolean hasLoaderError() { + return true; + } + + @Override + public List<TrackableLog> getTrackables() { + return Collections.emptyList(); + } + + @Override + public List<LogType> getPossibleLogTypes() { + return Collections.emptyList(); + } + +} diff --git a/main/src/cgeo/geocaching/connector/gc/GCConnector.java b/main/src/cgeo/geocaching/connector/gc/GCConnector.java index 33cd528..b773f66 100644 --- a/main/src/cgeo/geocaching/connector/gc/GCConnector.java +++ b/main/src/cgeo/geocaching/connector/gc/GCConnector.java @@ -7,6 +7,7 @@ import cgeo.geocaching.SearchResult; import cgeo.geocaching.Settings; import cgeo.geocaching.cgData; import cgeo.geocaching.connector.AbstractConnector; +import cgeo.geocaching.connector.ILoggingManager; import cgeo.geocaching.connector.capability.ISearchByCenter; import cgeo.geocaching.connector.capability.ISearchByGeocode; import cgeo.geocaching.connector.capability.ISearchByViewPort; @@ -20,6 +21,8 @@ import cgeo.geocaching.utils.Log; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; +import android.app.Activity; + import java.util.regex.Pattern; public class GCConnector extends AbstractConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort { @@ -78,6 +81,16 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } @Override + public boolean supportsLogImages() { + return true; + } + + @Override + public ILoggingManager getLoggingManager(Activity activity, Geocache cache) { + return new GCLoggingManager(activity, cache); + } + + @Override public String getName() { return "GeoCaching.com"; } @@ -149,7 +162,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, } - public static boolean addToWatchlist(Geocache cache) { + @Override + public boolean addToWatchlist(Geocache cache) { final boolean added = GCParser.addToWatchlist(cache); if (added) { cgData.saveChangedCache(cache); @@ -157,7 +171,8 @@ public class GCConnector extends AbstractConnector implements ISearchByGeocode, return added; } - public static boolean removeFromWatchlist(Geocache cache) { + @Override + public boolean removeFromWatchlist(Geocache cache) { final boolean removed = GCParser.removeFromWatchlist(cache); if (removed) { cgData.saveChangedCache(cache); diff --git a/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java new file mode 100644 index 0000000..334a8e4 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java @@ -0,0 +1,135 @@ +package cgeo.geocaching.connector.gc; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.VisitCacheActivity; +import cgeo.geocaching.activity.ActivityMixin; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.ImageResult; +import cgeo.geocaching.connector.LogResult; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.loaders.UrlLoader; +import cgeo.geocaching.network.Parameters; +import cgeo.geocaching.utils.Log; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import android.app.Activity; +import android.net.Uri; +import android.os.Bundle; +import android.support.v4.app.LoaderManager; +import android.support.v4.content.Loader; + +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public class GCLoggingManager implements ILoggingManager, LoaderManager.LoaderCallbacks<String> { + + private final VisitCacheActivity activity; + private final Geocache cache; + + private String[] viewstates; + private List<TrackableLog> trackables; + private List<LogType> possibleLogTypes; + private boolean hasLoaderError = true; + + public GCLoggingManager(Activity activity, Geocache cache) { + this.activity = (VisitCacheActivity) activity; + this.cache = cache; + } + + @Override + public Loader<String> onCreateLoader(int arg0, Bundle arg1) { + if (!Settings.isLogin()) { // allow offline logging + ActivityMixin.showToast(activity, activity.getResources().getString(R.string.err_login)); + return null; + } + return new UrlLoader(activity.getBaseContext(), "http://www.geocaching.com/seek/log.aspx", new Parameters("ID", cache.getCacheId())); + } + + @Override + public void onLoadFinished(Loader<String> arg0, String page) { + if (page == null) { + hasLoaderError = true; + } else { + + viewstates = Login.getViewstates(page); + trackables = GCParser.parseTrackableLog(page); + possibleLogTypes = GCParser.parseTypes(page); + + if (possibleLogTypes.isEmpty()) { + hasLoaderError = true; + } else { + hasLoaderError = false; + } + } + + activity.onLoadFinished(); + } + + @Override + public void onLoaderReset(Loader<String> arg0) { + // nothing to do + } + + @Override + public void init() { + activity.getSupportLoaderManager().initLoader(0, null, this); + } + + @Override + public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) { + + try { + final ImmutablePair<StatusCode, String> postResult = GCParser.postLog(cache.getGeocode(), cache.getCacheId(), viewstates, logType, + date.get(Calendar.YEAR), (date.get(Calendar.MONTH) + 1), date.get(Calendar.DATE), + log, trackableLogs); + + return new LogResult(postResult.left, postResult.right); + } catch (Exception e) { + Log.e("GCLoggingManager.postLog", e); + } + + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) { + + if (StringUtils.isNotBlank(imageUri.getPath())) { + + ImmutablePair<StatusCode, String> imageResult = GCParser.uploadLogImage(logId, imageCaption, imageDescription, imageUri); + + return new ImageResult(imageResult.left, imageResult.right); + } + + return new ImageResult(StatusCode.LOGIMAGE_POST_ERROR, ""); + } + + @Override + public boolean hasLoaderError() { + return hasLoaderError; + } + + @Override + public List<TrackableLog> getTrackables() { + if (hasLoaderError) { + return Collections.emptyList(); + } + return trackables; + } + + @Override + public List<LogType> getPossibleLogTypes() { + if (hasLoaderError) { + return Collections.emptyList(); + } + return possibleLogTypes; + } + +} diff --git a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java b/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java deleted file mode 100644 index d03062f..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java +++ /dev/null @@ -1,762 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.Geocache; -import cgeo.geocaching.Image; -import cgeo.geocaching.LogEntry; -import cgeo.geocaching.R; -import cgeo.geocaching.Settings; -import cgeo.geocaching.cgeoapplication; -import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.IConnector; -import cgeo.geocaching.connector.gc.GCConnector; -import cgeo.geocaching.enumerations.CacheAttribute; -import cgeo.geocaching.enumerations.CacheSize; -import cgeo.geocaching.enumerations.CacheType; -import cgeo.geocaching.enumerations.LogType; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.utils.Log; - -import org.apache.commons.lang3.StringUtils; -import org.xml.sax.Attributes; -import org.xml.sax.SAXException; - -import android.content.res.Resources; -import android.sax.Element; -import android.sax.EndElementListener; -import android.sax.EndTextElementListener; -import android.sax.RootElement; -import android.sax.StartElementListener; -import android.util.Xml; - -import java.io.IOException; -import java.io.InputStream; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Locale; -import java.util.Map; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -public class OC11XMLParser { - - private static final String[] MARKUP = new String[] { "p", "span" }; - private static Pattern STRIP_DATE = Pattern.compile("\\+0([0-9]){1}\\:00"); - private static Pattern LOCAL_URL = Pattern.compile("href=\"(.*)\""); - private static final int CACHE_PARSE_LIMIT = 250; - private static final Resources res = cgeoapplication.getInstance().getResources(); - private static final Pattern WHITESPACE = Pattern.compile("<p>(\\s| )*</p>"); - - - private static ImageHolder imageHolder = null; - - private static class CacheHolder { - public Geocache cache; - public String latitude; - public String longitude; - } - - private static class CacheLog { - public String id; - public String cacheId; - public LogEntry logEntry; - } - - private static class CacheDescription { - public String cacheId; - public String shortDesc; - public String desc; - public String hint; - } - - private static class ImageHolder { - public String url; - public String objectId; - protected String title; - protected boolean isSpoiler = false; - } - - private static Date parseFullDate(final String date) { - final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US); - ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100"); - try { - return ISO8601DATEFORMAT.parse(strippedDate); - } catch (ParseException e) { - Log.e("OC11XMLParser.parseFullDate", e); - } - return null; - } - - private static Date parseDayDate(final String date) { - final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd", Locale.US); - ISO8601DATEFORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); - final String strippedDate = STRIP_DATE.matcher(date).replaceAll("+0$100"); - try { - return ISO8601DATEFORMAT.parse(strippedDate); - } catch (ParseException e) { - Log.e("OC11XMLParser.parseDayDate", e); - } - return null; - } - - private static CacheSize getCacheSize(final String sizeId) { - try { - int size = Integer.parseInt(sizeId); - - switch (size) { - case 1: - return CacheSize.OTHER; - case 2: - return CacheSize.MICRO; - case 3: - return CacheSize.SMALL; - case 4: - return CacheSize.REGULAR; - case 5: - case 6: - return CacheSize.LARGE; - case 8: - return CacheSize.VIRTUAL; - default: - break; - } - } catch (NumberFormatException e) { - Log.e("OC11XMLParser.getCacheSize", e); - } - return CacheSize.NOT_CHOSEN; - } - - private static CacheType getCacheType(final String typeId) { - try { - int type = Integer.parseInt(typeId); - switch (type) { - case 1: // Other/unbekannter Cachetyp - return CacheType.UNKNOWN; - case 2: // Trad./normaler Cache - return CacheType.TRADITIONAL; - case 3: // Multi/Multicache - return CacheType.MULTI; - case 4: // Virt./virtueller Cache - return CacheType.VIRTUAL; - case 5: // ICam./Webcam-Cache - return CacheType.WEBCAM; - case 6: // Event/Event-Cache - return CacheType.EVENT; - case 7: // Quiz/Rätselcache - return CacheType.MYSTERY; - case 8: // Math/Mathe-/Physikcache - return CacheType.MYSTERY; - case 9: // Moving/beweglicher Cache - return CacheType.VIRTUAL; - case 10: // Driv./Drive-In - return CacheType.TRADITIONAL; - default: - return CacheType.UNKNOWN; - } - } catch (NumberFormatException e) { - Log.e("OC11XMLParser.getCacheType", e); - } - return CacheType.UNKNOWN; - } - - private static LogType getLogType(final int typeId) { - switch (typeId) { - case 1: - return LogType.FOUND_IT; - case 2: - return LogType.DIDNT_FIND_IT; - case 3: - return LogType.NOTE; - case 7: - return LogType.ATTENDED; - case 8: - return LogType.WILL_ATTEND; - default: - return LogType.UNKNOWN; - } - } - - private static void setCacheStatus(final int statusId, final Geocache cache) { - switch (statusId) { - case 1: - cache.setArchived(false); - cache.setDisabled(false); - break; - case 2: - cache.setArchived(false); - cache.setDisabled(true); - break; - default: - cache.setArchived(true); - cache.setDisabled(false); - break; - } - } - - private static void resetCache(final CacheHolder cacheHolder) { - cacheHolder.cache = new Geocache(null); - cacheHolder.cache.setReliableLatLon(true); - cacheHolder.cache.setDescription(StringUtils.EMPTY); - cacheHolder.latitude = "0.0"; - cacheHolder.longitude = "0.0"; - } - - private static void resetLog(final CacheLog log) { - log.cacheId = StringUtils.EMPTY; - log.logEntry = new LogEntry("", 0, LogType.UNKNOWN, ""); - } - - private static void resetDesc(final CacheDescription desc) { - desc.cacheId = StringUtils.EMPTY; - desc.shortDesc = StringUtils.EMPTY; - desc.desc = StringUtils.EMPTY; - desc.hint = StringUtils.EMPTY; - } - - private static int attributeId; - - public static Collection<Geocache> parseCaches(final InputStream stream) throws IOException { - // parse and return caches without filtering - return parseCaches(stream, true); - } - - public static Collection<Geocache> parseCachesFiltered(final InputStream stream) throws IOException { - // parse caches and filter result - return parseCaches(stream, false); - } - - private static Collection<Geocache> parseCaches(final InputStream stream, boolean ignoreFiltersIn) throws IOException { - - final Map<String, Geocache> caches = new HashMap<String, Geocache>(); - final Map<String, LogEntry> logs = new HashMap<String, LogEntry>(); - - final CacheHolder cacheHolder = new CacheHolder(); - final CacheLog logHolder = new CacheLog(); - final CacheDescription descHolder = new CacheDescription(); - - final RootElement root = new RootElement("oc11xml"); - final Element cacheNode = root.getChild("cache"); - - final boolean ignoreFilters = ignoreFiltersIn; - - // cache - cacheNode.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - resetCache(cacheHolder); - } - - }); - - cacheNode.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - Geocache cache = cacheHolder.cache; - Geopoint coords = new Geopoint(cacheHolder.latitude, cacheHolder.longitude); - cache.setCoords(coords); - if (caches.size() < CACHE_PARSE_LIMIT && isValid(cache) && (ignoreFilters || !isExcluded(cache))) { - cache.setDetailedUpdatedNow(); - caches.put(cache.getCacheId(), cache); - } - } - - private boolean isExcluded(Geocache cache) { - if (cache.isArchived()) { - return true; - } - if (cache.isDisabled() && Settings.isExcludeDisabledCaches()) { - return true; - } - if ((cache.isFound() || cache.isOwner()) && Settings.isExcludeMyCaches()) { - return true; - } - return !Settings.getCacheType().contains(cache); - } - - private boolean isValid(Geocache cache) { - return StringUtils.isNotBlank(cache.getGeocode()) && !cache.getCoords().equals(Geopoint.ZERO); - } - }); - - // cache.id - cacheNode.getChild("id").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - cacheHolder.cache.setCacheId(body); - } - }); - - // cache.longitude - cacheNode.getChild("longitude").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - String longitude = body.trim(); - if (StringUtils.isNotBlank(longitude)) { - cacheHolder.longitude = longitude; - } - } - }); - - // cache.latitude - cacheNode.getChild("latitude").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - String latitude = body.trim(); - if (StringUtils.isNotBlank(latitude)) { - cacheHolder.latitude = latitude; - } - } - }); - - // cache.name - cacheNode.getChild("name").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - cacheHolder.cache.setName(content); - } - }); - - // cache.waypoints[oc] - cacheNode.getChild("waypoints").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("oc") > -1) { - cacheHolder.cache.setGeocode(attrs.getValue("oc")); - } - if (attrs.getIndex("gccom") > -1) { - String gccode = attrs.getValue("gccom"); - if (!StringUtils.isBlank(gccode)) { - cacheHolder.cache.setDescription(res.getString(R.string.cache_listed_on, GCConnector.getInstance().getName()) + ": <a href=\"http://coord.info/" + gccode + "\">" + gccode + "</a><br /><br />"); - } - } - } - }); - - // cache.type[id] - cacheNode.getChild("type").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - final String typeId = attrs.getValue("id"); - cacheHolder.cache.setType(getCacheType(typeId)); - } - } - }); - - // cache.status[id] - cacheNode.getChild("status").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - try { - final int statusId = Integer.parseInt(attrs.getValue("id")); - setCacheStatus(statusId, cacheHolder.cache); - } catch (NumberFormatException e) { - Log.w(String.format("Failed to parse status of cache '%s'.", cacheHolder.cache.getGeocode())); - } - } - } - }); - - // cache.size[id] - cacheNode.getChild("size").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - final String typeId = attrs.getValue("id"); - cacheHolder.cache.setSize(getCacheSize(typeId)); - } - } - }); - - // cache.difficulty - cacheNode.getChild("difficulty").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - try { - cacheHolder.cache.setDifficulty(Float.valueOf(content)); - } catch (NumberFormatException e) { - Log.e("OC11XMLParser: unknown difficulty " + content, e); - } - } - }); - - // cache.terrain - cacheNode.getChild("terrain").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - try { - cacheHolder.cache.setTerrain(Float.valueOf(content)); - } catch (NumberFormatException e) { - Log.e("OC11XMLParser: unknown terrain " + content, e); - } - } - }); - - // cache.datehidden - cacheNode.getChild("datehidden").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - cacheHolder.cache.setHidden(parseFullDate(content)); - } - }); - - // cache.userid - final Element useridNode = cacheNode.getChild("userid"); - - useridNode.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - if (attributes.getIndex("id") > -1) { - cacheHolder.cache.setOwnerUserId(attributes.getValue("id")); - } - } - }); - - useridNode.setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - cacheHolder.cache.setOwnerDisplayName(body); - } - }); - - // cache.attributes.attribute - final Element attributeNode = cacheNode.getChild("attributes").getChild("attribute"); - - attributeNode.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - if (attributes.getIndex("id") > -1) { - try { - attributeId = Integer.parseInt(attributes.getValue("id")); - } catch (NumberFormatException e) { - Log.w(String.format("Failed to parse attribute id of cache '%s'.", cacheHolder.cache.getGeocode())); - } - } - } - }); - - attributeNode.setEndTextElementListener(new EndTextElementListener() { - @Override - public void end(String body) { - CacheAttribute attribute = CacheAttribute.getByOcId(attributeId); - if (attribute != null) { - // semantic of attributes on opencaching is always "yes" - cacheHolder.cache.getAttributes().add(attribute.getAttributeName(true)); - } - else { - if (StringUtils.isNotBlank(body)) { - cacheHolder.cache.getAttributes().add(body.trim()); - } - } - } - }); - - // cachedesc - final Element cacheDesc = root.getChild("cachedesc"); - - cacheDesc.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - resetDesc(descHolder); - } - }); - - cacheDesc.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - final Geocache cache = caches.get(descHolder.cacheId); - if (cache != null) { - cache.setShortDescription(descHolder.shortDesc); - cache.setDescription(cache.getDescription() + descHolder.desc); - cache.setHint(descHolder.hint); - } - } - }); - - // cachedesc.cacheid - cacheDesc.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - descHolder.cacheId = body; - } - }); - - // cachedesc.desc - cacheDesc.getChild("shortdesc").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - descHolder.shortDesc = linkify(stripEmptyText(content)); - } - }); - - // cachedesc.desc - cacheDesc.getChild("desc").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - final String content = body.trim(); - descHolder.desc = linkify(stripEmptyText(content)); - } - }); - - // cachedesc.hint - cacheDesc.getChild("hint").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - descHolder.hint = body.trim(); - } - }); - - // cachelog - final Element cacheLog = root.getChild("cachelog"); - - cacheLog.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - resetLog(logHolder); - } - }); - - cacheLog.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - final Geocache cache = caches.get(logHolder.cacheId); - if (cache != null && logHolder.logEntry.type != LogType.UNKNOWN) { - logs.put(logHolder.id, logHolder.logEntry); - cache.getLogs().add(0, logHolder.logEntry); - if ((logHolder.logEntry.type == LogType.FOUND_IT || logHolder.logEntry.type == LogType.ATTENDED) - && StringUtils.equalsIgnoreCase(logHolder.logEntry.author, Settings.getOCConnectorUserName())) { - cache.setFound(true); - cache.setVisitedDate(logHolder.logEntry.date); - } - } - } - }); - - // cachelog.id - cacheLog.getChild("id").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - logHolder.id = StringUtils.trim(body); - } - }); - - // cachelog.cacheid - cacheLog.getChild("cacheid").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - logHolder.cacheId = body; - } - }); - - // cachelog.date - cacheLog.getChild("date").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - try { - logHolder.logEntry.date = parseDayDate(body).getTime(); - } catch (NullPointerException e) { - Log.w("Failed to parse log date", e); - } - } - }); - - // cachelog.logtype - cacheLog.getChild("logtype").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - if (attrs.getIndex("id") > -1) { - final String id = attrs.getValue("id"); - try { - final int typeId = Integer.parseInt(id); - logHolder.logEntry.type = getLogType(typeId); - } catch (NumberFormatException e) { - Log.e("OC11XMLParser, unknown logtype " + id, e); - } - } - } - }); - - // cachelog.userid - cacheLog.getChild("userid").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String finderName) { - logHolder.logEntry.author = finderName; - } - }); - - // cachelog.text - cacheLog.getChild("text").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String logText) { - logHolder.logEntry.log = stripEmptyText(logText); - } - }); - - // pictures - final Element picture = root.getChild("picture"); - - picture.setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attrs) { - imageHolder = new ImageHolder(); - } - }); - - picture.setEndElementListener(new EndElementListener() { - - @Override - public void end() { - if (imageHolder.isSpoiler) { - final Geocache cache = caches.get(imageHolder.objectId); - if (cache != null) { - Image spoiler = new Image(imageHolder.url, imageHolder.title); - cache.addSpoiler(spoiler); - } - } - else { - final LogEntry log = logs.get(imageHolder.objectId); - if (log != null) { - log.addLogImage(new Image(imageHolder.url, imageHolder.title)); - } - } - } - }); - - // picture.object - picture.getChild("object").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - imageHolder.objectId = StringUtils.trim(body); - } - }); - - // picture.title - picture.getChild("title").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - imageHolder.title = StringUtils.trim(body); - } - }); - - // picture.url - picture.getChild("url").setEndTextElementListener(new EndTextElementListener() { - - @Override - public void end(String body) { - imageHolder.url = StringUtils.trim(body); - } - }); - - // picture.attributes - picture.getChild("attributes").setStartElementListener(new StartElementListener() { - - @Override - public void start(Attributes attributes) { - if (attributes.getIndex("spoiler") > -1) { - String spoiler = attributes.getValue("spoiler"); - imageHolder.isSpoiler = ("1".equals(spoiler)); - } - } - }); - - try { - Xml.parse(stream, Xml.Encoding.UTF_8, root.getContentHandler()); - return caches.values(); - } catch (SAXException e) { - Log.e("Cannot parse .gpx file as oc11xml: could not parse XML", e); - return null; - } - } - - /** - * Converts local links to absolute links targeting the OC website. - */ - private static String linkify(String input) { - String result = input; - Matcher matcher = LOCAL_URL.matcher(result); - while (matcher.find()) { - String url = matcher.group(1); - if (!url.contains(":/")) { - IConnector ocConnector = ConnectorFactory.getConnector("OCXXX"); - String prefix = "http://" + ocConnector.getHost() + "/"; - result = StringUtils.replace(result, url, prefix + url); - matcher = LOCAL_URL.matcher(result); - } - } - return result; - } - - /** - * Removes some unneeded markup and whitespace. Log texts are typically encapsulated in paragraph tags which lead to - * more empty space on rendering. - */ - protected static String stripEmptyText(String input) { - final Matcher matcher = WHITESPACE.matcher(input); - String result = matcher.replaceAll("").trim(); - if (!StringUtils.startsWith(result, "<")) { - return result; - } - return stripMarkup(result); - } - - private static String stripMarkup(final String input) { - String result = input; - for (String tagName : MARKUP) { - final String startTag = "<" + tagName + ">"; - if (StringUtils.startsWith(result, startTag)) { - final String endTag = "</" + tagName + ">"; - if (StringUtils.endsWith(result, endTag)) { - String inner = result.substring(startTag.length(), result.length() - endTag.length()).trim(); - String nested = stripMarkup(inner); - if (!nested.contains(startTag)) { - result = nested; - } - } - } - } - return result; - } -}
\ No newline at end of file diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java index 69cf8a4..a236a0e 100644 --- a/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java +++ b/main/src/cgeo/geocaching/connector/oc/OCApiConnector.java @@ -23,7 +23,7 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode { @Override public String getLicenseText(final Geocache cache) { // NOT TO BE TRANSLATED - return "<a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a> data licensed under the Creative Commons BY-SA 3.0 License"; + return "©" + cache.getOwnerDisplayName() + ", <a href=\"" + getCacheUrl(cache) + "\">" + getName() + "</a>, CC-BY-NC-ND, alle Logeinträge © jeweiliger Autor"; } @Override @@ -40,4 +40,8 @@ public class OCApiConnector extends OCConnector implements ISearchByGeocode { // currently always active, but only for details download return true; } + + public String getCK() { + return CryptUtils.rot13(cK); + } } diff --git a/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java new file mode 100644 index 0000000..a578aac --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java @@ -0,0 +1,78 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.SearchResult; +import cgeo.geocaching.cgData; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.capability.ISearchByCenter; +import cgeo.geocaching.connector.capability.ISearchByViewPort; +import cgeo.geocaching.geopoint.Geopoint; +import cgeo.geocaching.geopoint.Viewport; +import cgeo.geocaching.utils.CryptUtils; + +import android.app.Activity; + +public class OCApiLiveConnector extends OCApiConnector implements ISearchByCenter, ISearchByViewPort { + + private String cS; + + public OCApiLiveConnector(String name, String host, String prefix, int cKResId, int cSResId) { + super(name, host, prefix, CryptUtils.rot13(cgeoapplication.getInstance().getResources().getString(cKResId))); + + cS = CryptUtils.rot13(cgeoapplication.getInstance().getResources().getString(cSResId)); + } + + @Override + public SearchResult searchByViewport(Viewport viewport, String[] tokens) { + return new SearchResult(OkapiClient.getCachesBBox(viewport, this)); + } + + @Override + public SearchResult searchByCenter(Geopoint center) { + + return new SearchResult(OkapiClient.getCachesAround(center, this)); + } + + public String getCS() { + return CryptUtils.rot13(cS); + } + + @Override + public boolean supportsWatchList() { + return true; + } + + @Override + public boolean addToWatchlist(Geocache cache) { + final boolean added = OkapiClient.setWatchState(cache, true, this); + + if (added) { + cgData.saveChangedCache(cache); + } + + return added; + } + + @Override + public boolean removeFromWatchlist(Geocache cache) { + final boolean removed = OkapiClient.setWatchState(cache, false, this); + + if (removed) { + cgData.saveChangedCache(cache); + } + + return removed; + } + + @Override + public boolean supportsLogging() { + return true; + } + + @Override + public ILoggingManager getLoggingManager(Activity activity, Geocache cache) { + return new OkapiLoggingManager(activity, this, cache); + } + +} diff --git a/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java new file mode 100644 index 0000000..779c1c5 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java @@ -0,0 +1,109 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.cgeoapplication; +import cgeo.geocaching.network.OAuthAuthorizationActivity; + +import org.apache.commons.lang3.tuple.ImmutablePair; + +public class OCAuthorizationActivity extends OAuthAuthorizationActivity { + + private final int siteResId = R.string.auth_ocde; + + public OCAuthorizationActivity() { + super("www.opencaching.de", + "/okapi/services/oauth/request_token", + "/okapi/services/oauth/authorize", + "/okapi/services/oauth/access_token", + false, + cgeoapplication.getInstance().getResources().getString(R.string.oc_de_okapi_consumer_key), + cgeoapplication.getInstance().getResources().getString(R.string.oc_de_okapi_consumer_secret)); + } + + @Override + protected ImmutablePair<String, String> getTempToken() { + return Settings.getTempOCDEToken(); + } + + @Override + protected void setTempTokens(String tokenPublic, String tokenSecret) { + Settings.setOCDETempTokens(tokenPublic, tokenSecret); + } + + @Override + protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) { + Settings.setOCDETokens(tokenPublic, tokenSecret, enable); + } + + @Override + protected String getAuthTitle() { + return res.getString(siteResId); + } + + @Override + protected String getAuthAgain() { + return res.getString(R.string.auth_again_oc); + } + + @Override + protected String getErrAuthInitialize() { + return res.getString(R.string.err_auth_initialize); + } + + @Override + protected String getAuthStart() { + return res.getString(R.string.auth_start_oc); + } + + @Override + protected String getAuthDialogCompleted() { + return res.getString(R.string.auth_dialog_completed_oc, getAuthTitle()); + } + + @Override + protected String getErrAuthProcess() { + return res.getString(R.string.err_auth_process); + } + + @Override + protected String getAuthDialogWait() { + return res.getString(R.string.auth_dialog_wait_oc, getAuthTitle()); + } + + @Override + protected String getAuthDialogPinTitle() { + return res.getString(R.string.auth_dialog_pin_title_oc); + } + + @Override + protected String getAuthDialogPinMessage() { + return res.getString(R.string.auth_dialog_pin_message_oc, getAuthTitle()); + } + + @Override + protected String getAboutAuth1() { + return res.getString(R.string.about_auth_1_oc, getAuthTitle()); + } + + @Override + protected String getAboutAuth2() { + return res.getString(R.string.about_auth_2_oc, getAuthTitle(), getAuthTitle()); + } + + @Override + protected String getAuthAuthorize() { + return res.getString(R.string.auth_authorize_oc); + } + + @Override + protected String getAuthPinHint() { + return res.getString(R.string.auth_pin_hint_oc, getAuthTitle()); + } + + @Override + protected String getAuthFinish() { + return res.getString(R.string.auth_finish_oc); + } + +} diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java b/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java deleted file mode 100644 index 43fdcfc..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java +++ /dev/null @@ -1,67 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.Geocache; -import cgeo.geocaching.ICache; -import cgeo.geocaching.SearchResult; -import cgeo.geocaching.Settings; -import cgeo.geocaching.connector.capability.ISearchByCenter; -import cgeo.geocaching.connector.capability.ISearchByGeocode; -import cgeo.geocaching.connector.capability.ISearchByViewPort; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.Viewport; -import cgeo.geocaching.ui.Formatter; -import cgeo.geocaching.utils.CancellableHandler; - -import org.apache.commons.lang3.StringUtils; - -public class OCXMLApiConnector extends OCConnector implements ISearchByGeocode, ISearchByCenter, ISearchByViewPort { - - private final static double SEARCH_DISTANCE_LIMIT = 15.0; - private final static double NEARBY_SEARCH_DISTANCE = 5.0; - - public OCXMLApiConnector(String name, String host, String prefix) { - super(name, host, prefix); - } - - @Override - public SearchResult searchByGeocode(final String geocode, final String guid, CancellableHandler handler) { - final Geocache cache = OCXMLClient.getCache(geocode); - if (cache == null) { - return null; - } - return new SearchResult(cache); - } - - @Override - public SearchResult searchByCenter(final Geopoint center) { - return new SearchResult(OCXMLClient.getCachesAround(center, NEARBY_SEARCH_DISTANCE)); - } - - @Override - public SearchResult searchByViewport(final Viewport viewport, final String[] tokens) { - final Geopoint center = viewport.getCenter(); - double distance = center.distanceTo(viewport.bottomLeft) * 1.15; - if (distance > SEARCH_DISTANCE_LIMIT) { - distance = SEARCH_DISTANCE_LIMIT; - } - return new SearchResult(OCXMLClient.getCachesAround(center, distance)); - } - - @Override - public boolean isActivated() { - // currently only tested and working with oc.de - return Settings.isOCConnectorActive(); - } - - @Override - public boolean isOwner(ICache cache) { - return StringUtils.equalsIgnoreCase(cache.getOwnerDisplayName(), Settings.getOCConnectorUserName()); - } - - @Override - public String getLicenseText(Geocache cache) { - // not to be translated - return "© " + cache.getOwnerDisplayName() + ", " + "<a href=\"" + getCacheUrl(cache) + "\">www.opencaching.de</a>, CC-BY-NC-ND, Stand: " + Formatter.formatFullDate(cache.getUpdated()); - } - -} diff --git a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java b/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java deleted file mode 100644 index df75682..0000000 --- a/main/src/cgeo/geocaching/connector/oc/OCXMLClient.java +++ /dev/null @@ -1,122 +0,0 @@ -package cgeo.geocaching.connector.oc; - -import cgeo.geocaching.Geocache; -import cgeo.geocaching.cgData; -import cgeo.geocaching.connector.ConnectorFactory; -import cgeo.geocaching.connector.IConnector; -import cgeo.geocaching.enumerations.LoadFlags; -import cgeo.geocaching.geopoint.Geopoint; -import cgeo.geocaching.geopoint.GeopointFormatter; -import cgeo.geocaching.network.Network; -import cgeo.geocaching.network.Parameters; -import cgeo.geocaching.utils.IOUtils; -import cgeo.geocaching.utils.Log; - -import ch.boye.httpclientandroidlib.HttpResponse; - -import org.apache.commons.lang3.StringUtils; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Collection; -import java.util.Collections; -import java.util.Locale; -import java.util.zip.GZIPInputStream; - -public class OCXMLClient { - - private static final String SERVICE_CACHE = "/xml/ocxml11.php"; - - // Url for single cache requests - // http://www.opencaching.de/xml/ocxml11.php?modifiedsince=20060320000000&user=0&cache=1&cachedesc=1&cachelog=1&picture=1&removedobject=0&session=0&doctype=0&charset=utf-8&wp=OCC9BE - - public static Geocache getCache(final String geoCode) { - try { - final Parameters params = getOCXmlQueryParameters(true, true, true); - params.put("wp", geoCode); - final InputStream data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params); - - if (data == null) { - return null; - } - - final BufferedInputStream stream = new BufferedInputStream(new GZIPInputStream(data)); - Collection<Geocache> caches = OC11XMLParser.parseCaches(stream); - if (caches.iterator().hasNext()) { - Geocache cache = caches.iterator().next(); - cgData.saveCache(cache, LoadFlags.SAVE_ALL); - IOUtils.closeQuietly(stream); - return cache; - } - return null; - } catch (IOException e) { - Log.e("Error parsing cache '" + geoCode + "'", e); - return null; - } - } - - public static Collection<Geocache> getCachesAround(final Geopoint center, final double distance) { - try { - final Parameters params = getOCXmlQueryParameters(false, false, false); - params.put("lat", GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center)); - params.put("lon", GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center)); - params.put("distance", String.format(Locale.US, "%f", distance)); - final InputStream data = request(ConnectorFactory.getConnector("OCXXX"), SERVICE_CACHE, params); - - if (data == null) { - return Collections.emptyList(); - } - - final BufferedInputStream stream = new BufferedInputStream(new GZIPInputStream(data)); - final Collection<Geocache> result = OC11XMLParser.parseCachesFiltered(stream); - IOUtils.closeQuietly(stream); - return result; - } catch (IOException e) { - Log.e("Error parsing nearby search result", e); - return Collections.emptyList(); - } - } - - private static InputStream request(final IConnector connector, final String service, final Parameters params) { - if (connector == null) { - return null; - } - if (!(connector instanceof OCXMLApiConnector)) { - return null; - } - - final String host = connector.getHost(); - if (StringUtils.isBlank(host)) { - return null; - } - - final String uri = "http://" + host + service; - HttpResponse resp = Network.getRequest(uri, params); - if (resp != null) { - try { - return resp.getEntity().getContent(); - } catch (IllegalStateException e) { - // fall through and return null - } catch (IOException e) { - // fall through and return null - } - } - return null; - } - - private static Parameters getOCXmlQueryParameters(final boolean withDescription, final boolean withLogs, final boolean withImages) { - return new Parameters("modifiedsince", "20000101000000", - "user", "0", - "cache", "1", - "cachedesc", withDescription ? "1" : "0", - "cachelog", withLogs ? "1" : "0", - "picture", withImages ? "1" : "0", - "removedobject", "0", - "session", "0", - "doctype", "0", - "charset", "utf-8", - "zip", "gzip", - "picturefromcachelog", withImages ? "1" : "0"); - } -} diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java index 0673605..3224549 100644 --- a/main/src/cgeo/geocaching/connector/oc/OkapiClient.java +++ b/main/src/cgeo/geocaching/connector/oc/OkapiClient.java @@ -3,16 +3,27 @@ package cgeo.geocaching.connector.oc; import cgeo.geocaching.Geocache; import cgeo.geocaching.Image; import cgeo.geocaching.LogEntry; +import cgeo.geocaching.R; +import cgeo.geocaching.Settings; +import cgeo.geocaching.Waypoint; import cgeo.geocaching.cgData; +import cgeo.geocaching.cgeoapplication; import cgeo.geocaching.connector.ConnectorFactory; import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.LogResult; +import cgeo.geocaching.connector.gc.GCConnector; +import cgeo.geocaching.enumerations.CacheAttribute; import cgeo.geocaching.enumerations.CacheSize; import cgeo.geocaching.enumerations.CacheType; import cgeo.geocaching.enumerations.LoadFlags.SaveFlag; import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; +import cgeo.geocaching.enumerations.WaypointType; import cgeo.geocaching.geopoint.Geopoint; import cgeo.geocaching.geopoint.GeopointFormatter; +import cgeo.geocaching.geopoint.Viewport; import cgeo.geocaching.network.Network; +import cgeo.geocaching.network.OAuth; import cgeo.geocaching.network.Parameters; import cgeo.geocaching.utils.Log; @@ -27,12 +38,36 @@ import android.text.Html; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collections; import java.util.Date; import java.util.EnumSet; +import java.util.Iterator; +import java.util.LinkedHashMap; import java.util.List; import java.util.Locale; +import java.util.Map; +import java.util.TimeZone; final public class OkapiClient { + + private static final SimpleDateFormat logDateFormat; + + static { + logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ", Locale.US); + logDateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + } + + private static final String CACHE_ATTRNAMES = "attrnames"; + private static final String WPT_LOCATION = "location"; + private static final String WPT_DESCRIPTION = "description"; + private static final String WPT_TYPE = "type"; + private static final String WPT_NAME = "name"; + private static final String CACHE_IS_WATCHED = "is_watched"; + private static final String CACHE_WPTS = "alt_wpts"; + private static final String CACHE_STATUS_ARCHIVED = "Archived"; + private static final String CACHE_STATUS_DISABLED = "Temporarily unavailable"; + private static final String CACHE_IS_FOUND = "is_found"; private static final String CACHE_SIZE = "size"; private static final String CACHE_VOTES = "rating_votes"; private static final String CACHE_NOTFOUNDS = "notfounds"; @@ -64,12 +99,22 @@ final public class OkapiClient { private static final String USER_USERNAME = "username"; private static final String SERVICE_CACHE = "/okapi/services/caches/geocache"; - private static final String SERVICE_CACHE_FIELDS = "code|name|location|type|status|owner|founds|notfounds|size|difficulty|terrain|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden"; - private static final String SERVICE_NEAREST = "/okapi/services/caches/search/nearest"; + private static final String SERVICE_CACHE_CORE_FIELDS = "code|name|location|type|status|difficulty|terrain|size|is_found"; + private static final String SERVICE_CACHE_FIELDS = SERVICE_CACHE_CORE_FIELDS + "|owner|founds|notfounds|rating|rating_votes|recommendations|description|hint|images|latest_logs|date_hidden|attribution_note|alt_wpts|is_watched|attrnames|gc_code"; + + private static final String SERVICE_SEARCH_AND_RETRIEVE = "/okapi/services/caches/shortcuts/search_and_retrieve"; + + private static final String METHOD_SEARCH_NEAREST = "services/caches/search/nearest"; + private static final String METHOD_SEARCH_BBOX = "services/caches/search/bbox"; + private static final String METHOD_RETRIEVE_CACHES = "services/caches/geocaches"; + + private static final String SERVICE_MARK_CACHE = "/okapi/services/caches/mark"; + + private static final String SERVICE_SUBMIT_LOG = "/okapi/services/logs/submit"; public static Geocache getCache(final String geoCode) { - final Parameters params = new Parameters("cache_code", geoCode, "fields", SERVICE_CACHE_FIELDS); + final Parameters params = new Parameters("cache_code", geoCode, "fields", SERVICE_CACHE_FIELDS, "attribution_append", "none"); final JSONObject data = request(ConnectorFactory.getConnector(geoCode), SERVICE_CACHE, params); if (data == null) { @@ -81,30 +126,115 @@ final public class OkapiClient { public static List<Geocache> getCachesAround(final Geopoint center, IConnector connector) { String centerString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, center) + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, center); - final Parameters params = new Parameters("center", centerString); - final JSONObject data = request(connector, SERVICE_NEAREST, params); + final Parameters params = new Parameters("search_method", METHOD_SEARCH_NEAREST); + final Map<String, String> valueMap = new LinkedHashMap<String, String>(); + valueMap.put("center", centerString); + valueMap.put("limit", "20"); + + addFilterParams(valueMap); + + params.add("search_params", new JSONObject(valueMap).toString()); + + addRetrieveParams(params); + + final JSONObject data = request(connector, SERVICE_SEARCH_AND_RETRIEVE, params); if (data == null) { - return null; + return Collections.emptyList(); + } + + return parseCaches(data); + } + + public static List<Geocache> getCachesBBox(final Viewport viewport, IConnector connector) { + + if (viewport.getLatitudeSpan() == 0 || viewport.getLongitudeSpan() == 0) { + return Collections.emptyList(); + } + + String bboxString = GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, viewport.bottomLeft) + + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, viewport.bottomLeft) + + "|" + GeopointFormatter.format(GeopointFormatter.Format.LAT_DECDEGREE_RAW, viewport.topRight) + + "|" + GeopointFormatter.format(GeopointFormatter.Format.LON_DECDEGREE_RAW, viewport.topRight); + final Parameters params = new Parameters("search_method", METHOD_SEARCH_BBOX); + final Map<String, String> valueMap = new LinkedHashMap<String, String>(); + valueMap.put("bbox", bboxString); + + addFilterParams(valueMap); + + params.add("search_params", new JSONObject(valueMap).toString()); + + addRetrieveParams(params); + + final JSONObject data = request(connector, SERVICE_SEARCH_AND_RETRIEVE, params); + + if (data == null) { + return Collections.emptyList(); } return parseCaches(data); } + public static boolean setWatchState(final Geocache cache, final boolean watched, IConnector connector) { + final Parameters params = new Parameters("cache_code", cache.getGeocode()); + params.add("watched", watched ? "true" : "false"); + + final JSONObject data = request(connector, SERVICE_MARK_CACHE, params); + + if (data == null) { + return false; + } + + cache.setOnWatchlist(watched); + + return true; + } + + public static LogResult postLog(final Geocache cache, LogType logType, Calendar date, String log, IConnector connector) { + final Parameters params = new Parameters("cache_code", cache.getGeocode()); + params.add("logtype", logType.oc_type); + params.add("comment", log); + params.add("comment_format", "plaintext"); + params.add("when", logDateFormat.format(date.getTime())); + if (logType.equals(LogType.NEEDS_MAINTENANCE)) { + params.add("needs_maintenance", "true"); + } + + final JSONObject data = request(connector, SERVICE_SUBMIT_LOG, params); + + if (data == null) { + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + + try { + if (data.getBoolean("success")) { + return new LogResult(StatusCode.NO_ERROR, data.getString("log_uuid")); + } + + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } catch (JSONException e) { + Log.e("OkapiClient.postLog", e); + } + return new LogResult(StatusCode.LOG_POST_ERROR, ""); + } + private static List<Geocache> parseCaches(final JSONObject response) { try { - final JSONArray cachesResponse = response.getJSONArray("results"); + // Check for empty result + final String result = response.getString("results"); + if (StringUtils.isBlank(result) || StringUtils.equals(result, "[]")) { + return Collections.emptyList(); + } + + // Get and iterate result list + final JSONObject cachesResponse = response.getJSONObject("results"); if (cachesResponse != null) { - ArrayList<String> geocodes = new ArrayList<String>(cachesResponse.length()); - for (int i = 0; i < cachesResponse.length(); i++) { - String geocode = cachesResponse.getString(i); - if (StringUtils.isNotBlank(geocode)) { - geocodes.add(geocode); - } - } - List<Geocache> caches = new ArrayList<Geocache>(geocodes.size()); - for (String geocode : geocodes) { - Geocache cache = getCache(geocode); + List<Geocache> caches = new ArrayList<Geocache>(cachesResponse.length()); + @SuppressWarnings("unchecked") + Iterator<String> keys = cachesResponse.keys(); + while (keys.hasNext()) { + String key = keys.next(); + Geocache cache = parseSmallCache(cachesResponse.getJSONObject(key)); if (cache != null) { caches.add(cache); } @@ -112,24 +242,31 @@ final public class OkapiClient { return caches; } } catch (JSONException e) { - Log.e("OkapiClient.parseCaches", e); + Log.e("OkapiClient.parseCachesResult", e); } - return null; + return Collections.emptyList(); + } + + private static Geocache parseSmallCache(final JSONObject response) { + final Geocache cache = new Geocache(); + cache.setReliableLatLon(true); + try { + + parseCoreCache(response, cache); + + cgData.saveCache(cache, EnumSet.of(SaveFlag.SAVE_CACHE)); + } catch (JSONException e) { + Log.e("OkapiClient.parseSmallCache", e); + } + return cache; } private static Geocache parseCache(final JSONObject response) { final Geocache cache = new Geocache(); cache.setReliableLatLon(true); try { - cache.setGeocode(response.getString(CACHE_CODE)); - cache.setName(response.getString(CACHE_NAME)); - // not used: names - setLocation(cache, response.getString(CACHE_LOCATION)); - cache.setType(getCacheType(response.getString(CACHE_TYPE))); - final String status = response.getString(CACHE_STATUS); - cache.setDisabled(status.equalsIgnoreCase("Temporarily unavailable")); - cache.setArchived(status.equalsIgnoreCase("Archived")); + parseCoreCache(response, cache); // not used: url final JSONObject owner = response.getJSONObject(CACHE_OWNER); @@ -137,9 +274,7 @@ final public class OkapiClient { cache.getLogCounts().put(LogType.FOUND_IT, response.getInt(CACHE_FOUNDS)); cache.getLogCounts().put(LogType.DIDNT_FIND_IT, response.getInt(CACHE_NOTFOUNDS)); - cache.setSize(getCacheSize(response)); - cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY)); - cache.setTerrain((float) response.getDouble(CACHE_TERRAIN)); + if (!response.isNull(CACHE_RATING)) { cache.setRating((float) response.getDouble(CACHE_RATING)); } @@ -147,8 +282,22 @@ final public class OkapiClient { cache.setFavoritePoints(response.getInt(CACHE_RECOMMENDATIONS)); // not used: req_password - cache.setDescription(response.getString(CACHE_DESCRIPTION)); - cache.setHint(Html.fromHtml(response.getString(CACHE_HINT)).toString()); + // Prepend gc-link to description if available + StringBuilder description = new StringBuilder(500); + if (!response.isNull("gc_code")) { + String gccode = response.getString("gc_code"); + description.append(cgeoapplication.getInstance().getResources() + .getString(R.string.cache_listed_on, GCConnector.getInstance().getName())) + .append(": <a href=\"http://coord.info/") + .append(gccode) + .append("\">") + .append(gccode) + .append("</a><br /><br />"); + } + description.append(response.getString(CACHE_DESCRIPTION)); + cache.setDescription(description.toString()); + + cache.setHint(Html.escapeHtml(response.getString(CACHE_HINT))); // not used: hints final JSONArray images = response.getJSONArray(CACHE_IMAGES); @@ -163,9 +312,13 @@ final public class OkapiClient { } } - // not used: attrnames + cache.setAttributes(parseAttributes(response.getJSONArray(CACHE_ATTRNAMES))); cache.setLogs(parseLogs(response.getJSONArray(CACHE_LATEST_LOGS))); cache.setHidden(parseDate(response.getString(CACHE_HIDDEN))); + //TODO: Store license per cache + //cache.setLicense(response.getString("attribution_note")); + cache.setWaypoints(parseWaypoints(response.getJSONArray(CACHE_WPTS)), false); + cache.setOnWatchlist(response.getBoolean(CACHE_IS_WATCHED)); cache.setDetailedUpdatedNow(); // save full detailed caches @@ -176,6 +329,24 @@ final public class OkapiClient { return cache; } + private static void parseCoreCache(final JSONObject response, final Geocache cache) throws JSONException { + cache.setGeocode(response.getString(CACHE_CODE)); + cache.setName(response.getString(CACHE_NAME)); + // not used: names + setLocation(cache, response.getString(CACHE_LOCATION)); + cache.setType(getCacheType(response.getString(CACHE_TYPE))); + + final String status = response.getString(CACHE_STATUS); + cache.setDisabled(status.equalsIgnoreCase(CACHE_STATUS_DISABLED)); + cache.setArchived(status.equalsIgnoreCase(CACHE_STATUS_ARCHIVED)); + + cache.setSize(getCacheSize(response)); + cache.setDifficulty((float) response.getDouble(CACHE_DIFFICULTY)); + cache.setTerrain((float) response.getDouble(CACHE_TERRAIN)); + + cache.setFound(response.getBoolean(CACHE_IS_FOUND)); + } + private static String absoluteUrl(String url, String geocode) { final Uri uri = Uri.parse(url); @@ -214,6 +385,30 @@ final public class OkapiClient { return result; } + private static List<Waypoint> parseWaypoints(JSONArray wptsJson) { + List<Waypoint> result = null; + for (int i = 0; i < wptsJson.length(); i++) { + try { + JSONObject wptResponse = wptsJson.getJSONObject(i); + Waypoint wpt = new Waypoint(wptResponse.getString(WPT_NAME), + parseWptType(wptResponse.getString(WPT_TYPE)), + false); + wpt.setNote(wptResponse.getString(WPT_DESCRIPTION)); + Geopoint pt = parseCoords(wptResponse.getString(WPT_LOCATION)); + if (pt != null) { + wpt.setCoords(pt); + } + if (result == null) { + result = new ArrayList<Waypoint>(); + } + result.add(wpt); + } catch (JSONException e) { + Log.e("OkapiClient.parseWaypoints", e); + } + } + return result; + } + private static LogType parseLogType(String logType) { if ("Found it".equalsIgnoreCase(logType)) { return LogType.FOUND_IT; @@ -224,6 +419,31 @@ final public class OkapiClient { return LogType.NOTE; } + private static WaypointType parseWptType(String wptType) { + if ("parking".equalsIgnoreCase(wptType)) { + return WaypointType.PARKING; + } + if ("path".equalsIgnoreCase(wptType)) { + return WaypointType.TRAILHEAD; + } + if ("stage".equalsIgnoreCase(wptType)) { + return WaypointType.STAGE; + } + if ("physical-stage".equalsIgnoreCase(wptType)) { + return WaypointType.STAGE; + } + if ("virtual-stage".equalsIgnoreCase(wptType)) { + return WaypointType.PUZZLE; + } + if ("final".equalsIgnoreCase(wptType)) { + return WaypointType.FINAL; + } + if ("poi".equalsIgnoreCase(wptType)) { + return WaypointType.TRAILHEAD; + } + return WaypointType.WAYPOINT; + } + private static Date parseDate(final String date) { final SimpleDateFormat ISO8601DATEFORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.getDefault()); final String strippedDate = date.replaceAll("\\+0([0-9]){1}\\:00", "+0$100"); @@ -235,6 +455,36 @@ final public class OkapiClient { return null; } + private static Geopoint parseCoords(final String location) { + final String latitude = StringUtils.substringBefore(location, "|"); + final String longitude = StringUtils.substringAfter(location, "|"); + if (StringUtils.isNotBlank(latitude) && StringUtils.isNotBlank(longitude)) { + return new Geopoint(latitude, longitude); + } + + return null; + } + + private static List<String> parseAttributes(JSONArray nameList) { + + List<String> result = new ArrayList<String>(); + + for (int i = 0; i < nameList.length(); i++) { + try { + String name = nameList.getString(i); + CacheAttribute attr = CacheAttribute.getByOcId(AttributeParser.getOcDeId(name)); + + if (attr != null) { + result.add(attr.rawName); + } + } catch (JSONException e) { + Log.e("OkapiClient.parseAttributes", e); + } + } + + return result; + } + private static void setLocation(final Geocache cache, final String location) { final String latitude = StringUtils.substringBefore(location, "|"); final String longitude = StringUtils.substringAfter(location, "|"); @@ -281,6 +531,18 @@ final public class OkapiClient { if (cacheType.equalsIgnoreCase("Virtual")) { return CacheType.VIRTUAL; } + if (cacheType.equalsIgnoreCase("Event")) { + return CacheType.EVENT; + } + if (cacheType.equalsIgnoreCase("Webcam")) { + return CacheType.WEBCAM; + } + if (cacheType.equalsIgnoreCase("Math/Physics")) { + return CacheType.MYSTERY; + } + if (cacheType.equalsIgnoreCase("Drive-In")) { + return CacheType.TRADITIONAL; + } return CacheType.UNKNOWN; } @@ -297,9 +559,10 @@ final public class OkapiClient { return null; } - ((OCApiConnector) connector).addAuthentication(params); params.add("langpref", getPreferredLanguage()); + OAuth.signOAuth(host, service, "GET", false, params, Settings.getOCDETokenPublic(), Settings.getOCDETokenSecret(), ((OCApiLiveConnector) connector).getCK(), ((OCApiLiveConnector) connector).getCS()); + final String uri = "http://" + host + service; return Network.requestJSON(uri, params); } @@ -311,4 +574,43 @@ final public class OkapiClient { } return "en"; } + + private static void addFilterParams(final Map<String, String> valueMap) { + if (!Settings.isExcludeDisabledCaches()) { + valueMap.put("status", "Available|Temporarily unavailable"); + } + if (Settings.isExcludeMyCaches()) { + valueMap.put("exclude_my_own", "true"); + valueMap.put("found_status", "notfound_only"); + } + if (Settings.getCacheType() != CacheType.ALL) { + valueMap.put("type", getFilterFromType(Settings.getCacheType())); + } + } + + private static void addRetrieveParams(final Parameters params) { + params.add("retr_method", METHOD_RETRIEVE_CACHES); + params.add("retr_params", "{\"fields\": \"" + SERVICE_CACHE_CORE_FIELDS + "\"}"); + params.add("wrap", "true"); + } + + private static String getFilterFromType(CacheType cacheType) { + switch (cacheType) { + case EVENT: + return "Event"; + case MULTI: + return "Multi"; + case MYSTERY: + return "Quiz"; + case TRADITIONAL: + return "Traditional"; + case VIRTUAL: + return "Virtual"; + case WEBCAM: + return "Webcam"; + default: + return ""; + } + } + } diff --git a/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java new file mode 100644 index 0000000..24c6b79 --- /dev/null +++ b/main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java @@ -0,0 +1,69 @@ +package cgeo.geocaching.connector.oc; + +import cgeo.geocaching.Geocache; +import cgeo.geocaching.TrackableLog; +import cgeo.geocaching.VisitCacheActivity; +import cgeo.geocaching.connector.IConnector; +import cgeo.geocaching.connector.ILoggingManager; +import cgeo.geocaching.connector.ImageResult; +import cgeo.geocaching.connector.LogResult; +import cgeo.geocaching.enumerations.LogType; +import cgeo.geocaching.enumerations.StatusCode; + +import android.app.Activity; +import android.net.Uri; + +import java.util.Arrays; +import java.util.Calendar; +import java.util.Collections; +import java.util.List; + +public class OkapiLoggingManager implements ILoggingManager { + + private final IConnector connector; + private final Geocache cache; + private VisitCacheActivity activity; + + private final static List<LogType> standardLogTypes = Arrays.asList(LogType.FOUND_IT, LogType.DIDNT_FIND_IT, LogType.NOTE, LogType.NEEDS_MAINTENANCE); + private final static List<LogType> eventLogTypes = Arrays.asList(LogType.WILL_ATTEND, LogType.ATTENDED, LogType.NOTE); + + public OkapiLoggingManager(Activity activity, IConnector connector, Geocache cache) { + this.connector = connector; + this.cache = cache; + this.activity = (VisitCacheActivity) activity; + } + + @Override + public void init() { + activity.onLoadFinished(); + } + + @Override + public LogResult postLog(Geocache cache, LogType logType, Calendar date, String log, List<TrackableLog> trackableLogs) { + return OkapiClient.postLog(cache, logType, date, log, connector); + } + + @Override + public ImageResult postLogImage(String logId, String imageCaption, String imageDescription, Uri imageUri) { + return new ImageResult(StatusCode.LOG_POST_ERROR, ""); + } + + @Override + public boolean hasLoaderError() { + return false; + } + + @Override + public List<TrackableLog> getTrackables() { + return Collections.emptyList(); + } + + @Override + public List<LogType> getPossibleLogTypes() { + if (cache.isEventCache()) { + return eventLogTypes; + } + + return standardLogTypes; + } +} diff --git a/main/src/cgeo/geocaching/enumerations/LogType.java b/main/src/cgeo/geocaching/enumerations/LogType.java index 71a5146..6a055f4 100644 --- a/main/src/cgeo/geocaching/enumerations/LogType.java +++ b/main/src/cgeo/geocaching/enumerations/LogType.java @@ -15,50 +15,52 @@ import java.util.Map; */ public enum LogType { - FOUND_IT(2, "2", "found it", R.string.log_found, R.drawable.mark_green), - DIDNT_FIND_IT(3, "3", "didn't find it", R.string.log_dnf, R.drawable.mark_red), - NOTE(4, "4", "write note", R.string.log_note), - PUBLISH_LISTING(1003, "24", "publish listing", R.string.log_published, R.drawable.mark_green_more), - ENABLE_LISTING(23, "23", "enable listing", R.string.log_enabled, R.drawable.mark_green_more), - ARCHIVE(5, "5", "archive", R.string.log_archived, R.drawable.mark_red_more), - UNARCHIVE(12, "12", "unarchive", R.string.log_unarchived, R.drawable.mark_green_more), - TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", R.string.log_disabled, R.drawable.mark_red_more), - NEEDS_ARCHIVE(7, "7", "needs archived", R.string.log_needs_archived, R.drawable.mark_red), - WILL_ATTEND(9, "9", "will attend", R.string.log_attend), - ATTENDED(10, "10", "attended", R.string.log_attended, R.drawable.mark_green), - RETRIEVED_IT(13, "13", "retrieved it", R.string.log_retrieved, R.drawable.mark_green_more), - PLACED_IT(14, "14", "placed it", R.string.log_placed, R.drawable.mark_green_more), - GRABBED_IT(19, "19", "grabbed it", R.string.log_grabbed, R.drawable.mark_green_more), - NEEDS_MAINTENANCE(45, "45", "needs maintenance", R.string.log_maintenance_needed, R.drawable.mark_red), - OWNER_MAINTENANCE(46, "46", "owner maintenance", R.string.log_maintained, R.drawable.mark_green_more), - UPDATE_COORDINATES(47, "47", "update coordinates", R.string.log_update), - DISCOVERED_IT(48, "48", "discovered it", R.string.log_discovered, R.drawable.mark_green), - POST_REVIEWER_NOTE(18, "68", "post reviewer note", R.string.log_reviewer), - VISIT(1001, "75", "visit", R.string.log_tb_visit, R.drawable.mark_green), - WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", R.string.log_webcam, R.drawable.mark_green), - ANNOUNCEMENT(74, "74", "announcement", R.string.log_announcement), - MOVE_COLLECTION(69, "69", "unused_collection", R.string.log_movecollection), - MOVE_INVENTORY(70, "70", "unused_inventory", R.string.log_moveinventory), - RETRACT(25, "25", "retract listing", R.string.log_retractlisting), - MARKED_MISSING(16, "16", "marked missing", R.string.log_marked_missing, R.drawable.mark_red), - UNKNOWN(0, "unknown", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet + FOUND_IT(2, "2", "found it", "Found it", R.string.log_found, R.drawable.mark_green), + DIDNT_FIND_IT(3, "3", "didn't find it", "Didn't find it", R.string.log_dnf, R.drawable.mark_red), + NOTE(4, "4", "write note", "Comment", R.string.log_note), + PUBLISH_LISTING(1003, "24", "", "publish listing", R.string.log_published, R.drawable.mark_green_more), + ENABLE_LISTING(23, "23", "", "enable listing", R.string.log_enabled, R.drawable.mark_green_more), + ARCHIVE(5, "5", "archive", "", R.string.log_archived, R.drawable.mark_red_more), + UNARCHIVE(12, "12", "unarchive", "", R.string.log_unarchived, R.drawable.mark_green_more), + TEMP_DISABLE_LISTING(22, "22", "temporarily disable listing", "", R.string.log_disabled, R.drawable.mark_red_more), + NEEDS_ARCHIVE(7, "7", "needs archived", "", R.string.log_needs_archived, R.drawable.mark_red), + WILL_ATTEND(9, "9", "will attend", "Will attend", R.string.log_attend), + ATTENDED(10, "10", "attended", "Attended", R.string.log_attended, R.drawable.mark_green), + RETRIEVED_IT(13, "13", "retrieved it", "", R.string.log_retrieved, R.drawable.mark_green_more), + PLACED_IT(14, "14", "placed it", "", R.string.log_placed, R.drawable.mark_green_more), + GRABBED_IT(19, "19", "grabbed it", "", R.string.log_grabbed, R.drawable.mark_green_more), + NEEDS_MAINTENANCE(45, "45", "needs maintenance", "Comment", R.string.log_maintenance_needed, R.drawable.mark_red), + OWNER_MAINTENANCE(46, "46", "owner maintenance", "", R.string.log_maintained, R.drawable.mark_green_more), + UPDATE_COORDINATES(47, "47", "update coordinates", "", R.string.log_update), + DISCOVERED_IT(48, "48", "discovered it", "", R.string.log_discovered, R.drawable.mark_green), + POST_REVIEWER_NOTE(18, "68", "post reviewer note", "", R.string.log_reviewer), + VISIT(1001, "75", "visit", "", R.string.log_tb_visit, R.drawable.mark_green), + WEBCAM_PHOTO_TAKEN(11, "11", "webcam photo taken", "", R.string.log_webcam, R.drawable.mark_green), + ANNOUNCEMENT(74, "74", "announcement", "", R.string.log_announcement), + MOVE_COLLECTION(69, "69", "unused_collection", "", R.string.log_movecollection), + MOVE_INVENTORY(70, "70", "unused_inventory", "", R.string.log_moveinventory), + RETRACT(25, "25", "retract listing", "", R.string.log_retractlisting), + MARKED_MISSING(16, "16", "marked missing", "", R.string.log_marked_missing, R.drawable.mark_red), + UNKNOWN(0, "unknown", "", "", R.string.err_unknown, R.drawable.mark_red); // LogType not init. yet public final int id; public final String iconName; public final String type; + public final String oc_type; private final int stringId; public final int markerId; - LogType(int id, String iconName, String type, int stringId, int markerId) { + LogType(int id, String iconName, String type, String oc_type, int stringId, int markerId) { this.id = id; this.iconName = iconName; this.type = type; + this.oc_type = oc_type; this.stringId = stringId; this.markerId = markerId; } - LogType(int id, String iconName, String type, int stringId) { - this(id, iconName, type, stringId, R.drawable.mark_gray); + LogType(int id, String iconName, String type, String oc_type, int stringId) { + this(id, iconName, type, oc_type, stringId, R.drawable.mark_gray); } private final static Map<String, LogType> FIND_BY_ICONNAME; diff --git a/main/src/cgeo/geocaching/network/OAuth.java b/main/src/cgeo/geocaching/network/OAuth.java index 0b7a261..6740096 100644 --- a/main/src/cgeo/geocaching/network/OAuth.java +++ b/main/src/cgeo/geocaching/network/OAuth.java @@ -1,9 +1,9 @@ package cgeo.geocaching.network; -import cgeo.geocaching.Settings; import cgeo.geocaching.utils.CryptUtils; import ch.boye.httpclientandroidlib.NameValuePair; + import org.apache.commons.lang3.StringUtils; import java.util.ArrayList; @@ -11,9 +11,17 @@ import java.util.Date; import java.util.List; public class OAuth { - public static void signOAuth(final String host, final String path, final String method, final boolean https, final Parameters params, final String token, final String tokenSecret) { + public static void signOAuth(final String host, + final String path, + final String method, + final boolean https, + final Parameters params, + final String token, + final String tokenSecret, + final String consumerKey, + final String consumerSecret) { params.put( - "oauth_consumer_key", Settings.getKeyConsumerPublic(), + "oauth_consumer_key", consumerKey, "oauth_nonce", CryptUtils.md5(Long.toString(System.currentTimeMillis())), "oauth_signature_method", "HMAC-SHA1", "oauth_timestamp", Long.toString(new Date().getTime() / 1000), @@ -26,7 +34,7 @@ public class OAuth { paramsEncoded.add(nameValue.getName() + "=" + Network.rfc3986URLEncode(nameValue.getValue())); } - final String keysPacked = Settings.getKeyConsumerSecret() + "&" + StringUtils.defaultString(tokenSecret); // both even if empty some of them! + 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(), '&')); params.put("oauth_signature", CryptUtils.base64Encode(CryptUtils.hashHmac(requestPacked, keysPacked))); } diff --git a/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java new file mode 100644 index 0000000..751443e --- /dev/null +++ b/main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java @@ -0,0 +1,326 @@ +package cgeo.geocaching.network; + +import cgeo.geocaching.R; +import cgeo.geocaching.activity.AbstractActivity; +import cgeo.geocaching.utils.Log; +import cgeo.geocaching.utils.MatcherWrapper; + +import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity; +import ch.boye.httpclientandroidlib.util.EntityUtils; + +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.tuple.ImmutablePair; + +import android.app.ProgressDialog; +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.os.Handler; +import android.os.Message; +import android.view.View; +import android.widget.Button; +import android.widget.EditText; +import android.widget.TextView; + +import java.util.regex.Pattern; + +public abstract class OAuthAuthorizationActivity extends AbstractActivity { + + private String host; + private String pathRequest; + private String pathAuthorize; + private String pathAccess; + private boolean https; + private String consumerKey; + private String consumerSecret; + private String OAtoken = null; + private String OAtokenSecret = null; + private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)"); + private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)"); + private Button startButton = null; + private EditText pinEntry = null; + private Button pinEntryButton = null; + private ProgressDialog requestTokenDialog = null; + private ProgressDialog changeTokensDialog = null; + private Handler requestTokenHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + if (requestTokenDialog != null && requestTokenDialog.isShowing()) { + requestTokenDialog.dismiss(); + } + + startButton.setOnClickListener(new StartListener()); + startButton.setEnabled(true); + + if (msg.what == 1) { + startButton.setText(getAuthAgain()); + + pinEntry.setVisibility(View.VISIBLE); + pinEntryButton.setVisibility(View.VISIBLE); + pinEntryButton.setOnClickListener(new ConfirmPINListener()); + } else { + showToast(getErrAuthInitialize()); + startButton.setText(getAuthStart()); + } + } + + }; + private Handler changeTokensHandler = new Handler() { + + @Override + public void handleMessage(Message msg) { + if (changeTokensDialog != null && changeTokensDialog.isShowing()) { + changeTokensDialog.dismiss(); + } + + pinEntryButton.setOnClickListener(new ConfirmPINListener()); + pinEntryButton.setEnabled(true); + + if (msg.what == 1) { + showToast(getAuthDialogCompleted()); + + pinEntryButton.setVisibility(View.GONE); + + finish(); + } else { + showToast(getErrAuthProcess()); + + pinEntry.setVisibility(View.GONE); + pinEntryButton.setVisibility(View.GONE); + startButton.setText(getAuthStart()); + } + } + }; + + public OAuthAuthorizationActivity(String host, + String pathRequest, + String pathAuthorize, + String pathAccess, + boolean https, + String consumerKey, + String consumerSecret) { + this.host = host; + this.pathRequest = pathRequest; + this.pathAuthorize = pathAuthorize; + this.pathAccess = pathAccess; + this.https = https; + this.consumerKey = consumerKey; + this.consumerSecret = consumerSecret; + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState, R.layout.authorization_activity); + + setTitle(getAuthTitle()); + + init(); + } + + private void init() { + startButton = (Button) findViewById(R.id.start); + pinEntry = (EditText) findViewById(R.id.pin); + pinEntryButton = (Button) findViewById(R.id.pin_button); + + TextView auth = (TextView) findViewById(R.id.auth_1); + auth.setText(getAboutAuth1()); + auth = (TextView) findViewById(R.id.auth_2); + auth.setText(getAboutAuth2()); + + ImmutablePair<String, String> tempToken = getTempToken(); + OAtoken = tempToken.left; + OAtokenSecret = tempToken.right; + + startButton.setText(getAuthAuthorize()); + pinEntryButton.setText(getAuthFinish()); + + startButton.setEnabled(true); + startButton.setOnClickListener(new StartListener()); + + if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { + // start authorization process + startButton.setText(getAuthStart()); + } else { + // already have temporary tokens, continue from pin + startButton.setText(getAuthAgain()); + + pinEntry.setHint(getAuthPinHint()); + pinEntry.setVisibility(View.VISIBLE); + pinEntryButton.setVisibility(View.VISIBLE); + pinEntryButton.setOnClickListener(new ConfirmPINListener()); + } + } + + private void requestToken() { + + int status = 0; + try { + final Parameters params = new Parameters(); + params.put("oauth_callback", "oob"); + final String method = "GET"; + OAuth.signOAuth(host, pathRequest, method, https, params, null, null, consumerKey, consumerSecret); + final String line = Network.getResponseData(Network.getRequest(getUrlPrefix() + host + pathRequest, params)); + + if (StringUtils.isNotBlank(line)) { + final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); + if (paramsMatcher1.find()) { + OAtoken = paramsMatcher1.group(1); + } + final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); + if (paramsMatcher2.find()) { + OAtokenSecret = paramsMatcher2.group(1); + } + + if (StringUtils.isNotBlank(OAtoken) && StringUtils.isNotBlank(OAtokenSecret)) { + setTempTokens(OAtoken, OAtokenSecret); + try { + final Parameters paramsBrowser = new Parameters(); + paramsBrowser.put("oauth_token", OAtoken); + final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser)); + startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(getUrlPrefix() + host + pathAuthorize + "?" + encodedParams))); + status = 1; + } catch (Exception e) { + Log.e("OAuthAuthorizationActivity.requestToken(2)", e); + } + } + } + } catch (Exception e) { + Log.e("OAuthAuthorizationActivity.requestToken(1)", e); + } + + requestTokenHandler.sendEmptyMessage(status); + } + + private void changeToken() { + + int status = 0; + + try { + final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString()); + + final String method = "POST"; + OAuth.signOAuth(host, pathAccess, method, https, params, OAtoken, OAtokenSecret, consumerKey, consumerSecret); + final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest(getUrlPrefix() + host + pathAccess, params))); + + OAtoken = ""; + OAtokenSecret = ""; + + final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); + if (paramsMatcher1.find()) { + OAtoken = paramsMatcher1.group(1); + } + final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); + if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) { + OAtokenSecret = paramsMatcher2.group(1); + } + + if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { + OAtoken = ""; + OAtokenSecret = ""; + setTokens(null, null, false); + } else { + setTokens(OAtoken, OAtokenSecret, true); + status = 1; + } + } catch (Exception e) { + Log.e("OAuthAuthorizationActivity.changeToken", e); + } + + changeTokensHandler.sendEmptyMessage(status); + } + + private String getUrlPrefix() { + return https ? "https://" : "http://"; + } + + private class StartListener implements View.OnClickListener { + + @Override + public void onClick(View arg0) { + if (requestTokenDialog == null) { + requestTokenDialog = new ProgressDialog(OAuthAuthorizationActivity.this); + requestTokenDialog.setCancelable(false); + requestTokenDialog.setMessage(getAuthDialogWait()); + } + requestTokenDialog.show(); + startButton.setEnabled(false); + startButton.setOnTouchListener(null); + startButton.setOnClickListener(null); + + setTempTokens(null, null); + (new Thread() { + + @Override + public void run() { + requestToken(); + } + }).start(); + } + } + + private class ConfirmPINListener implements View.OnClickListener { + + @Override + public void onClick(View arg0) { + if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) { + helpDialog(getAuthDialogPinTitle(), getAuthDialogPinMessage()); + return; + } + + if (changeTokensDialog == null) { + changeTokensDialog = new ProgressDialog(OAuthAuthorizationActivity.this); + changeTokensDialog.setCancelable(false); + changeTokensDialog.setMessage(getAuthDialogWait()); + } + changeTokensDialog.show(); + pinEntryButton.setEnabled(false); + pinEntryButton.setOnTouchListener(null); + pinEntryButton.setOnClickListener(null); + + (new Thread() { + + @Override + public void run() { + changeToken(); + } + }).start(); + } + } + + protected abstract ImmutablePair<String, String> getTempToken(); + + protected abstract void setTempTokens(String tokenPublic, String tokenSecret); + + protected abstract void setTokens(String tokenPublic, String tokenSecret, boolean enable); + + // get resources from derived class + + protected abstract String getAuthTitle(); + + protected abstract String getAuthAgain(); + + protected abstract String getErrAuthInitialize(); + + protected abstract String getAuthStart(); + + protected abstract String getAuthDialogCompleted(); + + protected abstract String getErrAuthProcess(); + + protected abstract String getAuthDialogWait(); + + protected abstract String getAuthDialogPinTitle(); + + protected abstract String getAuthDialogPinMessage(); + + protected abstract String getAboutAuth1(); + + protected abstract String getAboutAuth2(); + + protected abstract String getAuthAuthorize(); + + protected abstract String getAuthPinHint(); + + protected abstract String getAuthFinish(); +} diff --git a/main/src/cgeo/geocaching/twitter/Twitter.java b/main/src/cgeo/geocaching/twitter/Twitter.java index e3d3f77..525b7f0 100644 --- a/main/src/cgeo/geocaching/twitter/Twitter.java +++ b/main/src/cgeo/geocaching/twitter/Twitter.java @@ -38,7 +38,7 @@ public final class Twitter { "display_coordinates", "true"); } - OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret()); + OAuth.signOAuth("api.twitter.com", "/1/statuses/update.json", "POST", false, parameters, Settings.getTokenPublic(), Settings.getTokenSecret(), Settings.getKeyConsumerPublic(), Settings.getKeyConsumerSecret()); final HttpResponse httpResponse = Network.postRequest("http://api.twitter.com/1/statuses/update.json", parameters); if (httpResponse != null && httpResponse.getStatusLine().getStatusCode() == 200) { Log.i("Tweet posted"); diff --git a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java index 3bc1dec..7146a62 100644 --- a/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java +++ b/main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java @@ -2,258 +2,105 @@ package cgeo.geocaching.twitter; import cgeo.geocaching.R; import cgeo.geocaching.Settings; -import cgeo.geocaching.activity.AbstractActivity; -import cgeo.geocaching.network.Network; -import cgeo.geocaching.network.OAuth; -import cgeo.geocaching.network.Parameters; -import cgeo.geocaching.utils.Log; -import cgeo.geocaching.utils.MatcherWrapper; +import cgeo.geocaching.network.OAuthAuthorizationActivity; -import ch.boye.httpclientandroidlib.client.entity.UrlEncodedFormEntity; -import ch.boye.httpclientandroidlib.util.EntityUtils; - -import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; -import android.app.ProgressDialog; -import android.content.Intent; -import android.net.Uri; -import android.os.Bundle; -import android.os.Handler; -import android.os.Message; -import android.view.View; -import android.widget.Button; -import android.widget.EditText; - -import java.util.regex.Pattern; - -public class TwitterAuthorizationActivity extends AbstractActivity { - private String OAtoken = null; - private String OAtokenSecret = null; - private final Pattern paramsPattern1 = Pattern.compile("oauth_token=([a-zA-Z0-9\\-\\_.]+)"); - private final Pattern paramsPattern2 = Pattern.compile("oauth_token_secret=([a-zA-Z0-9\\-\\_.]+)"); - private Button startButton = null; - private EditText pinEntry = null; - private Button pinEntryButton = null; - private ProgressDialog requestTokenDialog = null; - private ProgressDialog changeTokensDialog = null; - private Handler requestTokenHandler = new Handler() { - - @Override - public void handleMessage(Message msg) { - if (requestTokenDialog != null && requestTokenDialog.isShowing()) { - requestTokenDialog.dismiss(); - } - - startButton.setOnClickListener(new StartListener()); - startButton.setEnabled(true); - - if (msg.what == 1) { - startButton.setText(res.getString(R.string.auth_again)); - - pinEntry.setVisibility(View.VISIBLE); - pinEntryButton.setVisibility(View.VISIBLE); - pinEntryButton.setOnClickListener(new ConfirmPINListener()); - } else { - showToast(res.getString(R.string.err_auth_initialize)); - startButton.setText(res.getString(R.string.auth_start)); - } - } - }; - private Handler changeTokensHandler = new Handler() { +public class TwitterAuthorizationActivity extends OAuthAuthorizationActivity { - @Override - public void handleMessage(Message msg) { - if (changeTokensDialog != null && changeTokensDialog.isShowing()) { - changeTokensDialog.dismiss(); - } - - pinEntryButton.setOnClickListener(new ConfirmPINListener()); - pinEntryButton.setEnabled(true); - - if (msg.what == 1) { - showToast(res.getString(R.string.auth_dialog_completed)); - - pinEntryButton.setVisibility(View.GONE); - - finish(); - } else { - showToast(res.getString(R.string.err_auth_process)); - - pinEntry.setVisibility(View.GONE); - pinEntryButton.setVisibility(View.GONE); - startButton.setText(res.getString(R.string.auth_start)); - } - } - }; + public TwitterAuthorizationActivity() { + super("api.twitter.com", + "/oauth/request_token", + "/oauth/authorize", + "/oauth/access_token", + true, + Settings.getKeyConsumerPublic(), + Settings.getKeyConsumerSecret()); + } @Override - public void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState, R.layout.twitter_authorization_activity); - - init(); + protected ImmutablePair<String, String> getTempToken() { + return Settings.getTempToken(); } - private void init() { - startButton = (Button) findViewById(R.id.start); - pinEntry = (EditText) findViewById(R.id.pin); - pinEntryButton = (Button) findViewById(R.id.pin_button); - - ImmutablePair<String, String> tempToken = Settings.getTempToken(); - OAtoken = tempToken.left; - OAtokenSecret = tempToken.right; - - startButton.setEnabled(true); - startButton.setOnClickListener(new StartListener()); - - if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { - // start authorization process - startButton.setText(res.getString(R.string.auth_start)); - } else { - // already have temporary tokens, continue from pin - startButton.setText(res.getString(R.string.auth_again)); - - pinEntry.setVisibility(View.VISIBLE); - pinEntryButton.setVisibility(View.VISIBLE); - pinEntryButton.setOnClickListener(new ConfirmPINListener()); - } + @Override + protected void setTempTokens(String tokenPublic, String tokenSecret) { + Settings.setTwitterTempTokens(tokenPublic, tokenSecret); } - private void requestToken() { - - int status = 0; - try { - final Parameters params = new Parameters(); - final String method = "GET"; - final String pathRequest = "/oauth/request_token"; - final String host = "api.twitter.com"; - OAuth.signOAuth(host, pathRequest, method, true, params, null, null); - final String line = Network.getResponseData(Network.getRequest("https://" + host + pathRequest, params)); - - - if (StringUtils.isNotBlank(line)) { - final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); - if (paramsMatcher1.find()) { - OAtoken = paramsMatcher1.group(1); - } - final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); - if (paramsMatcher2.find()) { - OAtokenSecret = paramsMatcher2.group(1); - } - - if (StringUtils.isNotBlank(OAtoken) && StringUtils.isNotBlank(OAtokenSecret)) { - Settings.setTwitterTempTokens(OAtoken, OAtokenSecret); - try { - final Parameters paramsBrowser = new Parameters(); - paramsBrowser.put("oauth_callback", "oob"); - final String pathAuthorize = "/oauth/authorize"; - OAuth.signOAuth(host, pathAuthorize, "GET", true, paramsBrowser, OAtoken, OAtokenSecret); - final String encodedParams = EntityUtils.toString(new UrlEncodedFormEntity(paramsBrowser)); - startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse("https://" + host + pathAuthorize + "?" + encodedParams))); - status = 1; - } catch (Exception e) { - Log.e("TwitterAuthorizationActivity.requestToken(2)", e); - } - } - } - } catch (Exception e) { - Log.e("TwitterAuthorizationActivity.requestToken(1)", e); - } - - requestTokenHandler.sendEmptyMessage(status); + @Override + protected void setTokens(String tokenPublic, String tokenSecret, boolean enable) { + Settings.setTwitterTokens(tokenPublic, tokenSecret, enable); } - private void changeToken() { - - int status = 0; - - try { - final Parameters params = new Parameters("oauth_verifier", pinEntry.getText().toString()); - - final String method = "POST"; - final String path = "/oauth/access_token"; - final String host = "api.twitter.com"; - OAuth.signOAuth(host, path, method, true, params, OAtoken, OAtokenSecret); - final String line = StringUtils.defaultString(Network.getResponseData(Network.postRequest("https://" + host + path, params))); + @Override + protected String getAuthTitle() { + return res.getString(R.string.auth_twitter); + } - OAtoken = ""; - OAtokenSecret = ""; + @Override + protected String getAuthAgain() { + return res.getString(R.string.auth_again); + } - final MatcherWrapper paramsMatcher1 = new MatcherWrapper(paramsPattern1, line); - if (paramsMatcher1.find()) { - OAtoken = paramsMatcher1.group(1); - } - final MatcherWrapper paramsMatcher2 = new MatcherWrapper(paramsPattern2, line); - if (paramsMatcher2.find() && paramsMatcher2.groupCount() > 0) { - OAtokenSecret = paramsMatcher2.group(1); - } + @Override + protected String getErrAuthInitialize() { + return res.getString(R.string.err_auth_initialize); + } - if (StringUtils.isBlank(OAtoken) && StringUtils.isBlank(OAtokenSecret)) { - OAtoken = ""; - OAtokenSecret = ""; - Settings.setTwitterTokens(null, null, false); - } else { - Settings.setTwitterTokens(OAtoken, OAtokenSecret, true); - status = 1; - } - } catch (Exception e) { - Log.e("TwitterAuthorizationActivity.changeToken", e); - } + @Override + protected String getAuthStart() { + return res.getString(R.string.auth_start); + } - changeTokensHandler.sendEmptyMessage(status); + @Override + protected String getAuthDialogCompleted() { + return res.getString(R.string.auth_dialog_completed); } - private class StartListener implements View.OnClickListener { + @Override + protected String getErrAuthProcess() { + return res.getString(R.string.err_auth_process); + } - @Override - public void onClick(View arg0) { - if (requestTokenDialog == null) { - requestTokenDialog = new ProgressDialog(TwitterAuthorizationActivity.this); - requestTokenDialog.setCancelable(false); - requestTokenDialog.setMessage(res.getString(R.string.auth_dialog_wait)); - } - requestTokenDialog.show(); - startButton.setEnabled(false); - startButton.setOnTouchListener(null); - startButton.setOnClickListener(null); + @Override + protected String getAuthDialogWait() { + return res.getString(R.string.auth_dialog_wait); + } - Settings.setTwitterTempTokens(null, null); - (new Thread() { + @Override + protected String getAuthDialogPinTitle() { + return res.getString(R.string.auth_dialog_pin_title); + } - @Override - public void run() { - requestToken(); - } - }).start(); - } + @Override + protected String getAuthDialogPinMessage() { + return res.getString(R.string.auth_dialog_pin_message); } - private class ConfirmPINListener implements View.OnClickListener { + @Override + protected String getAboutAuth1() { + return res.getString(R.string.about_auth_1); + } - @Override - public void onClick(View arg0) { - if (StringUtils.isEmpty(((EditText) findViewById(R.id.pin)).getText().toString())) { - helpDialog(res.getString(R.string.auth_dialog_pin_title), res.getString(R.string.auth_dialog_pin_message)); - return; - } + @Override + protected String getAboutAuth2() { + return res.getString(R.string.about_auth_2); + } - if (changeTokensDialog == null) { - changeTokensDialog = new ProgressDialog(TwitterAuthorizationActivity.this); - changeTokensDialog.setCancelable(false); - changeTokensDialog.setMessage(res.getString(R.string.auth_dialog_wait)); - } - changeTokensDialog.show(); - pinEntryButton.setEnabled(false); - pinEntryButton.setOnTouchListener(null); - pinEntryButton.setOnClickListener(null); + @Override + protected String getAuthAuthorize() { + return res.getString(R.string.auth_authorize); + } - (new Thread() { + @Override + protected String getAuthPinHint() { + return res.getString(R.string.auth_pin_hint); + } - @Override - public void run() { - changeToken(); - } - }).start(); - } + @Override + protected String getAuthFinish() { + return res.getString(R.string.auth_finish); } + } |
