aboutsummaryrefslogtreecommitdiffstats
path: root/main/src/cgeo/geocaching/network
diff options
context:
space:
mode:
Diffstat (limited to 'main/src/cgeo/geocaching/network')
-rw-r--r--main/src/cgeo/geocaching/network/HtmlImage.java24
-rw-r--r--main/src/cgeo/geocaching/network/Network.java18
-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/network/StatusUpdater.java13
5 files changed, 373 insertions, 24 deletions
diff --git a/main/src/cgeo/geocaching/network/HtmlImage.java b/main/src/cgeo/geocaching/network/HtmlImage.java
index 38498d6..d5b610c 100644
--- a/main/src/cgeo/geocaching/network/HtmlImage.java
+++ b/main/src/cgeo/geocaching/network/HtmlImage.java
@@ -6,6 +6,7 @@ import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.compatibility.Compatibility;
import cgeo.geocaching.connector.ConnectorFactory;
import cgeo.geocaching.files.LocalStorage;
+import cgeo.geocaching.utils.IOUtils;
import cgeo.geocaching.utils.ImageHelper;
import cgeo.geocaching.utils.Log;
@@ -21,10 +22,10 @@ import android.graphics.drawable.BitmapDrawable;
import android.net.Uri;
import android.text.Html;
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.util.Date;
public class HtmlImage implements Html.ImageGetter {
@@ -66,6 +67,7 @@ public class HtmlImage implements Html.ImageGetter {
bfOptions = new BitmapFactory.Options();
bfOptions.inTempStorage = new byte[16 * 1024];
+ bfOptions.inPreferredConfig = Bitmap.Config.RGB_565;
Point displaySize = Compatibility.getDisplaySize();
this.maxWidth = displaySize.x - 25;
@@ -194,7 +196,11 @@ public class HtmlImage implements Html.ImageGetter {
if (file.exists()) {
if (listId >= StoredList.STANDARD_LIST_ID || file.lastModified() > (new Date().getTime() - (24 * 60 * 60 * 1000)) || forceKeep) {
setSampleSize(file);
- return BitmapFactory.decodeFile(file.getPath(), bfOptions);
+ final Bitmap image = BitmapFactory.decodeFile(file.getPath(), bfOptions);
+ if (image == null) {
+ Log.e("Cannot decode bitmap from " + file.getPath());
+ }
+ return image;
}
}
return null;
@@ -205,20 +211,14 @@ public class HtmlImage implements Html.ImageGetter {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
- FileInputStream fis = null;
+ BufferedInputStream stream = null;
try {
- fis = new FileInputStream(file);
- BitmapFactory.decodeStream(fis, null, options);
+ stream = new BufferedInputStream(new FileInputStream(file));
+ BitmapFactory.decodeStream(stream, null, options);
} catch (FileNotFoundException e) {
Log.e("HtmlImage.setSampleSize", e);
} finally {
- if (fis != null) {
- try {
- fis.close();
- } catch (IOException e) {
- // ignore
- }
- }
+ IOUtils.closeQuietly(stream);
}
int scale = 1;
diff --git a/main/src/cgeo/geocaching/network/Network.java b/main/src/cgeo/geocaching/network/Network.java
index eb6a6ac..5a8cbb2 100644
--- a/main/src/cgeo/geocaching/network/Network.java
+++ b/main/src/cgeo/geocaching/network/Network.java
@@ -40,6 +40,9 @@ import org.apache.commons.lang3.StringUtils;
import org.json.JSONException;
import org.json.JSONObject;
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo;
import android.net.Uri;
import java.io.File;
@@ -471,4 +474,19 @@ public abstract class Network {
return null;
}
+ /**
+ * Checks if the device has network connection.
+ *
+ * @param context
+ * context of the application, cannot be null
+ *
+ * @return <code>true</code> if the device is connected to the network.
+ */
+ public static boolean isNetworkConnected(Context context) {
+ ConnectivityManager conMan = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+ NetworkInfo activeNetwork = conMan.getActiveNetworkInfo();
+
+ return activeNetwork != null && activeNetwork.isConnected();
+ }
+
}
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/network/StatusUpdater.java b/main/src/cgeo/geocaching/network/StatusUpdater.java
index 1953e1d..bfc77ba 100644
--- a/main/src/cgeo/geocaching/network/StatusUpdater.java
+++ b/main/src/cgeo/geocaching/network/StatusUpdater.java
@@ -3,6 +3,7 @@ package cgeo.geocaching.network;
import cgeo.geocaching.cgeoapplication;
import cgeo.geocaching.utils.MemorySubject;
import cgeo.geocaching.utils.PeriodicHandler;
+import cgeo.geocaching.utils.PeriodicHandler.PeriodicHandlerListener;
import cgeo.geocaching.utils.Version;
import org.json.JSONException;
@@ -12,7 +13,7 @@ import android.os.Looper;
import java.util.Locale;
-public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implements Runnable {
+public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implements Runnable, PeriodicHandlerListener {
static public class Status {
final public String message;
@@ -28,7 +29,8 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
}
}
- private void requestUpdate() {
+ @Override
+ public void onPeriodic() {
final JSONObject response =
Network.requestJSON("http://status.cgeo.org/api/status.json",
new Parameters("version_code", String.valueOf(Version.getVersionCode(cgeoapplication.getInstance())),
@@ -50,12 +52,7 @@ public class StatusUpdater extends MemorySubject<StatusUpdater.Status> implement
@Override
public void run() {
Looper.prepare();
- new PeriodicHandler(1800000L) {
- @Override
- public void act() {
- requestUpdate();
- }
- }.start();
+ new PeriodicHandler(1800000L, this).start();
Looper.loop();
}