aboutsummaryrefslogtreecommitdiffstats
path: root/main/src
diff options
context:
space:
mode:
authorrsudev <rasch@munin-soft.de>2013-05-26 17:44:10 +0200
committerrsudev <rasch@munin-soft.de>2013-05-26 17:44:10 +0200
commit8e2ec9dd830d9c5c370ae8aa77163c22364e47e0 (patch)
tree2ed070f00896c636867b01f0c5dadf78ac2a828f /main/src
parentea5cfa107123deaf358bf75a7cf8835fc95acc8f (diff)
downloadcgeo-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')
-rw-r--r--main/src/cgeo/geocaching/CacheDetailActivity.java4
-rw-r--r--main/src/cgeo/geocaching/Geocache.java9
-rw-r--r--main/src/cgeo/geocaching/Settings.java68
-rw-r--r--main/src/cgeo/geocaching/SettingsActivity.java22
-rw-r--r--main/src/cgeo/geocaching/VisitCacheActivity.java74
-rw-r--r--main/src/cgeo/geocaching/connector/AbstractConnector.java22
-rw-r--r--main/src/cgeo/geocaching/connector/ConnectorFactory.java5
-rw-r--r--main/src/cgeo/geocaching/connector/IConnector.java32
-rw-r--r--main/src/cgeo/geocaching/connector/ILoggingManager.java32
-rw-r--r--main/src/cgeo/geocaching/connector/ImageResult.java23
-rw-r--r--main/src/cgeo/geocaching/connector/LogResult.java23
-rw-r--r--main/src/cgeo/geocaching/connector/NoLoggingManager.java46
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCConnector.java19
-rw-r--r--main/src/cgeo/geocaching/connector/gc/GCLoggingManager.java135
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OC11XMLParser.java762
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiConnector.java6
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCApiLiveConnector.java78
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCAuthorizationActivity.java109
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLApiConnector.java67
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OCXMLClient.java122
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiClient.java370
-rw-r--r--main/src/cgeo/geocaching/connector/oc/OkapiLoggingManager.java69
-rw-r--r--main/src/cgeo/geocaching/enumerations/LogType.java62
-rw-r--r--main/src/cgeo/geocaching/network/OAuth.java16
-rw-r--r--main/src/cgeo/geocaching/network/OAuthAuthorizationActivity.java326
-rw-r--r--main/src/cgeo/geocaching/twitter/Twitter.java2
-rw-r--r--main/src/cgeo/geocaching/twitter/TwitterAuthorizationActivity.java299
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|&nbsp;)*</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);
}
+
}