diff --git a/OsmAnd-java/build.gradle b/OsmAnd-java/build.gradle index 4385f9d0b0..2c5415a84f 100644 --- a/OsmAnd-java/build.gradle +++ b/OsmAnd-java/build.gradle @@ -1,6 +1,6 @@ apply plugin: 'java' apply plugin: 'maven-publish' - + configurations { android } @@ -104,6 +104,9 @@ dependencies { implementation 'com.moparisthebest:junidecode:0.1.1' implementation 'com.vividsolutions:jts-core:1.14.0' implementation 'com.google.openlocationcode:openlocationcode:1.0.4' + implementation ('com.github.scribejava:scribejava-apis:7.1.1') { + exclude group: "com.fasterxml.jackson.core" + } // turn off for now //implementation 'com.atilika.kuromoji:kuromoji-ipadic:0.9.0' implementation 'net.sf.kxml:kxml2:2.1.8' diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/io/NetworkUtils.java b/OsmAnd-java/src/main/java/net/osmand/osm/io/NetworkUtils.java index 282d6addbd..28a1ec3fb9 100644 --- a/OsmAnd-java/src/main/java/net/osmand/osm/io/NetworkUtils.java +++ b/OsmAnd-java/src/main/java/net/osmand/osm/io/NetworkUtils.java @@ -1,30 +1,22 @@ package net.osmand.osm.io; -import java.io.BufferedInputStream; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.net.HttpURLConnection; -import java.net.InetSocketAddress; -import java.net.MalformedURLException; -import java.net.Proxy; -import java.net.URL; -import java.net.URLEncoder; -import java.util.Map; -import java.util.zip.GZIPOutputStream; - +import com.github.scribejava.core.model.OAuthRequest; +import com.github.scribejava.core.model.Response; +import com.github.scribejava.core.model.Verb; import net.osmand.PlatformUtil; +import net.osmand.osm.oauth.OsmOAuthAuthorizationClient; import net.osmand.util.Algorithms; - import org.apache.commons.logging.Log; +import java.io.*; +import java.net.*; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.zip.GZIPOutputStream; + public class NetworkUtils { private static final Log log = PlatformUtil.getLog(NetworkUtils.class); - + private static final String GPX_UPLOAD_USER_AGENT = "OsmGPXUploadAgent"; private static Proxy proxy = null; public static String sendGetRequest(String urlText, String userNamePassword, StringBuilder responseBody){ @@ -55,7 +47,6 @@ public class NetworkUtils { responseBody.append("\n"); //$NON-NLS-1$ } responseBody.append(s); - } is.close(); } @@ -65,9 +56,10 @@ public class NetworkUtils { return e.getMessage(); } } - private static final String BOUNDARY = "CowMooCowMooCowCowCow"; //$NON-NLS-1$ - public static String uploadFile(String urlText, File fileToUpload, String userNamePassword, String formName, boolean gzip, Map additionalMapData){ + public static String uploadFile(String urlText, File fileToUpload, String userNamePassword, + OsmOAuthAuthorizationClient client, + String formName, boolean gzip, Map additionalMapData){ URL url; try { boolean firstPrm =!urlText.contains("?"); @@ -77,34 +69,48 @@ public class NetworkUtils { } log.info("Start uploading file to " + urlText + " " +fileToUpload.getName()); url = new URL(urlText); - HttpURLConnection conn = (HttpURLConnection) url.openConnection(); - conn.setDoInput(true); - conn.setDoOutput(true); - conn.setRequestMethod("POST"); - if(userNamePassword != null) { - conn.setRequestProperty("Authorization", "Basic " + Base64.encode(userNamePassword)); //$NON-NLS-1$ //$NON-NLS-2$ + HttpURLConnection conn; + if (client != null && client.isValidToken()){ + OAuthRequest req = new OAuthRequest(Verb.POST, urlText); + client.getService().signRequest(client.getAccessToken(), req); + req.addHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); + try { + Response r = client.getHttpClient().execute(GPX_UPLOAD_USER_AGENT, req.getHeaders(), req.getVerb(), + req.getCompleteUrl(), fileToUpload); + if (r.getCode() != 200) { + return r.getBody(); + } + return null; + } catch (InterruptedException e) { + log.error(e); + } catch (ExecutionException e) { + log.error(e); + } + return null; + } + else { + conn = (HttpURLConnection) url.openConnection(); + conn.setDoInput(true); + conn.setDoOutput(true); + conn.setRequestMethod("POST"); + if(userNamePassword != null) { + conn.setRequestProperty("Authorization", "Basic " + Base64.encode(userNamePassword)); //$NON-NLS-1$ //$NON-NLS-2$ + } } - conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); //$NON-NLS-1$ //$NON-NLS-2$ conn.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$ - OutputStream ous = conn.getOutputStream(); -// for (String key : additionalMapData.keySet()) { -// ous.write(("--" + BOUNDARY + "\r\n").getBytes()); -// ous.write(("content-disposition: form-data; name=\"" + key + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ -// ous.write((additionalMapData.get(key) + "\r\n").getBytes()); -// } - ous.write(("--" + BOUNDARY+"\r\n").getBytes()); + ous.write(("--" + BOUNDARY + "\r\n").getBytes()); String filename = fileToUpload.getName(); - if(gzip){ - filename+=".gz"; + if (gzip) { + filename += ".gz"; } - ous.write(("content-disposition: form-data; name=\""+formName+"\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ - ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$ - InputStream fis = new FileInputStream(fileToUpload); + ous.write(("content-disposition: form-data; name=\"" + formName + "\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ + ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$ + InputStream fis = new FileInputStream(fileToUpload); BufferedInputStream bis = new BufferedInputStream(fis, 20 * 1024); ous.flush(); - if(gzip){ + if (gzip) { GZIPOutputStream gous = new GZIPOutputStream(ous, 1024); Algorithms.streamCopy(bis, gous); gous.flush(); @@ -112,8 +118,7 @@ public class NetworkUtils { } else { Algorithms.streamCopy(bis, ous); } - - ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ + ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ ous.flush(); Algorithms.closeStream(bis); Algorithms.closeStream(ous); @@ -136,7 +141,6 @@ public class NetworkUtils { responseBody.append("\n"); //$NON-NLS-1$ } responseBody.append(s); - } is.close(); } @@ -157,7 +161,6 @@ public class NetworkUtils { proxy = null; } } - public static Proxy getProxy() { return proxy; } diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/oauth/OsmAndJDKHttpClient.java b/OsmAnd-java/src/main/java/net/osmand/osm/oauth/OsmAndJDKHttpClient.java new file mode 100644 index 0000000000..9b320119ee --- /dev/null +++ b/OsmAnd-java/src/main/java/net/osmand/osm/oauth/OsmAndJDKHttpClient.java @@ -0,0 +1,259 @@ +package net.osmand.osm.oauth; + +import com.github.scribejava.core.exceptions.OAuthException; +import com.github.scribejava.core.httpclient.HttpClient; +import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig; +import com.github.scribejava.core.httpclient.jdk.JDKHttpFuture; +import com.github.scribejava.core.httpclient.multipart.MultipartPayload; +import com.github.scribejava.core.httpclient.multipart.MultipartUtils; +import com.github.scribejava.core.model.*; +import net.osmand.util.Algorithms; + +import java.io.*; +import java.net.HttpURLConnection; +import java.net.URL; +import java.net.UnknownHostException; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +public class OsmAndJDKHttpClient implements HttpClient { + private static final String BOUNDARY = "CowMooCowMooCowCowCow"; + private final JDKHttpClientConfig config; + + public OsmAndJDKHttpClient() { + this(JDKHttpClientConfig.defaultConfig()); + } + + public OsmAndJDKHttpClient(JDKHttpClientConfig clientConfig) { + config = clientConfig; + } + + @Override + public void close() { + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + byte[] bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.BYTE_ARRAY, bodyContents, callback, + converter); + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + MultipartPayload bodyContents, OAuthAsyncRequestCallback callback, + OAuthRequest.ResponseConverter converter) { + + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, bodyContents, callback, + converter); + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + String bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.STRING, bodyContents, callback, + converter); + } + + @Override + public Future executeAsync(String userAgent, Map headers, Verb httpVerb, String completeUrl, + File bodyContents, OAuthAsyncRequestCallback callback, OAuthRequest.ResponseConverter converter) { + return doExecuteAsync(userAgent, headers, httpVerb, completeUrl, BodyType.STREAM, bodyContents, callback, + converter); + } + + private Future doExecuteAsync(String userAgent, Map headers, Verb httpVerb, + String completeUrl, BodyType bodyType, Object bodyContents, OAuthAsyncRequestCallback callback, + OAuthRequest.ResponseConverter converter) { + try { + final Response response = doExecute(userAgent, headers, httpVerb, completeUrl, bodyType, bodyContents); + @SuppressWarnings("unchecked") final T t = converter == null ? (T) response : converter.convert(response); + if (callback != null) { + callback.onCompleted(t); + } + return new JDKHttpFuture<>(t); + } catch (IOException | RuntimeException e) { + if (callback != null) { + callback.onThrowable(e); + } + return new JDKHttpFuture<>(e); + } + } + + @Override + public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, + byte[] bodyContents) throws InterruptedException, ExecutionException, IOException { + return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.BYTE_ARRAY, bodyContents); + } + + @Override + public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, + MultipartPayload multipartPayloads) throws InterruptedException, ExecutionException, IOException { + return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.MULTIPART, multipartPayloads); + } + + @Override + public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, + String bodyContents) throws InterruptedException, ExecutionException, IOException { + return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.STRING, bodyContents); + } + + @Override + public Response execute(String userAgent, Map headers, Verb httpVerb, String completeUrl, + File bodyContents) throws InterruptedException, ExecutionException, IOException { + return doExecute(userAgent, headers, httpVerb, completeUrl, BodyType.STREAM, bodyContents); + } + + private Response doExecute(String userAgent, Map headers, Verb httpVerb, String completeUrl, + BodyType bodyType, Object bodyContents) throws IOException { + final URL url = new URL(completeUrl); + final HttpURLConnection connection; + if (config.getProxy() == null) { + connection = (HttpURLConnection) url.openConnection(); + } else { + connection = (HttpURLConnection) url.openConnection(config.getProxy()); + } + connection.setInstanceFollowRedirects(config.isFollowRedirects()); + connection.setRequestMethod(httpVerb.name()); + if (config.getConnectTimeout() != null) { + connection.setConnectTimeout(config.getConnectTimeout()); + } + if (config.getReadTimeout() != null) { + connection.setReadTimeout(config.getReadTimeout()); + } + addHeaders(connection, headers, userAgent); + if (httpVerb.isPermitBody()) { + bodyType.setBody(connection, bodyContents, httpVerb.isRequiresBody()); + } + + try { + connection.connect(); + final int responseCode = connection.getResponseCode(); + return new Response(responseCode, connection.getResponseMessage(), parseHeaders(connection), + responseCode >= 200 && responseCode < 400 ? connection.getInputStream() + : connection.getErrorStream()); + } catch (UnknownHostException e) { + throw new OAuthException("The IP address of a host could not be determined.", e); + } + } + + private enum BodyType { + BYTE_ARRAY { + @Override + void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException { + addBody(connection, (byte[]) bodyContents, requiresBody); + } + }, + STREAM { + @Override + void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException { + addBody(connection, (File) bodyContents, requiresBody); + } + }, + MULTIPART { + @Override + void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException { + addBody(connection, (MultipartPayload) bodyContents, requiresBody); + } + }, + STRING { + @Override + void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) throws IOException { + addBody(connection, ((String) bodyContents).getBytes(), requiresBody); + } + }; + + abstract void setBody(HttpURLConnection connection, Object bodyContents, boolean requiresBody) + throws IOException; + } + + private static Map parseHeaders(HttpURLConnection conn) { + final Map headers = new HashMap<>(); + + for (Map.Entry> headerField : conn.getHeaderFields().entrySet()) { + final String key = headerField.getKey(); + final String value = headerField.getValue().get(0); + if ("Content-Encoding".equalsIgnoreCase(key)) { + headers.put("Content-Encoding", value); + } else { + headers.put(key, value); + } + } + return headers; + } + + private static void addHeaders(HttpURLConnection connection, Map headers, String userAgent) { + for (Map.Entry header : headers.entrySet()) { + connection.setRequestProperty(header.getKey(), header.getValue()); + } + + if (userAgent != null) { + connection.setRequestProperty(OAuthConstants.USER_AGENT_HEADER_NAME, userAgent); + } + } + + private static void addBody(HttpURLConnection connection, File file, boolean requiresBody) throws IOException { + if (requiresBody) { + String filename = file.getName(); + String formName = "file"; + InputStream stream = new FileInputStream(file); + connection.setDoInput(true); + connection.setDoOutput(true); + connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY); //$NON-NLS-1$ //$NON-NLS-2$ + connection.setRequestProperty("User-Agent", "OsmAnd"); //$NON-NLS-1$ //$NON-NLS-2$ + final OutputStream ous = connection.getOutputStream(); + ous.write(("--" + BOUNDARY + "\r\n").getBytes()); + ous.write(("content-disposition: form-data; name=\"" + formName + "\"; filename=\"" + filename + "\"\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ + ous.write(("Content-Type: application/octet-stream\r\n\r\n").getBytes()); //$NON-NLS-1$ + BufferedInputStream bis = new BufferedInputStream(stream, 20 * 1024); + ous.flush(); + Algorithms.streamCopy(bis, ous); + ous.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes()); //$NON-NLS-1$ //$NON-NLS-2$ + ous.flush(); + Algorithms.closeStream(bis); + } + } + + private static void addBody(HttpURLConnection connection, byte[] content, boolean requiresBody) throws IOException { + final int contentLength = content.length; + if (requiresBody || contentLength > 0) { + connection.setDoOutput(true); + final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength); + if (contentLength > 0) { + outputStream.write(content); + } + } + } + + private static void addBody(HttpURLConnection connection, MultipartPayload multipartPayload, boolean requiresBody) + throws IOException { + + for (Map.Entry header : multipartPayload.getHeaders().entrySet()) { + connection.setRequestProperty(header.getKey(), header.getValue()); + } + + if (requiresBody) { + final ByteArrayOutputStream os = MultipartUtils.getPayload(multipartPayload); + final int contentLength = os.size(); + connection.setDoOutput(true); + final OutputStream outputStream = prepareConnectionForBodyAndGetOutputStream(connection, contentLength); + if (contentLength > 0) { + os.writeTo(outputStream); + } + } + } + + private static OutputStream prepareConnectionForBodyAndGetOutputStream(HttpURLConnection connection, + int contentLength) throws IOException { + connection.setRequestProperty(CONTENT_LENGTH, String.valueOf(contentLength)); + if (connection.getRequestProperty(CONTENT_TYPE) == null) { + connection.setRequestProperty(CONTENT_TYPE, DEFAULT_CONTENT_TYPE); + } + return connection.getOutputStream(); + } +} \ No newline at end of file diff --git a/OsmAnd-java/src/main/java/net/osmand/osm/oauth/OsmOAuthAuthorizationClient.java b/OsmAnd-java/src/main/java/net/osmand/osm/oauth/OsmOAuthAuthorizationClient.java new file mode 100644 index 0000000000..f1c718465e --- /dev/null +++ b/OsmAnd-java/src/main/java/net/osmand/osm/oauth/OsmOAuthAuthorizationClient.java @@ -0,0 +1,149 @@ +// License: GPL. For details, see LICENSE file. +package net.osmand.osm.oauth; + +import com.github.scribejava.core.builder.ServiceBuilder; +import com.github.scribejava.core.builder.api.DefaultApi10a; +import com.github.scribejava.core.builder.api.OAuth1SignatureType; +import com.github.scribejava.core.httpclient.jdk.JDKHttpClientConfig; +import com.github.scribejava.core.model.*; +import com.github.scribejava.core.oauth.OAuth10aService; +import net.osmand.PlatformUtil; +import org.apache.commons.logging.Log; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +/** + * An OAuth 1.0 authorization client. + * + * @since 2746 + */ +public class OsmOAuthAuthorizationClient { + private OAuth1RequestToken requestToken; + private OAuth1AccessToken accessToken; + private final OAuth10aService service; + private final OsmAndJDKHttpClient httpClient; + public final static Log log = PlatformUtil.getLog(OsmOAuthAuthorizationClient.class); + + public OsmOAuthAuthorizationClient(String key, String secret) { + httpClient = new OsmAndJDKHttpClient(JDKHttpClientConfig.defaultConfig()); + service = new ServiceBuilder(key) + .apiSecret(secret) + .httpClient(httpClient) + .callback("osmand-oauth://example.com/oauth") + .build(new OsmApi()); + } + + static class OsmApi extends DefaultApi10a { + @Override + public OAuth1SignatureType getSignatureType() { + return OAuth1SignatureType.QUERY_STRING; + } + + @Override + public String getRequestTokenEndpoint() { + return "https://www.openstreetmap.org/oauth/request_token"; + } + + @Override + public String getAccessTokenEndpoint() { + return "https://www.openstreetmap.org/oauth/access_token"; + } + + @Override + protected String getAuthorizationBaseUrl() { + return "https://www.openstreetmap.org/oauth/authorize"; + } + } + + public OsmAndJDKHttpClient getHttpClient() { + return httpClient; + } + + public OAuth10aService getService() { + return service; + } + + public void setAccessToken(OAuth1AccessToken accessToken) { + this.accessToken = accessToken; + } + + public OAuth1AccessToken getAccessToken() { + return accessToken; + } + + public Response performRequestWithoutAuth(String url, String requestMethod, String requestBody) + throws InterruptedException, ExecutionException, IOException { + Verb verb = parseRequestMethod(requestMethod); + OAuthRequest req = new OAuthRequest(verb, url); + req.setPayload(requestBody); + return service.execute(req); + } + + public void performGetRequest(String url, OAuthAsyncRequestCallback callback) { + if (accessToken == null) { + throw new IllegalStateException("Access token is null"); + } + OAuthRequest req = new OAuthRequest(Verb.GET, url); + service.signRequest(accessToken, req); + service.execute(req, callback); + } + + public Response performRequest(String url, String method, String body) + throws InterruptedException, ExecutionException, IOException { + service.getApi().getSignatureType(); + if (accessToken == null) { + throw new IllegalStateException("Access token is null"); + } + Verb verbMethod = parseRequestMethod(method); + OAuthRequest req = new OAuthRequest(verbMethod, url); + req.setPayload(body); + service.signRequest(accessToken, req); + req.addHeader("Content-Type", "application/xml"); + return service.execute(req); + } + + public OAuth1RequestToken startOAuth() { + try { + requestToken = service.getRequestToken(); + } catch (IOException e) { + log.error(e); + } catch (InterruptedException e) { + log.error(e); + } catch (ExecutionException e) { + log.error(e); + } + return requestToken; + } + + public OAuth1AccessToken authorize(String oauthVerifier) { + try { + setAccessToken(service.getAccessToken(requestToken, oauthVerifier)); + } catch (IOException e) { + log.error(e); + } catch (InterruptedException e) { + log.error(e); + } catch (ExecutionException e) { + log.error(e); + } + return accessToken; + } + + public boolean isValidToken() { + return !(accessToken == null); + } + + private Verb parseRequestMethod(String method) { + Verb m = Verb.GET; + if (method.equals("POST")) { + m = Verb.POST; + } + if (method.equals("PUT")) { + m = Verb.PUT; + } + if (method.equals("DELETE")) { + m = Verb.DELETE; + } + return m; + } +} diff --git a/OsmAnd/AndroidManifest.xml b/OsmAnd/AndroidManifest.xml index 2c6d6b6463..4e5395a04a 100644 --- a/OsmAnd/AndroidManifest.xml +++ b/OsmAnd/AndroidManifest.xml @@ -7,7 +7,7 @@ - + @@ -52,7 +52,7 @@ @@ -65,7 +65,7 @@ - + - + + + + + + + + @@ -1025,7 +1034,7 @@ + Logout successful + Clear OpenStreetMap OAuth token + Log in via OAuth + Perform an OAuth Login to use osmedit features Switch to Java (safe) Public Transport routing calculation Native Public Transport development Recalculates only the initial part of the route. Can be used for long trips. diff --git a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java index 80ce6cfb27..7e0aadfa3b 100644 --- a/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java +++ b/OsmAnd/src/net/osmand/plus/download/DownloadIndexesThread.java @@ -5,6 +5,7 @@ import android.app.Activity; import android.content.ActivityNotFoundException; import android.content.DialogInterface; import android.content.Intent; +import android.net.TrafficStats; import android.net.Uri; import android.os.AsyncTask; import android.os.AsyncTask.Status; @@ -58,8 +59,8 @@ public class DownloadIndexesThread { private ConcurrentLinkedQueue indexItemDownloading = new ConcurrentLinkedQueue(); private IndexItem currentDownloadingItem = null; private int currentDownloadingItemProgress = 0; - private DownloadResources indexes; + private static final int THREAD_ID = 10103; public interface DownloadEvents { @@ -336,6 +337,7 @@ public class DownloadIndexesThread { @Override protected DownloadResources doInBackground(Void... params) { + TrafficStats.setThreadStatsTag(THREAD_ID); DownloadResources result = null; DownloadOsmandIndexesHelper.IndexFileList indexFileList = DownloadOsmandIndexesHelper.getIndexesList(ctx); if (indexFileList != null) { diff --git a/OsmAnd/src/net/osmand/plus/osmedit/EditPOIMenuController.java b/OsmAnd/src/net/osmand/plus/osmedit/EditPOIMenuController.java index 47c2eb5200..7d04c73252 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/EditPOIMenuController.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/EditPOIMenuController.java @@ -2,10 +2,8 @@ package net.osmand.plus.osmedit; import android.content.DialogInterface; import android.graphics.drawable.Drawable; - import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; - import net.osmand.data.PointDescription; import net.osmand.osm.PoiType; import net.osmand.plus.OsmandPlugin; @@ -14,6 +12,7 @@ import net.osmand.plus.activities.MapActivity; import net.osmand.plus.mapcontextmenu.MenuController; import net.osmand.plus.osmedit.OsmPoint.Action; import net.osmand.plus.osmedit.dialogs.SendPoiDialogFragment; +import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter; import net.osmand.plus.render.RenderingIcons; import net.osmand.util.Algorithms; @@ -39,9 +38,16 @@ public class EditPOIMenuController extends MenuController { public void buttonPressed() { MapActivity activity = getMapActivity(); if (plugin != null && activity != null) { - SendPoiDialogFragment sendPoiDialogFragment = - SendPoiDialogFragment.createInstance(new OsmPoint[]{getOsmPoint()}, SendPoiDialogFragment.PoiUploaderType.SIMPLE); - sendPoiDialogFragment.show(activity.getSupportFragmentManager(), SendPoiDialogFragment.TAG); + OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(activity.getMyApplication()); + if (client.isValidToken()){ + new SendPoiDialogFragment.SimpleProgressDialogPoiUploader(activity). + showProgressDialog(new OsmPoint[] { getOsmPoint() }, false, false); + } + else { + SendPoiDialogFragment sendPoiDialogFragment = + SendPoiDialogFragment.createInstance(new OsmPoint[]{getOsmPoint()}, SendPoiDialogFragment.PoiUploaderType.SIMPLE); + sendPoiDialogFragment.show(activity.getSupportFragmentManager(), SendPoiDialogFragment.TAG); + } } } }; diff --git a/OsmAnd/src/net/osmand/plus/osmedit/OpenstreetmapRemoteUtil.java b/OsmAnd/src/net/osmand/plus/osmedit/OpenstreetmapRemoteUtil.java index 3577987a8b..393dd7d965 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/OpenstreetmapRemoteUtil.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/OpenstreetmapRemoteUtil.java @@ -2,7 +2,8 @@ package net.osmand.plus.osmedit; import android.util.Xml; import android.widget.Toast; - +import com.github.scribejava.core.model.Response; +import gnu.trove.list.array.TLongArrayList; import net.osmand.NativeLibrary; import net.osmand.PlatformUtil; import net.osmand.data.Amenity; @@ -17,38 +18,29 @@ import net.osmand.osm.edit.Entity.EntityType; import net.osmand.osm.edit.EntityInfo; import net.osmand.osm.edit.Node; import net.osmand.osm.edit.Way; -import net.osmand.osm.io.Base64; import net.osmand.osm.io.NetworkUtils; import net.osmand.osm.io.OsmBaseStorage; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.Version; +import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.MapUtils; - import org.apache.commons.logging.Log; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; -import java.io.BufferedReader; -import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.File; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.OutputStream; -import java.io.OutputStreamWriter; import java.io.StringWriter; -import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.text.MessageFormat; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; - -import gnu.trove.list.array.TLongArrayList; +import java.util.concurrent.ExecutionException; public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { @@ -99,12 +91,16 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { private final static String URL_TO_UPLOAD_GPX = getSiteApi() + "api/0.6/gpx/create"; public String uploadGPXFile(String tagstring, String description, String visibility, File f) { + OsmOAuthAuthorizationAdapter adapter = new OsmOAuthAuthorizationAdapter(ctx); String url = URL_TO_UPLOAD_GPX; Map additionalData = new LinkedHashMap(); additionalData.put("description", description); additionalData.put("tags", tagstring); additionalData.put("visibility", visibility); - return NetworkUtils.uploadFile(url, f, settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(), "file", + return NetworkUtils.uploadFile(url, f, + settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(), + adapter.getClient(), + "file", true, additionalData); } @@ -112,53 +108,15 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { boolean doAuthenticate) { log.info("Sending request " + url); //$NON-NLS-1$ try { - HttpURLConnection connection = NetworkUtils.getHttpURLConnection(url); - - connection.setConnectTimeout(15000); - connection.setRequestMethod(requestMethod); - connection.setRequestProperty("User-Agent", Version.getFullVersion(ctx)); //$NON-NLS-1$ - StringBuilder responseBody = new StringBuilder(); - if (doAuthenticate) { - String token = settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(); //$NON-NLS-1$ - connection.addRequestProperty("Authorization", "Basic " + Base64.encode(token.getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (doAuthenticate){ + OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(ctx); + Response response = client.performRequest(url,requestMethod,requestBody); + return response.getBody(); } - connection.setDoInput(true); - if (requestMethod.equals("PUT") || requestMethod.equals("POST") || requestMethod.equals("DELETE")) { //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ - connection.setDoOutput(true); - connection.setRequestProperty("Content-type", "text/xml"); //$NON-NLS-1$ //$NON-NLS-2$ - OutputStream out = connection.getOutputStream(); - if (requestBody != null) { - BufferedWriter bwr = new BufferedWriter(new OutputStreamWriter(out, "UTF-8"), 1024); //$NON-NLS-1$ - bwr.write(requestBody); - bwr.flush(); - } - out.close(); - } - connection.connect(); - if (connection.getResponseCode() != HttpURLConnection.HTTP_OK) { - String msg = userOperation - + " " + ctx.getString(R.string.failed_op) + " : " + connection.getResponseMessage(); //$NON-NLS-1$//$NON-NLS-2$ - log.error(msg); - showWarning(msg); - } else { - log.info("Response : " + connection.getResponseMessage()); //$NON-NLS-1$ - // populate return fields. - responseBody.setLength(0); - InputStream i = connection.getInputStream(); - if (i != null) { - BufferedReader in = new BufferedReader(new InputStreamReader(i, "UTF-8"), 256); //$NON-NLS-1$ - String s; - boolean f = true; - while ((s = in.readLine()) != null) { - if (!f) { - responseBody.append("\n"); //$NON-NLS-1$ - } else { - f = false; - } - responseBody.append(s); - } - } - return responseBody.toString(); + else { + OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(ctx); + Response response = client.performRequestWithoutAuth(url,requestMethod,requestBody); + return response.getBody(); } } catch (NullPointerException e) { // that's tricky case why NPE is thrown to fix that problem httpClient could be used @@ -173,6 +131,14 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { log.error(userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$ showWarning(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template) + ": " + ctx.getResources().getString(R.string.shared_string_io_error), userOperation)); + } catch (InterruptedException e) { + log.error(userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$ + showWarning(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template) + + ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation)); + } catch (ExecutionException e) { + log.error(userOperation + " " + ctx.getString(R.string.failed_op), e); //$NON-NLS-1$ + showWarning(MessageFormat.format(ctx.getResources().getString(R.string.shared_string_action_template) + + ": " + ctx.getResources().getString(R.string.shared_string_unexpected_error), userOperation)); } return null; @@ -206,12 +172,16 @@ public class OpenstreetmapRemoteUtil implements OpenstreetmapUtil { } catch (IOException e) { log.error("Unhandled exception", e); //$NON-NLS-1$ } - String response = sendRequest( - getSiteApi() + "api/0.6/changeset/create/", "PUT", writer.getBuffer().toString(), ctx.getString(R.string.opening_changeset), true); //$NON-NLS-1$ //$NON-NLS-2$ - if (response != null && response.length() > 0) { - id = Long.parseLong(response); + String response = sendRequest( + getSiteApi() + "api/0.6/changeset/create/", "PUT", writer.getBuffer().toString(), ctx.getString(R.string.opening_changeset), true); //$NON-NLS-1$ //$NON-NLS-2$ + try { + if (response != null && response.length() > 0) { + log.debug(response); + id = Long.parseLong(response); + } + } catch (Exception e) { + log.error(e); } - return id; } diff --git a/OsmAnd/src/net/osmand/plus/osmedit/OsmBugsRemoteUtil.java b/OsmAnd/src/net/osmand/plus/osmedit/OsmBugsRemoteUtil.java index 8d1238e324..a6e2dd5ca8 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/OsmBugsRemoteUtil.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/OsmBugsRemoteUtil.java @@ -5,12 +5,12 @@ import net.osmand.PlatformUtil; import net.osmand.osm.io.Base64; import net.osmand.osm.io.NetworkUtils; import net.osmand.plus.OsmandApplication; -import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.R; import net.osmand.plus.Version; import net.osmand.plus.osmedit.OsmPoint.Action; +import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.util.Algorithms; - import org.apache.commons.logging.Log; import java.io.FileNotFoundException; @@ -109,6 +109,7 @@ public class OsmBugsRemoteUtil implements OsmBugsUtil { private OsmBugResult editingPOI(String url, String requestMethod, String userOperation, boolean anonymous) { + OsmOAuthAuthorizationAdapter client = new OsmOAuthAuthorizationAdapter(app); OsmBugResult r = new OsmBugResult(); try { HttpURLConnection connection = NetworkUtils.getHttpURLConnection(url); @@ -118,8 +119,12 @@ public class OsmBugsRemoteUtil implements OsmBugsUtil { connection.setRequestProperty("User-Agent", Version.getFullVersion(app)); //$NON-NLS-1$ if (!anonymous) { - String token = settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(); //$NON-NLS-1$ - connection.addRequestProperty("Authorization", "Basic " + Base64.encode(token.getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + if (client.isValidToken()) { + connection.addRequestProperty("Authorization", "OAuth " + client.getClient().getAccessToken().getToken()); + } else { + String token = settings.USER_NAME.get() + ":" + settings.USER_PASSWORD.get(); //$NON-NLS-1$ + connection.addRequestProperty("Authorization", "Basic " + Base64.encode(token.getBytes("UTF-8"))); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + } } connection.setDoInput(true); diff --git a/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java b/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java index f12f18c852..5030530f88 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/OsmEditingPlugin.java @@ -13,11 +13,9 @@ import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.Spinner; import android.widget.Toast; - import androidx.annotation.NonNull; import androidx.appcompat.app.AlertDialog; import androidx.fragment.app.Fragment; - import net.osmand.AndroidUtils; import net.osmand.PlatformUtil; import net.osmand.data.Amenity; @@ -25,7 +23,7 @@ import net.osmand.data.MapObject; import net.osmand.data.TransportStop; import net.osmand.osm.PoiType; import net.osmand.osm.edit.Entity; -import net.osmand.plus.ContextMenuAdapter; +import net.osmand.plus.*; import net.osmand.plus.ContextMenuAdapter.ItemClickListener; import net.osmand.plus.ContextMenuItem; import net.osmand.plus.OsmandApplication; @@ -44,22 +42,16 @@ import net.osmand.plus.myplaces.AvailableGPXFragment.GpxInfo; import net.osmand.plus.myplaces.FavoritesActivity; import net.osmand.plus.osmedit.OsmPoint.Action; import net.osmand.plus.quickaction.QuickActionType; +import net.osmand.plus.settings.backend.OsmandSettings; import net.osmand.plus.settings.fragments.BaseSettingsFragment; import net.osmand.plus.views.OsmandMapTileView; import net.osmand.util.Algorithms; - import org.apache.commons.logging.Log; import java.util.ArrayList; import java.util.List; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_CREATE_POI; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MODIFY_OSM_CHANGE; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MODIFY_OSM_NOTE; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_MODIFY_POI; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.MAP_CONTEXT_MENU_OPEN_OSM_NOTE; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.OSM_EDITS; -import static net.osmand.aidlapi.OsmAndCustomizationConstants.OSM_NOTES; +import static net.osmand.aidlapi.OsmAndCustomizationConstants.*; import static net.osmand.plus.ContextMenuAdapter.makeDeleteAction; @@ -465,7 +457,8 @@ public class OsmEditingPlugin extends OsmandPlugin { public boolean sendGPXFiles(final Activity la, AvailableGPXFragment f, final GpxInfo... info) { String name = settings.USER_NAME.get(); String pwd = settings.USER_PASSWORD.get(); - if (Algorithms.isEmpty(name) || Algorithms.isEmpty(pwd)) { + String authToken = settings.USER_ACCESS_TOKEN.get(); + if ((Algorithms.isEmpty(name) || Algorithms.isEmpty(pwd)) && Algorithms.isEmpty(authToken)) { Toast.makeText(la, R.string.validate_gpx_upload_name_pwd, Toast.LENGTH_LONG).show(); return false; } diff --git a/OsmAnd/src/net/osmand/plus/osmedit/SettingsOsmEditingActivity.java b/OsmAnd/src/net/osmand/plus/osmedit/SettingsOsmEditingActivity.java index ea259db512..4f1410dc4c 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/SettingsOsmEditingActivity.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/SettingsOsmEditingActivity.java @@ -3,8 +3,10 @@ package net.osmand.plus.osmedit; import android.content.Context; import android.content.Intent; +import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; +import android.os.StrictMode; import android.preference.CheckBoxPreference; import android.preference.DialogPreference; import android.preference.Preference; @@ -12,22 +14,40 @@ import android.preference.Preference.OnPreferenceClickListener; import android.preference.PreferenceScreen; import android.util.AttributeSet; import android.view.View; +import android.view.ViewGroup; import android.widget.TextView; import android.widget.Toast; - -import net.osmand.plus.settings.backend.OsmAndAppCustomization; +import com.github.scribejava.core.model.OAuthAsyncRequestCallback; +import com.github.scribejava.core.model.Response; +import net.osmand.PlatformUtil; import net.osmand.plus.OsmandApplication; import net.osmand.plus.OsmandPlugin; import net.osmand.plus.R; import net.osmand.plus.activities.SettingsBaseActivity; +import net.osmand.plus.osmedit.oauth.OsmOAuthAuthorizationAdapter; +import net.osmand.plus.settings.backend.OsmAndAppCustomization; +import org.apache.commons.logging.Log; + +import java.io.IOException; public class SettingsOsmEditingActivity extends SettingsBaseActivity { - + private OsmOAuthAuthorizationAdapter client; + private static final Log log = PlatformUtil.getLog(SettingsOsmEditingActivity.class); @Override public void onCreate(Bundle savedInstanceState) { + StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder() + .detectDiskReads() + .detectDiskWrites() + .detectNetwork() + .penaltyLog() + .build()); + ((OsmandApplication) getApplication()).applyTheme(this); super.onCreate(savedInstanceState); + + client = new OsmOAuthAuthorizationAdapter(getMyApplication()); + getToolbar().setTitle(R.string.osm_settings); @SuppressWarnings("deprecation") PreferenceScreen grp = getPreferenceScreen(); @@ -39,7 +59,7 @@ public class SettingsOsmEditingActivity extends SettingsBaseActivity { R.string.offline_edition, R.string.offline_edition_descr); grp.addPreference(poiEdit); - Preference pref = new Preference(this); + final Preference pref = new Preference(this); pref.setTitle(R.string.local_openstreetmap_settings); pref.setSummary(R.string.local_openstreetmap_settings_descr); pref.setKey("local_openstreetmap_points"); @@ -56,6 +76,44 @@ public class SettingsOsmEditingActivity extends SettingsBaseActivity { } }); grp.addPreference(pref); + + final Preference prefOAuth = new Preference(this); + if (client.isValidToken()){ + prefOAuth.setTitle(R.string.osm_authorization_success); + prefOAuth.setSummary(R.string.osm_authorization_success); + prefOAuth.setKey("local_openstreetmap_oauth_success"); + final Preference prefClearToken = new Preference(this); + prefClearToken.setTitle(R.string.shared_string_logoff); + prefClearToken.setSummary(R.string.clear_osm_token); + prefClearToken.setKey("local_openstreetmap_oauth_clear"); + prefClearToken.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + settings.USER_ACCESS_TOKEN.set(""); + settings.USER_ACCESS_TOKEN_SECRET.set(""); + client.resetToken(); + Toast.makeText(SettingsOsmEditingActivity.this, R.string.osm_edit_logout_success, Toast.LENGTH_SHORT).show(); + finish(); + startActivity(getIntent()); + return true; + } + }); + grp.addPreference(prefClearToken); + } + else { + prefOAuth.setTitle(R.string.perform_oauth_authorization); + prefOAuth.setSummary(R.string.perform_oauth_authorization_description); + prefOAuth.setKey("local_openstreetmap_oauth_login"); + prefOAuth.setOnPreferenceClickListener(new OnPreferenceClickListener() { + @Override + public boolean onPreferenceClick(Preference preference) { + ViewGroup preferenceView = (ViewGroup)getListView().getChildAt(preference.getOrder()); + client.startOAuth(preferenceView); + return true; + } + }); + } + grp.addPreference(prefOAuth); } public class OsmLoginDataDialogPreference extends DialogPreference { @@ -116,4 +174,17 @@ public class SettingsOsmEditingActivity extends SettingsBaseActivity { Toast.makeText(context, text, Toast.LENGTH_LONG).show(); } } + + @Override + protected void onNewIntent(Intent intent) { + super.onNewIntent(intent); + Uri uri = intent.getData(); + System.out.println("URI=" + uri); + if (uri != null && uri.toString().startsWith("osmand-oauth")) { + String oauthVerifier = uri.getQueryParameter("oauth_verifier"); + client.authorize(oauthVerifier); + finish(); + startActivity(getIntent()); + } + } } \ No newline at end of file diff --git a/OsmAnd/src/net/osmand/plus/osmedit/UploadOpenstreetmapPointAsyncTask.java b/OsmAnd/src/net/osmand/plus/osmedit/UploadOpenstreetmapPointAsyncTask.java index 1d99aee0c0..285c359656 100644 --- a/OsmAnd/src/net/osmand/plus/osmedit/UploadOpenstreetmapPointAsyncTask.java +++ b/OsmAnd/src/net/osmand/plus/osmedit/UploadOpenstreetmapPointAsyncTask.java @@ -1,6 +1,7 @@ package net.osmand.plus.osmedit; import android.content.DialogInterface; +import android.net.TrafficStats; import android.os.AsyncTask; import net.osmand.osm.edit.Entity; @@ -24,6 +25,7 @@ public class UploadOpenstreetmapPointAsyncTask private OsmEditingPlugin plugin; private final boolean closeChangeSet; private final boolean loadAnonymous; + private static final int THREAD_ID = 10102; public UploadOpenstreetmapPointAsyncTask(ProgressDialogFragment progress, OsmEditsUploadListener listener, @@ -43,6 +45,8 @@ public class UploadOpenstreetmapPointAsyncTask @Override protected Map doInBackground(OsmPoint... points) { + TrafficStats.setThreadStatsTag(THREAD_ID); + Map loadErrorsMap = new HashMap<>(); boolean uploaded = false; diff --git a/OsmAnd/src/net/osmand/plus/osmedit/oauth/OsmOAuthAuthorizationAdapter.java b/OsmAnd/src/net/osmand/plus/osmedit/oauth/OsmOAuthAuthorizationAdapter.java new file mode 100644 index 0000000000..8d687f9604 --- /dev/null +++ b/OsmAnd/src/net/osmand/plus/osmedit/oauth/OsmOAuthAuthorizationAdapter.java @@ -0,0 +1,88 @@ +package net.osmand.plus.osmedit.oauth; + +import android.net.TrafficStats; +import android.view.View; +import android.view.ViewGroup; +import android.webkit.WebView; +import com.github.scribejava.core.model.OAuth1AccessToken; +import com.github.scribejava.core.model.OAuth1RequestToken; +import com.github.scribejava.core.model.OAuthAsyncRequestCallback; +import com.github.scribejava.core.model.Response; +import net.osmand.osm.oauth.OsmOAuthAuthorizationClient; +import net.osmand.plus.BuildConfig; +import net.osmand.plus.OsmandApplication; + +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class OsmOAuthAuthorizationAdapter { + private OsmandApplication application; + private OsmOAuthAuthorizationClient client = + new OsmOAuthAuthorizationClient(BuildConfig.OSM_OAUTH_CONSUMER_KEY, BuildConfig.OSM_OAUTH_CONSUMER_SECRET); + private static final int THREAD_ID = 10101; + + public OsmOAuthAuthorizationAdapter(OsmandApplication application) { + TrafficStats.setThreadStatsTag(THREAD_ID); + this.application = application; + restoreToken(); + } + + public OsmOAuthAuthorizationClient getClient() { + return client; + } + + public boolean isValidToken() { + return client.isValidToken(); + } + + public void resetToken() { + client.setAccessToken(null); + } + + public void restoreToken() { + String token = application.getSettings().USER_ACCESS_TOKEN.get(); + String tokenSecret = application.getSettings().USER_ACCESS_TOKEN_SECRET.get(); + if (!(token.isEmpty() || tokenSecret.isEmpty())) { + client.setAccessToken(new OAuth1AccessToken(token, tokenSecret)); + } else { + client.setAccessToken(null); + } + } + + public void startOAuth(ViewGroup rootLayout) { + OAuth1RequestToken requestToken = client.startOAuth(); + loadWebView(rootLayout, client.getService().getAuthorizationUrl(requestToken)); + } + + private void saveToken() { + OAuth1AccessToken accessToken = client.getAccessToken(); + application.getSettings().USER_ACCESS_TOKEN.set(accessToken.getToken()); + application.getSettings().USER_ACCESS_TOKEN_SECRET.set(accessToken.getTokenSecret()); + } + + private void loadWebView(ViewGroup root, String url) { + WebView webView = new WebView(root.getContext()); + webView.requestFocus(View.FOCUS_DOWN); + webView.loadUrl(url); + root.addView(webView); + } + + public void performGetRequest(String url, OAuthAsyncRequestCallback callback) { + client.performGetRequest(url, callback); + } + + public Response performRequest(String url, String method, String body) + throws InterruptedException, ExecutionException, IOException { + return client.performRequest(url, method, body); + } + + public Response performRequestWithoutAuth(String url, String method, String body) + throws InterruptedException, ExecutionException, IOException { + return client.performRequestWithoutAuth(url, method, body); + } + + public void authorize(String oauthVerifier) { + client.authorize(oauthVerifier); + saveToken(); + } +} diff --git a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java index c05a583701..1bb9d6e987 100644 --- a/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java +++ b/OsmAnd/src/net/osmand/plus/settings/backend/OsmandSettings.java @@ -1125,6 +1125,12 @@ public class OsmandSettings { public final OsmandPreference USER_PASSWORD = new StringPreference(this, "user_password", "").makeGlobal(); + public final OsmandPreference USER_ACCESS_TOKEN = + new StringPreference("user_access_token", "").makeGlobal(); + + public final OsmandPreference USER_ACCESS_TOKEN_SECRET = + new StringPreference("user_access_token_secret", "").makeGlobal(); + // this value boolean is synchronized with settings_pref.xml preference offline POI/Bugs edition public final OsmandPreference OFFLINE_EDITION = new BooleanPreference(this, "offline_osm_editing", true).makeGlobal();