diff --git a/build.gradle b/build.gradle index 2fa7532f0..0c531e3c8 100644 --- a/build.gradle +++ b/build.gradle @@ -5,10 +5,12 @@ buildscript { repositories { jcenter() mavenCentral() + maven { url 'https://raw.github.com/xujiaao/mvn-repository/master/releases' } } dependencies { classpath 'com.github.ben-manes:gradle-versions-plugin:0.7' classpath 'com.android.tools.build:gradle:1.0.1' + classpath 'com.github.xujiaao:aarLinkSources:1.0.0' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files diff --git a/twidere.component.common/build.gradle b/twidere.component.common/build.gradle index db3fe4395..284634395 100644 --- a/twidere.component.common/build.gradle +++ b/twidere.component.common/build.gradle @@ -40,6 +40,7 @@ android { dependencies { compile 'com.android.support:support-annotations:21.0.3' compile 'org.apache.commons:commons-lang3:3.3.2' + compile 'com.squareup.retrofit:retrofit:1.9.0' compile project(':twidere.component.jsonserializer') compile project(':twidere.component.querybuilder') compile project(':twidere.component.twitter4j') diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/APIFactory.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/api/APIFactory.java new file mode 100644 index 000000000..3f02f2578 --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/api/APIFactory.java @@ -0,0 +1,56 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.api; + +import java.lang.reflect.Type; + +import retrofit.RestAdapter; +import retrofit.RestAdapter.Builder; +import retrofit.converter.ConversionException; +import retrofit.converter.Converter; +import retrofit.mime.TypedInput; +import retrofit.mime.TypedOutput; + +/** + * Created by mariotaku on 15/2/3. + */ +public class APIFactory { + + public static TwitterAPI getTwitterAPI() { + Builder builder = new RestAdapter.Builder(); + builder.setEndpoint("https://api.twitter.com"); + builder.setConverter(new ParcelableDataConverter()); + return builder.build().create(TwitterAPI.class); + } + + private static class ParcelableDataConverter implements Converter { + @Override + public Object fromBody(TypedInput typedInput, Type type) throws ConversionException { +// Class typeClass = (Class) type; +// typeClass.isAssignableFrom(); + return null; + } + + @Override + public TypedOutput toBody(Object o) { + throw new UnsupportedOperationException(); + } + } +} diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/TwitterAPI.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/api/TwitterAPI.java new file mode 100644 index 000000000..2ef42719c --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/api/TwitterAPI.java @@ -0,0 +1,34 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.api; + +import org.mariotaku.twidere.model.ParcelableAccount; + +import retrofit.http.GET; + +/** + * Created by mariotaku on 15/2/3. + */ +public interface TwitterAPI { + + @GET("/account/verify_credentials.json") + ParcelableAccount verifyCredentials(); + +} diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/api/TwitterMediaAPI.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/api/TwitterMediaAPI.java new file mode 100644 index 000000000..7a0cb377c --- /dev/null +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/api/TwitterMediaAPI.java @@ -0,0 +1,29 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.api; + +import org.mariotaku.twidere.model.ParcelableAccount; + +/** + * Created by mariotaku on 15/2/3. + */ +public interface TwitterMediaAPI { + +} diff --git a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableAccount.java b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableAccount.java index 19e0bc2bf..0caeee999 100644 --- a/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableAccount.java +++ b/twidere.component.common/src/main/java/org/mariotaku/twidere/model/ParcelableAccount.java @@ -26,6 +26,10 @@ import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; +import com.google.gson.TypeAdapter; +import com.google.gson.stream.JsonReader; +import com.google.gson.stream.JsonWriter; + import org.mariotaku.querybuilder.Columns.Column; import org.mariotaku.querybuilder.Expression; import org.mariotaku.querybuilder.RawItemArray; @@ -33,6 +37,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Accounts; import org.mariotaku.twidere.util.TwitterContentUtils; import org.mariotaku.twidere.util.content.ContentResolverUtils; +import java.io.IOException; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -362,4 +367,5 @@ public class ParcelableAccount implements Parcelable { + ", same_oauth_signing_url=" + same_oauth_signing_url + "}"; } } + } diff --git a/twidere.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java b/twidere.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java index a6cfaa16d..80c2c124e 100644 --- a/twidere.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java +++ b/twidere.component.twitter4j/src/main/java/twitter4j/http/HttpClientImpl.java @@ -61,294 +61,293 @@ import static twitter4j.http.RequestMethod.POST; * @since Twitter4J 2.1.2 */ public class HttpClientImpl extends HttpClientBase implements HttpClient, HttpResponseCode { - private static final Logger logger = Logger.getLogger(HttpClientImpl.class); + private static final Logger logger = Logger.getLogger(HttpClientImpl.class); - private static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[] { new TrustAllX509TrustManager() }; + private static final TrustManager[] TRUST_ALL_CERTS = new TrustManager[]{new TrustAllX509TrustManager()}; - private static final SSLSocketFactory IGNORE_ERROR_SSL_FACTORY; + private static final SSLSocketFactory IGNORE_ERROR_SSL_FACTORY; - static { - System.setProperty("http.keepAlive", "false"); - SSLSocketFactory factory = null; - try { - final SSLContext sc = SSLContext.getInstance("TLS"); - sc.init(null, TRUST_ALL_CERTS, new SecureRandom()); - factory = sc.getSocketFactory(); - } catch (final KeyManagementException e) { - } catch (final NoSuchAlgorithmException e) { - } - IGNORE_ERROR_SSL_FACTORY = factory; - } + static { + System.setProperty("http.keepAlive", "false"); + SSLSocketFactory factory = null; + try { + final SSLContext sc = SSLContext.getInstance("TLS"); + sc.init(null, TRUST_ALL_CERTS, new SecureRandom()); + factory = sc.getSocketFactory(); + } catch (final KeyManagementException | NoSuchAlgorithmException e) { + } + IGNORE_ERROR_SSL_FACTORY = factory; + } - private static final HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new AllowAllHostnameVerifier(); + private static final HostnameVerifier ALLOW_ALL_HOSTNAME_VERIFIER = new AllowAllHostnameVerifier(); - private static final Map instanceMap = new HashMap( - 1); + private static final Map instanceMap = new HashMap( + 1); - public HttpClientImpl() { - super(ConfigurationContext.getInstance()); - }; + public HttpClientImpl() { + super(ConfigurationContext.getInstance()); + } - public HttpClientImpl(final HttpClientConfiguration conf) { - super(conf); - } + public HttpClientImpl(final HttpClientConfiguration conf) { + super(conf); + } - public HttpResponse get(final String url, final String sign_url) throws TwitterException { - return request(new HttpRequest(RequestMethod.GET, url, sign_url, null, null, null)); - } + public HttpResponse get(final String url, final String sign_url) throws TwitterException { + return request(new HttpRequest(RequestMethod.GET, url, sign_url, null, null, null)); + } - public HttpResponse post(final String url, final String sign_url, final HttpParameter[] params) - throws TwitterException { - return request(new HttpRequest(RequestMethod.POST, url, sign_url, params, null, null)); - } + public HttpResponse post(final String url, final String sign_url, final HttpParameter[] params) + throws TwitterException { + return request(new HttpRequest(RequestMethod.POST, url, sign_url, params, null, null)); + } - @Override - public HttpResponse request(final HttpRequest req) throws TwitterException { - int retriedCount; - final int retry = CONF.getHttpRetryCount() + 1; - HttpResponse res = null; - for (retriedCount = 0; retriedCount < retry; retriedCount++) { - int responseCode = -1; - try { - HttpURLConnection con; - OutputStream os = null; - try { - con = getConnection(req.getURL()); - con.setDoInput(true); - setHeaders(req, con); - con.setRequestMethod(req.getMethod().name()); - final HttpParameter[] params = req.getParameters(); - if (req.getMethod() == POST) { - if (HttpParameter.containsFile(params)) { - String boundary = "----Twitter4J-upload" + System.currentTimeMillis(); - con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); - boundary = "--" + boundary; - con.setDoOutput(true); - os = con.getOutputStream(); - final DataOutputStream out = new DataOutputStream(os); - for (final HttpParameter param : params) { - if (param.isFile()) { - write(out, boundary + "\r\n"); - write(out, "Content-Disposition: form-data; name=\"" + param.getName() - + "\"; filename=\"" + param.getFileName() + "\"\r\n"); - write(out, "Content-Type: " + param.getContentType() + "\r\n\r\n"); - final BufferedInputStream in = new BufferedInputStream( - param.hasFileBody() ? param.getFileBody() : new FileInputStream( - param.getFile())); - int buff; - while ((buff = in.read()) != -1) { - out.write(buff); - } - write(out, "\r\n"); - in.close(); - } else { - write(out, boundary + "\r\n"); - write(out, "Content-Disposition: form-data; name=\"" + param.getName() + "\"\r\n"); - write(out, "Content-Type: text/plain; charset=UTF-8\r\n\r\n"); - logger.debug(param.getValue()); - out.write(param.getValue().getBytes("UTF-8")); - write(out, "\r\n"); - } - } - write(out, boundary + "--\r\n"); - write(out, "\r\n"); + @Override + public HttpResponse request(final HttpRequest req) throws TwitterException { + int retriedCount; + final int retry = CONF.getHttpRetryCount() + 1; + HttpResponse res = null; + for (retriedCount = 0; retriedCount < retry; retriedCount++) { + int responseCode = -1; + try { + HttpURLConnection con; + OutputStream os = null; + try { + con = getConnection(req.getURL()); + con.setDoInput(true); + setHeaders(req, con); + con.setRequestMethod(req.getMethod().name()); + final HttpParameter[] params = req.getParameters(); + if (req.getMethod() == POST) { + if (HttpParameter.containsFile(params)) { + String boundary = "----Twitter4J-upload" + System.currentTimeMillis(); + con.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary); + boundary = "--" + boundary; + con.setDoOutput(true); + os = con.getOutputStream(); + final DataOutputStream out = new DataOutputStream(os); + for (final HttpParameter param : params) { + if (param.isFile()) { + write(out, boundary + "\r\n"); + write(out, "Content-Disposition: form-data; name=\"" + param.getName() + + "\"; filename=\"" + param.getFileName() + "\"\r\n"); + write(out, "Content-Type: " + param.getContentType() + "\r\n\r\n"); + final BufferedInputStream in = new BufferedInputStream( + param.hasFileBody() ? param.getFileBody() : new FileInputStream( + param.getFile())); + int buff; + while ((buff = in.read()) != -1) { + out.write(buff); + } + write(out, "\r\n"); + in.close(); + } else { + write(out, boundary + "\r\n"); + write(out, "Content-Disposition: form-data; name=\"" + param.getName() + "\"\r\n"); + write(out, "Content-Type: text/plain; charset=UTF-8\r\n\r\n"); + logger.debug(param.getValue()); + out.write(param.getValue().getBytes("UTF-8")); + write(out, "\r\n"); + } + } + write(out, boundary + "--\r\n"); + write(out, "\r\n"); - } else { - con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); - final String postParam = HttpParameter.encodeParameters(req.getParameters()); - logger.debug("Post Params: ", postParam); - final byte[] bytes = postParam.getBytes("UTF-8"); - con.setRequestProperty("Content-Length", Integer.toString(bytes.length)); - con.setDoOutput(true); - os = con.getOutputStream(); - os.write(bytes); - } - os.flush(); - os.close(); - } - res = new HttpResponseImpl(con, CONF); - responseCode = con.getResponseCode(); - if (logger.isDebugEnabled()) { - logger.debug("Response: "); - final Map> responseHeaders = con.getHeaderFields(); - for (final String key : responseHeaders.keySet()) { - final List values = responseHeaders.get(key); - for (final String value : values) { - if (key != null) { - logger.debug(key + ": " + value); - } else { - logger.debug(value); - } - } - } - } - if (responseCode < OK || responseCode > ACCEPTED) { - if (responseCode == ENHANCE_YOUR_CLAIM || responseCode == BAD_REQUEST - || responseCode < INTERNAL_SERVER_ERROR || retriedCount == CONF.getHttpRetryCount()) - throw new TwitterException(res.asString(), req, res); - } else { - break; - } - } finally { - try { - if (os != null) { - os.close(); - } - } catch (final IOException ignore) { - } - } - } catch (final IOException ioe) { - // connection timeout or read timeout - if (retriedCount == CONF.getHttpRetryCount()) - // throw new TwitterException(ioe.getMessage(), ioe, - // responseCode); - throw new TwitterException(ioe.getMessage(), req, res); - } catch (final NullPointerException e) { - // This exception will be thown when URL is invalid. - e.printStackTrace(); - throw new TwitterException("The URL requested is invalid.", e); - } catch (final OutOfMemoryError e) { - throw new TwitterException(e.getMessage(), e); - } - try { - if (logger.isDebugEnabled() && res != null) { - res.asString(); - } - logger.debug("Sleeping " + CONF.getHttpRetryIntervalSeconds() + " seconds until the next retry."); - Thread.sleep(CONF.getHttpRetryIntervalSeconds() * 1000); - } catch (final InterruptedException ignore) { - // nothing to do - } - } - return res; - } + } else { + con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + final String postParam = HttpParameter.encodeParameters(req.getParameters()); + logger.debug("Post Params: ", postParam); + final byte[] bytes = postParam.getBytes("UTF-8"); + con.setRequestProperty("Content-Length", Integer.toString(bytes.length)); + con.setDoOutput(true); + os = con.getOutputStream(); + os.write(bytes); + } + os.flush(); + os.close(); + } + res = new HttpResponseImpl(con, CONF); + responseCode = con.getResponseCode(); + if (logger.isDebugEnabled()) { + logger.debug("Response: "); + final Map> responseHeaders = con.getHeaderFields(); + for (final String key : responseHeaders.keySet()) { + final List values = responseHeaders.get(key); + for (final String value : values) { + if (key != null) { + logger.debug(key + ": " + value); + } else { + logger.debug(value); + } + } + } + } + if (responseCode < OK || responseCode > ACCEPTED) { + if (responseCode == ENHANCE_YOUR_CLAIM || responseCode == BAD_REQUEST + || responseCode < INTERNAL_SERVER_ERROR || retriedCount == CONF.getHttpRetryCount()) + throw new TwitterException(res.asString(), req, res); + } else { + break; + } + } finally { + try { + if (os != null) { + os.close(); + } + } catch (final IOException ignore) { + } + } + } catch (final IOException ioe) { + // connection timeout or read timeout + if (retriedCount == CONF.getHttpRetryCount()) + // throw new TwitterException(ioe.getMessage(), ioe, + // responseCode); + throw new TwitterException(ioe.getMessage(), req, res); + } catch (final NullPointerException e) { + // This exception will be thown when URL is invalid. + e.printStackTrace(); + throw new TwitterException("The URL requested is invalid.", e); + } catch (final OutOfMemoryError e) { + throw new TwitterException(e.getMessage(), e); + } + try { + if (logger.isDebugEnabled() && res != null) { + res.asString(); + } + logger.debug("Sleeping " + CONF.getHttpRetryIntervalSeconds() + " seconds until the next retry."); + Thread.sleep(CONF.getHttpRetryIntervalSeconds() * 1000); + } catch (final InterruptedException ignore) { + // nothing to do + } + } + return res; + } - private HttpURLConnection getConnection(final String url_string) throws IOException { + private HttpURLConnection getConnection(final String url_string) throws IOException { - final HttpURLConnection con; - final Proxy proxy; - if (isProxyConfigured()) { - if (CONF.getHttpProxyUser() != null && !CONF.getHttpProxyUser().equals("")) { - if (logger.isDebugEnabled()) { - logger.debug("Proxy AuthUser: " + CONF.getHttpProxyUser()); - logger.debug("Proxy AuthPassword: " + InternalStringUtil.maskString(CONF.getHttpProxyPassword())); - } - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - // respond only to proxy auth requests - if (getRequestorType().equals(RequestorType.PROXY)) - return new PasswordAuthentication(CONF.getHttpProxyUser(), CONF.getHttpProxyPassword() - .toCharArray()); - else - return null; - } - }); - } - proxy = new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(CONF.getHttpProxyHost(), - CONF.getHttpProxyPort())); - if (logger.isDebugEnabled()) { - logger.debug("Opening proxied connection(" + CONF.getHttpProxyHost() + ":" + CONF.getHttpProxyPort() - + ")"); - } - } else { - proxy = Proxy.NO_PROXY; - } - final HostAddressResolver resolver = FactoryUtils.getHostAddressResolver(CONF); - final URI url_orig; - try { - url_orig = new URI(url_string); - } catch (final URISyntaxException e) { - throw new IOException("Invalid URI " + url_string); - } - final String host = url_orig.getHost(), authority = url_orig.getAuthority(); - final String resolved_host = resolver != null ? resolver.resolve(host) : null; - con = (HttpURLConnection) new URL(resolved_host != null ? url_string.replace("://" + host, "://" - + resolved_host) : url_string).openConnection(proxy); - if (resolved_host != null && !host.equals(resolved_host)) { - con.setRequestProperty("Host", authority); - } - if (CONF.getHttpConnectionTimeout() > 0) { - con.setConnectTimeout(CONF.getHttpConnectionTimeout()); - } - if (CONF.getHttpReadTimeout() > 0) { - con.setReadTimeout(CONF.getHttpReadTimeout()); - } - con.setInstanceFollowRedirects(false); - if (con instanceof HttpsURLConnection && CONF.isSSLErrorIgnored()) { - ((HttpsURLConnection) con).setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER); - if (IGNORE_ERROR_SSL_FACTORY != null) { - ((HttpsURLConnection) con).setSSLSocketFactory(IGNORE_ERROR_SSL_FACTORY); - } - } - return con; - } + final HttpURLConnection con; + final Proxy proxy; + if (isProxyConfigured()) { + if (CONF.getHttpProxyUser() != null && !CONF.getHttpProxyUser().equals("")) { + if (logger.isDebugEnabled()) { + logger.debug("Proxy AuthUser: " + CONF.getHttpProxyUser()); + logger.debug("Proxy AuthPassword: " + InternalStringUtil.maskString(CONF.getHttpProxyPassword())); + } + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + // respond only to proxy auth requests + if (getRequestorType().equals(RequestorType.PROXY)) + return new PasswordAuthentication(CONF.getHttpProxyUser(), CONF.getHttpProxyPassword() + .toCharArray()); + else + return null; + } + }); + } + proxy = new Proxy(Proxy.Type.HTTP, InetSocketAddress.createUnresolved(CONF.getHttpProxyHost(), + CONF.getHttpProxyPort())); + if (logger.isDebugEnabled()) { + logger.debug("Opening proxied connection(" + CONF.getHttpProxyHost() + ":" + CONF.getHttpProxyPort() + + ")"); + } + } else { + proxy = Proxy.NO_PROXY; + } + final HostAddressResolver resolver = FactoryUtils.getHostAddressResolver(CONF); + final URI url_orig; + try { + url_orig = new URI(url_string); + } catch (final URISyntaxException e) { + throw new IOException("Invalid URI " + url_string); + } + final String host = url_orig.getHost(), authority = url_orig.getAuthority(); + final String resolved_host = resolver != null ? resolver.resolve(host) : null; + con = (HttpURLConnection) new URL(resolved_host != null ? url_string.replace("://" + host, "://" + + resolved_host) : url_string).openConnection(proxy); + if (resolved_host != null && !host.equals(resolved_host)) { + con.setRequestProperty("Host", authority); + } + if (CONF.getHttpConnectionTimeout() > 0) { + con.setConnectTimeout(CONF.getHttpConnectionTimeout()); + } + if (CONF.getHttpReadTimeout() > 0) { + con.setReadTimeout(CONF.getHttpReadTimeout()); + } + con.setInstanceFollowRedirects(false); + if (con instanceof HttpsURLConnection && CONF.isSSLErrorIgnored()) { + ((HttpsURLConnection) con).setHostnameVerifier(ALLOW_ALL_HOSTNAME_VERIFIER); + if (IGNORE_ERROR_SSL_FACTORY != null) { + ((HttpsURLConnection) con).setSSLSocketFactory(IGNORE_ERROR_SSL_FACTORY); + } + } + return con; + } - /** - * sets HTTP headers - * - * @param req The request - * @param connection HttpURLConnection - */ - private void setHeaders(final HttpRequest req, final HttpURLConnection connection) { - if (logger.isDebugEnabled()) { - logger.debug("Request: "); - logger.debug(req.getMethod().name() + " ", req.getURL()); - } + /** + * sets HTTP headers + * + * @param req The request + * @param connection HttpURLConnection + */ + private void setHeaders(final HttpRequest req, final HttpURLConnection connection) { + if (logger.isDebugEnabled()) { + logger.debug("Request: "); + logger.debug(req.getMethod().name() + " ", req.getURL()); + } - String authorizationHeader; - if (req.getAuthorization() != null - && (authorizationHeader = req.getAuthorization().getAuthorizationHeader(req)) != null) { - if (logger.isDebugEnabled()) { - logger.debug("Authorization: ", InternalStringUtil.maskString(authorizationHeader)); - } - connection.addRequestProperty("Authorization", authorizationHeader); - } - final Map req_headers = req.getRequestHeaders(); - if (req_headers != null) { - for (final String key : req_headers.keySet()) { - connection.addRequestProperty(key, req.getRequestHeaders().get(key)); - logger.debug(key + ": " + req.getRequestHeaders().get(key)); - } - } - } + String authorizationHeader; + if (req.getAuthorization() != null + && (authorizationHeader = req.getAuthorization().getAuthorizationHeader(req)) != null) { + if (logger.isDebugEnabled()) { + logger.debug("Authorization: ", InternalStringUtil.maskString(authorizationHeader)); + } + connection.addRequestProperty("Authorization", authorizationHeader); + } + final Map req_headers = req.getRequestHeaders(); + if (req_headers != null) { + for (final String key : req_headers.keySet()) { + connection.addRequestProperty(key, req.getRequestHeaders().get(key)); + logger.debug(key + ": " + req.getRequestHeaders().get(key)); + } + } + } - public static String encode(final String str) { - try { - return URLEncoder.encode(str, "UTF-8"); - } catch (final java.io.UnsupportedEncodingException neverHappen) { - throw new AssertionError("will never happen"); - } - } + public static String encode(final String str) { + try { + return URLEncoder.encode(str, "UTF-8"); + } catch (final java.io.UnsupportedEncodingException neverHappen) { + throw new AssertionError("will never happen"); + } + } - public static HttpClient getInstance(final HttpClientConfiguration conf) { - HttpClient client = instanceMap.get(conf); - if (null == client) { - client = new HttpClientImpl(conf); - instanceMap.put(conf, client); - } - return client; - } + public static HttpClient getInstance(final HttpClientConfiguration conf) { + HttpClient client = instanceMap.get(conf); + if (null == client) { + client = new HttpClientImpl(conf); + instanceMap.put(conf, client); + } + return client; + } - static class AllowAllHostnameVerifier implements HostnameVerifier { - @Override - public boolean verify(final String hostname, final SSLSession session) { - return true; - } - } + static class AllowAllHostnameVerifier implements HostnameVerifier { + @Override + public boolean verify(final String hostname, final SSLSession session) { + return true; + } + } - final static class TrustAllX509TrustManager implements X509TrustManager { - @Override - public void checkClientTrusted(final X509Certificate[] chain, final String authType) { - } + final static class TrustAllX509TrustManager implements X509TrustManager { + @Override + public void checkClientTrusted(final X509Certificate[] chain, final String authType) { + } - @Override - public void checkServerTrusted(final X509Certificate[] chain, final String authType) { - } + @Override + public void checkServerTrusted(final X509Certificate[] chain, final String authType) { + } - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[] {}; - } - } + @Override + public X509Certificate[] getAcceptedIssuers() { + return new X509Certificate[]{}; + } + } } diff --git a/twidere/build.gradle b/twidere/build.gradle index b4472f808..18968b38a 100644 --- a/twidere/build.gradle +++ b/twidere/build.gradle @@ -1,6 +1,7 @@ import java.text.SimpleDateFormat apply plugin: 'com.android.application' +apply plugin: 'aar-link-sources' apply from: rootProject.file('signing.gradle') android { @@ -62,18 +63,18 @@ dependencies { compile 'com.android.support:palette-v7:21.0.3' compile 'com.sothree.slidinguppanel:library:2.0.4' compile 'com.twitter:twitter-text:1.9.9' + aarLinkSources 'com.twitter:twitter-text:1.9.9:sources@jar' compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.3' - compile 'org.apache.httpcomponents:httpclient-android:4.3.5' - compile 'org.apache.httpcomponents:httpmime:4.3.5' compile 'org.apache.commons:commons-csv:1.1' compile 'com.google.android.apps.dashclock:dashclock-api:2.0.0' - compile 'com.squareup:otto:1.3.5' + compile 'com.squareup:otto:1.3.6' compile 'dnsjava:dnsjava:2.1.6' compile 'com.commonsware.cwac:merge:1.1.1' compile 'com.diegocarloslima:byakugallery:0.1.0' compile 'com.rengwuxian.materialedittext:library:1.8.2' compile 'com.pnikosis:materialish-progress:1.4' compile 'com.squareup.okhttp:okhttp:2.2.0' + aarLinkSources 'com.squareup.okhttp:okhttp:2.2.0:sources@jar' googleCompile 'com.google.android.gms:play-services:6.5.87' googleCompile 'com.google.maps.android:android-maps-utils:0.3.4' fdroidCompile 'org.osmdroid:osmdroid-android:4.3' diff --git a/twidere/src/main/AndroidManifest.xml b/twidere/src/main/AndroidManifest.xml index 568e04d6b..467e7f4ad 100644 --- a/twidere/src/main/AndroidManifest.xml +++ b/twidere/src/main/AndroidManifest.xml @@ -1,7 +1,8 @@ - + @@ -569,9 +570,8 @@ diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java index 97032846b..8a1c4e72a 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/BrowserSignInActivity.java @@ -27,6 +27,7 @@ import android.graphics.Bitmap; import android.net.Uri; import android.net.http.SslError; import android.os.Bundle; +import android.support.annotation.NonNull; import android.view.MenuItem; import android.view.View; import android.view.Window; @@ -45,8 +46,8 @@ import org.mariotaku.twidere.util.OAuthPasswordAuthenticator; import org.mariotaku.twidere.util.ParseUtils; import org.mariotaku.twidere.util.TwitterContentUtils; import org.mariotaku.twidere.util.Utils; -import org.mariotaku.twidere.util.net.ApacheHttpClientFactory; import org.mariotaku.twidere.util.net.TwidereHostResolverFactory; +import org.mariotaku.twidere.util.net.OkHttpClientFactory; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; @@ -134,9 +135,7 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity implements private String readOAuthPin(final String html) { try { return OAuthPasswordAuthenticator.readOAuthPINFromHtml(new StringReader(html)); - } catch (final XmlPullParserException e) { - e.printStackTrace(); - } catch (final IOException e) { + } catch (final XmlPullParserException | IOException e) { e.printStackTrace(); } return null; @@ -179,7 +178,7 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity implements } @Override - public void onReceivedSslError(final WebView view, final SslErrorHandler handler, final SslError error) { + public void onReceivedSslError(final WebView view, @NonNull final SslErrorHandler handler, final SslError error) { if (mActivity.mPreferences.getBoolean(KEY_IGNORE_SSL_ERROR, false)) { handler.proceed(); } else { @@ -234,7 +233,7 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity implements final String consumerSecret = getNonEmptyString(mPreferences, KEY_CONSUMER_SECRET, TWITTER_CONSUMER_SECRET_3); cb.setHostAddressResolverFactory(new TwidereHostResolverFactory(mApplication)); - cb.setHttpClientFactory(new ApacheHttpClientFactory(mApplication)); + cb.setHttpClientFactory(new OkHttpClientFactory(mApplication)); if (TwitterContentUtils.isOfficialKey(mActivity, consumerKey, consumerSecret)) { Utils.setMockOfficialUserAgent(mActivity, cb); } else { @@ -301,13 +300,13 @@ public class BrowserSignInActivity extends BaseSupportDialogActivity implements @JavascriptInterface public void processHTML(final String html) { - final String oauth_verifier = mActivity.readOAuthPin(html); - final RequestToken request_token = mActivity.mRequestToken; - if (oauth_verifier != null && request_token != null) { + final String oauthVerifier = mActivity.readOAuthPin(html); + final RequestToken requestToken = mActivity.mRequestToken; + if (oauthVerifier != null && requestToken != null) { final Intent intent = new Intent(); - intent.putExtra(EXTRA_OAUTH_VERIFIER, oauth_verifier); - intent.putExtra(EXTRA_REQUEST_TOKEN, request_token.getToken()); - intent.putExtra(EXTRA_REQUEST_TOKEN_SECRET, request_token.getTokenSecret()); + intent.putExtra(EXTRA_OAUTH_VERIFIER, oauthVerifier); + intent.putExtra(EXTRA_REQUEST_TOKEN, requestToken.getToken()); + intent.putExtra(EXTRA_REQUEST_TOKEN_SECRET, requestToken.getTokenSecret()); mActivity.setResult(RESULT_OK, intent); mActivity.finish(); } diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/ComposeActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/ComposeActivity.java index 60f6b11e7..914c3e055 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/ComposeActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/ComposeActivity.java @@ -62,7 +62,6 @@ import android.support.v7.widget.RecyclerView.Adapter; import android.support.v7.widget.RecyclerView.ItemDecoration; import android.support.v7.widget.RecyclerView.State; import android.support.v7.widget.RecyclerView.ViewHolder; -import android.support.v7.widget.Toolbar; import android.text.Editable; import android.text.TextWatcher; import android.util.Log; @@ -195,7 +194,6 @@ public class ComposeActivity extends ThemedActionBarActivity implements TextWatc private View mLocationContainer; private ActionIconView mLocationIcon; private SupportMenuInflater mMenuInflater; - private Toolbar mToolbar; @Override public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) { @@ -536,7 +534,6 @@ public class ComposeActivity extends ThemedActionBarActivity implements TextWatc @Override public void onSupportContentChanged() { super.onSupportContentChanged(); - mToolbar = (Toolbar) findViewById(R.id.compose_actionbar); mEditText = (EditText) findViewById(R.id.edit_text); mMediaPreviewGrid = (GridView) findViewById(R.id.media_thumbnail_preview); mMenuBar = (ActionMenuView) findViewById(R.id.menu_bar); @@ -587,7 +584,6 @@ public class ComposeActivity extends ThemedActionBarActivity implements TextWatc mValidator = new TwidereValidator(this); mImageLoader = app.getImageLoaderWrapper(); setContentView(R.layout.activity_compose); - setSupportActionBar(mToolbar); setSupportProgressBarIndeterminateVisibility(false); setFinishOnTouchOutside(false); final long[] defaultAccountIds = getAccountIds(this); diff --git a/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java b/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java index ae75aa96e..3e08f320b 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java +++ b/twidere/src/main/java/org/mariotaku/twidere/activity/support/SignInActivity.java @@ -61,8 +61,8 @@ import org.mariotaku.twidere.util.ThemeUtils; import org.mariotaku.twidere.util.TwitterContentUtils; import org.mariotaku.twidere.util.Utils; import org.mariotaku.twidere.util.accessor.ViewAccessor; -import org.mariotaku.twidere.util.net.ApacheHttpClientFactory; import org.mariotaku.twidere.util.net.TwidereHostResolverFactory; +import org.mariotaku.twidere.util.net.OkHttpClientFactory; import twitter4j.Twitter; import twitter4j.TwitterConstants; @@ -355,7 +355,7 @@ public class SignInActivity extends BaseSupportActivity implements TwitterConsta final boolean ignore_ssl_error = mPreferences.getBoolean(KEY_IGNORE_SSL_ERROR, false); final boolean enable_proxy = mPreferences.getBoolean(KEY_ENABLE_PROXY, false); cb.setHostAddressResolverFactory(new TwidereHostResolverFactory(mApplication)); - cb.setHttpClientFactory(new ApacheHttpClientFactory(mApplication)); + cb.setHttpClientFactory(new OkHttpClientFactory(mApplication)); if (TwitterContentUtils.isOfficialKey(this, mConsumerKey, mConsumerSecret)) { Utils.setMockOfficialUserAgent(this, cb); } else { diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java index 393e1b121..9c9a203dc 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/Utils.java @@ -202,9 +202,8 @@ import org.mariotaku.twidere.provider.TwidereDataStore.UnreadCounts; import org.mariotaku.twidere.service.RefreshService; import org.mariotaku.twidere.util.content.ContentResolverUtils; import org.mariotaku.twidere.util.menu.TwidereMenuInfo; -import org.mariotaku.twidere.util.net.ApacheHttpClientFactory; import org.mariotaku.twidere.util.net.TwidereHostResolverFactory; -import org.mariotaku.twidere.util.net.ssl.OkHttpClientFactory; +import org.mariotaku.twidere.util.net.OkHttpClientFactory; import org.mariotaku.twidere.view.ShapedImageView; import org.mariotaku.twidere.view.ShapedImageView.ShapeStyle; @@ -1801,8 +1800,7 @@ public final class Utils implements Constants, TwitterConstants { if (userAgent != null) { cb.setHttpUserAgent(userAgent); } - cb.setHttpClientFactory(new ApacheHttpClientFactory(context)); -// cb.setHttpClientFactory(new OkHttpClientFactory()); + cb.setHttpClientFactory(new OkHttpClientFactory(context)); return new HttpClientWrapper(cb.build()); } @@ -2527,8 +2525,7 @@ public final class Utils implements Constants, TwitterConstants { final ConfigurationBuilder cb = new ConfigurationBuilder(); cb.setHostAddressResolverFactory(new TwidereHostResolverFactory(app)); if (apacheHttp) { - cb.setHttpClientFactory(new ApacheHttpClientFactory(app)); -// cb.setHttpClientFactory(new OkHttpClientFactory()); + cb.setHttpClientFactory(new OkHttpClientFactory(context)); } cb.setHttpConnectionTimeout(connection_timeout); cb.setGZIPEnabled(enableGzip); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientFactory.java deleted file mode 100644 index 32c046c16..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientFactory.java +++ /dev/null @@ -1,22 +0,0 @@ -package org.mariotaku.twidere.util.net; - -import android.content.Context; - -import twitter4j.http.HttpClient; -import twitter4j.http.HttpClientConfiguration; -import twitter4j.http.HttpClientFactory; - -public class ApacheHttpClientFactory implements HttpClientFactory { - - private final Context context; - - public ApacheHttpClientFactory(final Context context) { - this.context = context; - } - - @Override - public HttpClient getInstance(final HttpClientConfiguration conf) { - return new ApacheHttpClientImpl(context, conf); - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientHttpResponseImpl.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientHttpResponseImpl.java deleted file mode 100644 index a85cd9b2d..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientHttpResponseImpl.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2007 Yusuke Yamamoto - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.mariotaku.twidere.util.net; - -import org.apache.http.Header; -import org.apache.http.HeaderElement; -import org.apache.http.HttpResponse; - -import twitter4j.http.HttpClientConfiguration; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.zip.GZIPInputStream; - -/** - * @author Yusuke Yamamoto - yusuke at mac.com - * @since Twitter4J 2.1.2 - */ -final class ApacheHttpClientHttpResponseImpl extends twitter4j.http.HttpResponse { - private final HttpResponse res; - - ApacheHttpClientHttpResponseImpl(final HttpResponse res, final HttpClientConfiguration conf) throws IOException { - super(conf); - this.res = res; - is = res.getEntity().getContent(); - statusCode = res.getStatusLine().getStatusCode(); - if (is != null && "gzip".equals(getResponseHeader("Content-Encoding"))) { - // the response is gzipped - is = new GZIPInputStream(is); - } - } - - /** - * {@inheritDoc} - */ - @Override - public void disconnect() throws IOException { - if (res != null) { - res.getEntity().consumeContent(); - } - } - - /** - * {@inheritDoc} - */ - @Override - public final String getResponseHeader(final String name) { - final Header[] headers = res.getHeaders(name); - if (headers != null && headers.length > 0) - return headers[0].getValue(); - else - return null; - } - - @Override - public Map> getResponseHeaderFields() { - final Header[] headers = res.getAllHeaders(); - final Map> maps = new HashMap>(); - for (final Header header : headers) { - final HeaderElement[] elements = header.getElements(); - final List values = new ArrayList(1); - for (final HeaderElement element : elements) { - values.add(element.getValue()); - } - maps.put(header.getName(), values); - } - return maps; - } -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientImpl.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientImpl.java deleted file mode 100644 index a2af8dd59..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ApacheHttpClientImpl.java +++ /dev/null @@ -1,222 +0,0 @@ -/* - * Copyright 2007 Yusuke Yamamoto - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.mariotaku.twidere.util.net; - -import android.content.Context; - -import org.apache.http.Consts; -import org.apache.http.HttpEntity; -import org.apache.http.HttpHeaders; -import org.apache.http.HttpHost; -import org.apache.http.auth.AuthScope; -import org.apache.http.auth.UsernamePasswordCredentials; -import org.apache.http.client.CredentialsProvider; -import org.apache.http.client.config.RequestConfig; -import org.apache.http.client.methods.HttpDeleteHC4; -import org.apache.http.client.methods.HttpGetHC4; -import org.apache.http.client.methods.HttpHeadHC4; -import org.apache.http.client.methods.HttpPostHC4; -import org.apache.http.client.methods.HttpPutHC4; -import org.apache.http.client.methods.HttpRequestBaseHC4; -import org.apache.http.client.params.HttpClientParams; -import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.mime.MultipartEntityBuilder; -import org.apache.http.entity.mime.content.ContentBody; -import org.apache.http.entity.mime.content.FileBody; -import org.apache.http.entity.mime.content.InputStreamBody; -import org.apache.http.entity.mime.content.StringBody; -import org.apache.http.impl.client.BasicCredentialsProvider; -import org.apache.http.impl.client.CloseableHttpClient; -import org.apache.http.impl.client.HttpClientBuilder; -import org.apache.http.impl.client.HttpClients; -import org.apache.http.params.CoreProtocolPNames; -import org.apache.http.params.HttpParams; -import org.apache.http.protocol.BasicHttpContextHC4; -import org.apache.http.protocol.HttpContext; -import org.apache.http.util.TextUtils; -import org.mariotaku.twidere.util.ParseUtils; -import org.mariotaku.twidere.util.Utils; -import org.mariotaku.twidere.util.net.ssl.HostResolvedSSLConnectionSocketFactory; -import org.mariotaku.twidere.util.net.ssl.TwidereSSLSocketFactory; - -import java.io.IOException; -import java.io.UnsupportedEncodingException; -import java.net.URI; -import java.util.Map; - -import twitter4j.TwitterException; -import twitter4j.auth.Authorization; -import twitter4j.http.FactoryUtils; -import twitter4j.http.HostAddressResolver; -import twitter4j.http.HttpClientConfiguration; -import twitter4j.http.HttpParameter; -import twitter4j.http.HttpResponseCode; -import twitter4j.http.RequestMethod; -import twitter4j.internal.logging.Logger; -import twitter4j.internal.util.InternalStringUtil; - -import static android.text.TextUtils.isEmpty; - -/** - * HttpClient implementation for Apache HttpClient 4.0.x - * - * @author Yusuke Yamamoto - yusuke at mac.com - * @since Twitter4J 2.1.2 - */ -public class ApacheHttpClientImpl implements twitter4j.http.HttpClient, HttpResponseCode { - private static final Logger logger = Logger.getLogger(ApacheHttpClientImpl.class); - private final HttpClientConfiguration conf; - private final CloseableHttpClient client; - - public ApacheHttpClientImpl(final Context context, final HttpClientConfiguration conf) { - this.conf = conf; - final HttpClientBuilder clientBuilder = HttpClients.custom(); - final LayeredConnectionSocketFactory factory = TwidereSSLSocketFactory.getSocketFactory(context, - conf.isSSLErrorIgnored()); - clientBuilder.setSSLSocketFactory(factory); - final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom(); - requestConfigBuilder.setConnectionRequestTimeout(conf.getHttpConnectionTimeout()); - requestConfigBuilder.setConnectTimeout(conf.getHttpConnectionTimeout()); - requestConfigBuilder.setSocketTimeout(conf.getHttpReadTimeout()); - requestConfigBuilder.setRedirectsEnabled(false); - clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build()); - if (conf.isProxyConfigured()) { - final HttpHost proxy = new HttpHost(conf.getHttpProxyHost(), conf.getHttpProxyPort()); - clientBuilder.setProxy(proxy); - if (!TextUtils.isEmpty(conf.getHttpProxyUser())) { - if (logger.isDebugEnabled()) { - logger.debug("Proxy AuthUser: " + conf.getHttpProxyUser()); - logger.debug("Proxy AuthPassword: " + InternalStringUtil.maskString(conf.getHttpProxyPassword())); - } - final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); - credentialsProvider.setCredentials(new AuthScope(conf.getHttpProxyHost(), conf.getHttpProxyPort()), - new UsernamePasswordCredentials(conf.getHttpProxyUser(), conf.getHttpProxyPassword())); - clientBuilder.setDefaultCredentialsProvider(credentialsProvider); - } - } - client = clientBuilder.build(); - } - - @Override - public twitter4j.http.HttpResponse request(final twitter4j.http.HttpRequest req) throws TwitterException { - final HostAddressResolver resolver = FactoryUtils.getHostAddressResolver(conf); - final String urlString = req.getURL(); - final URI urlOrig = ParseUtils.parseURI(urlString); - final String host = urlOrig.getHost(), authority = urlOrig.getAuthority(); - try { - HttpRequestBaseHC4 commonsRequest; - final String resolvedHost = resolver != null ? resolver.resolve(host) : null; - final String resolvedUrl = !isEmpty(resolvedHost) ? urlString.replace("://" + host, "://" + resolvedHost) - : urlString; - final RequestMethod method = req.getMethod(); - switch (method) { - case GET: - commonsRequest = new HttpGetHC4(resolvedUrl); - break; - case POST: - final HttpPostHC4 post = new HttpPostHC4(resolvedUrl); - post.setEntity(getAsEntity(req.getParameters())); - post.getParams().setBooleanParameter(CoreProtocolPNames.USE_EXPECT_CONTINUE, false); - commonsRequest = post; - break; - case DELETE: - commonsRequest = new HttpDeleteHC4(resolvedUrl); - break; - case HEAD: - commonsRequest = new HttpHeadHC4(resolvedUrl); - break; - case PUT: - final HttpPutHC4 put = new HttpPutHC4(resolvedUrl); - put.setEntity(getAsEntity(req.getParameters())); - commonsRequest = put; - break; - default: - throw new TwitterException("Unsupported request method " + method); - } - final HttpParams httpParams = commonsRequest.getParams(); - HttpClientParams.setRedirecting(httpParams, false); - final Map headers = req.getRequestHeaders(); - for (final String headerName : headers.keySet()) { - commonsRequest.addHeader(headerName, headers.get(headerName)); - } - final Authorization authorization = req.getAuthorization(); - final String authorizationHeader = authorization != null ? authorization.getAuthorizationHeader(req) : null; - if (authorizationHeader != null) { - commonsRequest.addHeader(HttpHeaders.AUTHORIZATION, authorizationHeader); - } - if (resolvedHost != null && !resolvedHost.isEmpty() && !resolvedHost.equals(host)) { - commonsRequest.addHeader(HttpHeaders.HOST, authority); - } - - final ApacheHttpClientHttpResponseImpl res; - try { - final HttpContext httpContext = new BasicHttpContextHC4(); - httpContext.setAttribute(HostResolvedSSLConnectionSocketFactory.HTTP_CONTEXT_KEY_ORIGINAL_HOST, host); - res = new ApacheHttpClientHttpResponseImpl(client.execute(commonsRequest, httpContext), conf); - } catch (final IllegalStateException e) { - throw new TwitterException("Please check your API settings.", e); - } catch (final NullPointerException e) { - // Bug http://code.google.com/p/android/issues/detail?id=5255 - throw new TwitterException("Please check your APN settings, make sure not to use WAP APNs.", e); - } catch (final OutOfMemoryError e) { - // I don't know why OOM thown, but it should be catched. - System.gc(); - throw new TwitterException("Unknown error", e); - } - final int statusCode = res.getStatusCode(); - if (statusCode < OK || statusCode > ACCEPTED) - throw new TwitterException(res.asString(), req, res); - return res; - } catch (final IOException e) { - // TODO - if (resolver instanceof TwidereHostAddressResolver) { - final TwidereHostAddressResolver twidereResolver = (TwidereHostAddressResolver) resolver; - twidereResolver.removeCachedHost(host); - } - throw new TwitterException(e); - } - } - - @Override - public void shutdown() { - Utils.closeSilently(client); - } - - private static HttpEntity getAsEntity(final HttpParameter[] params) throws UnsupportedEncodingException { - if (params == null) return null; - if (!HttpParameter.containsFile(params)) return new HttpParameterFormEntity(params); - final MultipartEntityBuilder me = MultipartEntityBuilder.create(); - for (final HttpParameter param : params) { - if (param.isFile()) { - final ContentType contentType = ContentType.create(param.getContentType()); - final ContentBody body; - if (param.getFile() != null) { - body = new FileBody(param.getFile(), ContentType.create(param.getContentType())); - } else { - body = new InputStreamBody(param.getFileBody(), contentType, param.getFileName()); - } - me.addPart(param.getName(), body); - } else { - final ContentType contentType = ContentType.TEXT_PLAIN.withCharset(Consts.UTF_8); - final ContentBody body = new StringBody(param.getValue(), contentType); - me.addPart(param.getName(), body); - } - } - return me.build(); - } -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedHostnameVerifier.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedHostnameVerifier.java new file mode 100644 index 000000000..7655cb84d --- /dev/null +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedHostnameVerifier.java @@ -0,0 +1,34 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.util.net; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLSession; + +public final class HostResolvedHostnameVerifier implements HostnameVerifier { + public HostResolvedHostnameVerifier(boolean ignoreSSLError) { + + } + + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } +} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedSSLSocketFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedSSLSocketFactory.java new file mode 100644 index 000000000..6adb34234 --- /dev/null +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedSSLSocketFactory.java @@ -0,0 +1,94 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.util.net; + +import android.net.SSLCertificateSocketFactory; + +import org.apache.http.conn.util.InetAddressUtils; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.Socket; + +import javax.net.ssl.SSLSocketFactory; + +import twitter4j.http.HostAddressResolver; + +/** + * Created by mariotaku on 15/1/31. + */ +public class HostResolvedSSLSocketFactory extends SSLSocketFactory { + + private final SSLSocketFactory defaultFactory; + private final HostAddressResolver resolver; + + public HostResolvedSSLSocketFactory(HostAddressResolver resolver, boolean ignoreError) { + if (ignoreError) { + defaultFactory = SSLCertificateSocketFactory.getInsecure(0, null); + } else { + defaultFactory = SSLCertificateSocketFactory.getDefault(0, null); + } + this.resolver = resolver; + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + return defaultFactory.createSocket(host, port); + } + + @Override + public Socket createSocket() throws IOException { + return defaultFactory.createSocket(); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + return defaultFactory.createSocket(host, port, localHost, localPort); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + return defaultFactory.createSocket(host, port); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + return defaultFactory.createSocket(address, port, localAddress, localPort); + } + + + @Override + public String[] getDefaultCipherSuites() { + return defaultFactory.getDefaultCipherSuites(); + } + + @Override + public String[] getSupportedCipherSuites() { + return defaultFactory.getSupportedCipherSuites(); + } + + @Override + public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException { + return defaultFactory.createSocket(s, host, port, autoClose); + } + +} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedSocketFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedSocketFactory.java new file mode 100644 index 000000000..be485a1e9 --- /dev/null +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/HostResolvedSocketFactory.java @@ -0,0 +1,118 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2015 Mariotaku Lee + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.mariotaku.twidere.util.net; + +import org.apache.http.conn.util.InetAddressUtils; + +import java.io.IOException; +import java.net.Inet4Address; +import java.net.Inet6Address; +import java.net.InetAddress; +import java.net.Socket; + +import javax.net.SocketFactory; +import javax.net.ssl.SSLSocketFactory; + +import twitter4j.http.HostAddressResolver; + +/** + * Created by mariotaku on 15/1/31. + */ +public class HostResolvedSocketFactory extends SocketFactory { + + private final SocketFactory defaultFactory; + private final HostAddressResolver resolver; + + public HostResolvedSocketFactory(HostAddressResolver resolver) { + defaultFactory = SocketFactory.getDefault(); + this.resolver = resolver; + } + + @Override + public Socket createSocket(String host, int port) throws IOException { + final String resolvedHost = resolver.resolve(host); + if (resolvedHost != null && !resolvedHost.equals(host)) { + if (InetAddressUtils.isIPv6Address(resolvedHost)) { + final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(host, resolvedAddress), port); + } else if (InetAddressUtils.isIPv4Address(resolvedHost)) { + final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(host, resolvedAddress), port); + } + } + return defaultFactory.createSocket(host, port); + } + + @Override + public Socket createSocket() throws IOException { + return new Socket(); + } + + @Override + public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException { + final String resolvedHost = resolver.resolve(host); + if (resolvedHost != null && !resolvedHost.equals(host)) { + if (InetAddressUtils.isIPv6Address(resolvedHost)) { + final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(host, resolvedAddress), port); + } else if (InetAddressUtils.isIPv4Address(resolvedHost)) { + final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(host, resolvedAddress), port); + } + } + return defaultFactory.createSocket(host, port, localHost, localPort); + } + + @Override + public Socket createSocket(InetAddress host, int port) throws IOException { + final String hostName = host.getHostName(); + final String resolvedHost = resolver.resolve(hostName); + if (resolvedHost != null && !resolvedHost.equals(hostName)) { + if (InetAddressUtils.isIPv6Address(resolvedHost)) { + final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port); + } else if (InetAddressUtils.isIPv4Address(resolvedHost)) { + final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port); + } + } + return defaultFactory.createSocket(host, port); + } + + @Override + public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException { + final String hostName = address.getHostName(); + final String resolvedHost = resolver.resolve(hostName); + if (resolvedHost != null && !resolvedHost.equals(hostName)) { + if (InetAddressUtils.isIPv6Address(resolvedHost)) { + final byte[] resolvedAddress = Inet6Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port, localAddress, localPort); + } else if (InetAddressUtils.isIPv4Address(resolvedHost)) { + final byte[] resolvedAddress = Inet4Address.getByName(resolvedHost).getAddress(); + return new Socket(InetAddress.getByAddress(hostName, resolvedAddress), port, localAddress, localPort); + } + } + return defaultFactory.createSocket(address, port, localAddress, localPort); + } + + protected HostAddressResolver getResolver() { + return resolver; + } +} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/HttpParameterFormEntity.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/HttpParameterFormEntity.java deleted file mode 100644 index 11de4ea28..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/HttpParameterFormEntity.java +++ /dev/null @@ -1,19 +0,0 @@ -package org.mariotaku.twidere.util.net; - -import org.apache.http.Consts; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntityHC4; - -import twitter4j.http.HttpParameter; - -import java.io.UnsupportedEncodingException; - -public class HttpParameterFormEntity extends StringEntityHC4 { - - public static final ContentType CONTENT_TYPE = ContentType.APPLICATION_FORM_URLENCODED.withCharset(Consts.UTF_8); - - public HttpParameterFormEntity(final HttpParameter[] params) throws UnsupportedEncodingException { - super(HttpParameter.encodeParameters(params), CONTENT_TYPE); - } - -} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/OkHttpClientFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientFactory.java similarity index 86% rename from twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/OkHttpClientFactory.java rename to twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientFactory.java index 91b09e98d..bff9a0ded 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/OkHttpClientFactory.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientFactory.java @@ -17,8 +17,11 @@ * along with this program. If not, see . */ -package org.mariotaku.twidere.util.net.ssl; +package org.mariotaku.twidere.util.net; +import android.content.Context; + +import org.mariotaku.twidere.app.TwidereApplication; import org.mariotaku.twidere.util.net.OkHttpClientImpl; import twitter4j.http.HttpClient; @@ -29,6 +32,10 @@ import twitter4j.http.HttpClientFactory; * Created by mariotaku on 15/1/22. */ public class OkHttpClientFactory implements HttpClientFactory { + public OkHttpClientFactory(Context context) { + + } + @Override public HttpClient getInstance(HttpClientConfiguration conf) { return new OkHttpClientImpl(conf); diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientImpl.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientImpl.java index bc32aa115..37a6aad8d 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientImpl.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/OkHttpClientImpl.java @@ -20,55 +20,59 @@ package org.mariotaku.twidere.util.net; import android.net.Uri; -import android.util.Log; +import com.squareup.okhttp.Authenticator; import com.squareup.okhttp.Headers; import com.squareup.okhttp.MediaType; import com.squareup.okhttp.OkHttpClient; -import com.squareup.okhttp.Protocol; +import com.squareup.okhttp.Request; import com.squareup.okhttp.Request.Builder; import com.squareup.okhttp.RequestBody; import com.squareup.okhttp.Response; import org.mariotaku.twidere.TwidereConstants; +import java.io.BufferedInputStream; import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Proxy; +import java.net.Proxy.Type; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.UUID; import java.util.zip.GZIPInputStream; import twitter4j.TwitterException; import twitter4j.auth.Authorization; +import twitter4j.http.HostAddressResolver; import twitter4j.http.HttpClient; import twitter4j.http.HttpClientConfiguration; import twitter4j.http.HttpParameter; import twitter4j.http.HttpRequest; import twitter4j.http.HttpResponse; +import twitter4j.http.RequestMethod; /** * Created by mariotaku on 15/1/22. */ public class OkHttpClientImpl implements HttpClient, TwidereConstants { + public static final MediaType APPLICATION_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"); private final HttpClientConfiguration conf; private final OkHttpClient client; + private final HostAddressResolver resolver; public OkHttpClientImpl(HttpClientConfiguration conf) { this.conf = conf; + this.resolver = conf.getHostAddressResolverFactory().getInstance(conf); this.client = createHttpClient(conf); } - private OkHttpClient createHttpClient(HttpClientConfiguration conf) { - final OkHttpClient client = new OkHttpClient(); - if (conf.isSSLErrorIgnored()) { - } - return client; - } - @Override public HttpResponse request(HttpRequest req) throws TwitterException { final Builder builder = new Builder(); @@ -82,59 +86,34 @@ public class OkHttpClientImpl implements HttpClient, TwidereConstants { builder.header("Authorization", authHeader); } } - final String url; try { - switch (req.getMethod()) { - case GET: { - url = getUrl(req); - builder.get(); - break; - } - case POST: { - url = req.getURL(); - builder.post(getRequestBody(req.getParameters())); - break; - } - case DELETE: { - url = getUrl(req); - builder.delete(); - break; - } - case HEAD: { - url = getUrl(req); - builder.head(); - break; - } - case PUT: { - url = req.getURL(); - builder.put(getRequestBody(req.getParameters())); - break; - } - default: { - throw new AssertionError(); - } - } - builder.url(url); + setupRequestBuilder(builder, req); final Response response = client.newCall(builder.build()).execute(); - Log.d(TwidereConstants.LOGTAG, String.format("OkHttpClient finished a request to %s with %s protocol", url, response.protocol().name())); return new OkHttpResponse(conf, null, response); } catch (IOException e) { throw new TwitterException(e); } } - private String getUrl(HttpRequest req) { - final Uri.Builder uri = Uri.parse(req.getURL()).buildUpon(); - for (HttpParameter param : req.getParameters()) { - uri.appendQueryParameter(param.getName(), param.getValue()); - } - return uri.build().toString(); + @Override + public void shutdown() { + } - public static final MediaType APPLICATION_FORM_URLENCODED = MediaType.parse("application/x-www-form-urlencoded; charset=UTF-8"); - public static final MediaType MULTIPART_FORM_DATA = MediaType.parse("multipart/form-data; charset=UTF-8"); + private OkHttpClient createHttpClient(HttpClientConfiguration conf) { + final OkHttpClient client = new OkHttpClient(); + final boolean ignoreSSLError = conf.isSSLErrorIgnored(); + client.setHostnameVerifier(new HostResolvedHostnameVerifier(ignoreSSLError)); + client.setSslSocketFactory(new HostResolvedSSLSocketFactory(resolver, ignoreSSLError)); + client.setSocketFactory(new HostResolvedSocketFactory(resolver)); + if (conf.isProxyConfigured()) { + client.setProxy(new Proxy(Type.HTTP, InetSocketAddress.createUnresolved(conf.getHttpProxyHost(), + conf.getHttpProxyPort()))); + } + return client; + } - private RequestBody getRequestBody(HttpParameter[] params) { + private RequestBody getRequestBody(HttpParameter[] params) throws IOException { if (params == null) return null; if (!HttpParameter.containsFile(params)) { return RequestBody.create(APPLICATION_FORM_URLENCODED, HttpParameter.encodeParameters(params)); @@ -148,12 +127,71 @@ public class OkHttpClientImpl implements HttpClient, TwidereConstants { return RequestBody.create(MediaType.parse(param.getContentType()), param.getFile()); } } - return null; + String boundary = String.format("----%s", UUID.randomUUID().toString()); + final MediaType mediaType = MediaType.parse("multipart/form-data; boundary=" + boundary); + boundary = "--" + boundary; + final ByteArrayOutputStream os = new ByteArrayOutputStream(); + for (final HttpParameter param : params) { + os.write(String.format("%s\r\n", boundary).getBytes("UTF-8")); + if (param.isFile()) { + os.write(String.format("Content-Disposition: form-data; name=\"%s\"; filename=\"%s\"\r\n", param.getName(), param.getFileName()).getBytes("UTF-8")); + os.write(String.format("Content-Type: %s\r\n\r\n", param.getContentType()).getBytes("UTF-8")); + final BufferedInputStream in = new BufferedInputStream(param.hasFileBody() ? + param.getFileBody() : new FileInputStream(param.getFile())); + byte[] buff = new byte[8192]; + while (in.read(buff) != -1) { + os.write(buff); + } + in.close(); + } else { + os.write(String.format("Content-Disposition: form-data; name=\"%s\"\r\n", param.getName()).getBytes("UTF-8")); + os.write("Content-Type: text/plain; charset=UTF-8\r\n\r\n".getBytes("UTF-8")); + os.write(param.getValue().getBytes("UTF-8")); + } + os.write("\r\n".getBytes("UTF-8")); + } + os.write(String.format("%s--\r\n", boundary).getBytes("UTF-8")); + return RequestBody.create(mediaType, os.toByteArray()); } - @Override - public void shutdown() { - + private void setupRequestBuilder(Builder builder, HttpRequest req) throws IOException { + final Uri.Builder uriBuilder = Uri.parse(req.getURL()).buildUpon(); + final RequestMethod method = req.getMethod(); + if (method != RequestMethod.POST && method != RequestMethod.PUT) { + final HttpParameter[] parameters = req.getParameters(); + if (parameters != null) { + for (HttpParameter param : parameters) { + uriBuilder.appendQueryParameter(param.getName(), param.getValue()); + } + } + } + final Uri uri = uriBuilder.build(); + switch (req.getMethod()) { + case GET: { + builder.get(); + break; + } + case POST: { + builder.post(getRequestBody(req.getParameters())); + break; + } + case DELETE: { + builder.delete(); + break; + } + case HEAD: { + builder.head(); + break; + } + case PUT: { + builder.put(getRequestBody(req.getParameters())); + break; + } + default: { + throw new AssertionError(); + } + } + builder.url(uri.toString()); } private static class OkHttpResponse extends HttpResponse { diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java index 0c057c7c2..be941f1d8 100644 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java +++ b/twidere/src/main/java/org/mariotaku/twidere/util/net/TwidereHostAddressResolver.java @@ -23,7 +23,7 @@ import android.content.Context; import android.content.SharedPreferences; import android.util.Log; -import org.apache.http.conn.util.InetAddressUtilsHC4; +import org.apache.http.conn.util.InetAddressUtils; import org.mariotaku.twidere.Constants; import org.mariotaku.twidere.util.HostsFileParser; import org.mariotaku.twidere.util.Utils; @@ -191,7 +191,7 @@ public class TwidereHostAddressResolver implements Constants, HostAddressResolve private static boolean isValidIpAddress(final String address) { if (isEmpty(address)) return false; - return InetAddressUtilsHC4.isIPv4Address(address) || InetAddressUtilsHC4.isIPv6Address(address); + return InetAddressUtils.isIPv4Address(address) || InetAddressUtils.isIPv6Address(address); } private static class HostCache extends LinkedHashMap { diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/AbstractCheckSignatureVerifier.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/AbstractCheckSignatureVerifier.java deleted file mode 100644 index c72175b73..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/AbstractCheckSignatureVerifier.java +++ /dev/null @@ -1,347 +0,0 @@ -package org.mariotaku.twidere.util.net.ssl; - -import android.util.Log; - -import org.apache.http.conn.ssl.X509HostnameVerifier; -import org.apache.http.conn.util.InetAddressUtilsHC4; - -import java.io.IOException; -import java.io.InputStream; -import java.net.InetAddress; -import java.net.UnknownHostException; -import java.security.cert.Certificate; -import java.security.cert.CertificateParsingException; -import java.security.cert.X509Certificate; -import java.util.Arrays; -import java.util.Collection; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.StringTokenizer; - -import javax.net.ssl.SSLException; -import javax.net.ssl.SSLSession; -import javax.net.ssl.SSLSocket; - -public abstract class AbstractCheckSignatureVerifier implements X509HostnameVerifier { - - /** - * This contains a list of 2nd-level domains that aren't allowed to have - * wildcards when combined with country-codes. For example: [*.co.uk]. - *

- * The [*.co.uk] problem is an interesting one. Should we just hope that - * CA's would never foolishly allow such a certificate to happen? Looks like - * we're the only implementation guarding against this. Firefox, Curl, Sun - * Java 1.4, 5, 6 don't bother with this check. - */ - private final static String[] BAD_COUNTRY_2LDS = { "ac", "co", "com", "ed", "edu", "go", "gouv", "gov", "info", - "lg", "ne", "net", "or", "org" }; - - static { - // Just in case developer forgot to manually sort the array. :-) - Arrays.sort(BAD_COUNTRY_2LDS); - } - - private final static String TAG = "HttpClient"; - - @Override - public final boolean verify(final String host, final SSLSession session) { - try { - final Certificate[] certs = session.getPeerCertificates(); - final X509Certificate x509 = (X509Certificate) certs[0]; - verify(host, x509); - return true; - } catch (final SSLException e) { - return false; - } - } - - @Override - public final void verify(final String host, final SSLSocket ssl) throws IOException { - if (host == null) throw new NullPointerException("host to verify is null"); - - SSLSession session = ssl.getSession(); - if (session == null) { - // In our experience this only happens under IBM 1.4.x when - // spurious (unrelated) certificates show up in the server' - // chain. Hopefully this will unearth the real problem: - final InputStream in = ssl.getInputStream(); - in.available(); - /* - * If you're looking at the 2 lines of code above because you're - * running into a problem, you probably have two options: - * - * #1. Clean up the certificate chain that your server is presenting - * (e.g. edit "/etc/apache2/server.crt" or wherever it is your - * server's certificate chain is defined). - * - * OR - * - * #2. Upgrade to an IBM 1.5.x or greater JVM, or switch to a - * non-IBM JVM. - */ - - // If ssl.getInputStream().available() didn't cause an - // exception, maybe at least now the session is available? - session = ssl.getSession(); - if (session == null) { - // If it's still null, probably a startHandshake() will - // unearth the real problem. - ssl.startHandshake(); - - // Okay, if we still haven't managed to cause an exception, - // might as well go for the NPE. Or maybe we're okay now? - session = ssl.getSession(); - } - } - - final Certificate[] certs = session.getPeerCertificates(); - final X509Certificate x509 = (X509Certificate) certs[0]; - verify(host, x509); - } - - @Override - public final void verify(final String host, final String[] cns, final String[] subjectAlts) throws SSLException { - verify(host, cns, subjectAlts, null); - } - - public abstract void verify(final String host, final String[] cns, final String[] subjectAlts, - final X509Certificate cert) throws SSLException; - - @Override - public final void verify(final String host, final X509Certificate cert) throws SSLException { - final String[] cns = getCNs(cert); - final String[] subjectAlts = getSubjectAlts(cert, host); - verify(host, cns, subjectAlts, cert); - } - - /** - * @deprecated (4.3.1) should not be a part of public APIs. - */ - @Deprecated - public static boolean acceptableCountryWildcard(final String cn) { - final String parts[] = cn.split("\\.");// it's - // not an attempt to wildcard a 2TLD within a country code - if (parts.length != 3 || parts[2].length() != 2) return true; - return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0; - } - - /** - * Counts the number of dots "." in a string. - * - * @param s string to count dots from - * @return number of dots - */ - public static int countDots(final String s) { - int count = 0; - for (int i = 0; i < s.length(); i++) { - if (s.charAt(i) == '.') { - count++; - } - } - return count; - } - - public static String[] getCNs(final X509Certificate cert) { - final LinkedList cnList = new LinkedList(); - /* - * Sebastian Hauer's original StrictSSLProtocolSocketFactory used - * getName() and had the following comment: - * - * Parses a X.500 distinguished name for the value of the "Common Name" - * field. This is done a bit sloppy right now and should probably be - * done a bit more according to RFC 2253. - * - * I've noticed that toString() seems to do a better job than getName() - * on these X500Principal objects, so I'm hoping that addresses - * Sebastian's concern. - * - * For example, getName() gives me this: - * 1.2.840.113549.1.9.1=#16166a756c6975736461766965734063756362632e636f6d - * - * whereas toString() gives me this: EMAILADDRESS=juliusdavies@cucbc.com - * - * Looks like toString() even works with non-ascii domain names! I - * tested it with "花子.co.jp" and it worked fine. - */ - - final String subjectPrincipal = cert.getSubjectX500Principal().toString(); - final StringTokenizer st = new StringTokenizer(subjectPrincipal, ",+"); - while (st.hasMoreTokens()) { - final String tok = st.nextToken().trim(); - if (tok.length() > 3) { - if (tok.substring(0, 3).equalsIgnoreCase("CN=")) { - cnList.add(tok.substring(3)); - } - } - } - if (!cnList.isEmpty()) { - final String[] cns = new String[cnList.size()]; - cnList.toArray(cns); - return cns; - } else - return null; - } - - /** - * Extracts the array of SubjectAlt DNS names from an X509Certificate. - * Returns null if there aren't any. - *

- * Note: Java doesn't appear able to extract international characters from - * the SubjectAlts. It can only extract international characters from the CN - * field. - *

- * (Or maybe the version of OpenSSL I'm using to test isn't storing the - * international characters correctly in the SubjectAlts?). - * - * @param cert X509Certificate - * @return Array of SubjectALT DNS names stored in the certificate. - */ - public static String[] getDNSSubjectAlts(final X509Certificate cert) { - return getSubjectAlts(cert, null); - } - - public static final boolean verify(final String host, final String[] cns, final String[] subjectAlts, - final boolean strictWithSubDomains) { - - // Build the list of names we're going to check. Our DEFAULT and - // STRICT implementations of the HostnameVerifier only use the - // first CN provided. All other CNs are ignored. - // (Firefox, wget, curl, Sun Java 1.4, 5, 6 all work this way). - final LinkedList names = new LinkedList(); - if (cns != null && cns.length > 0 && cns[0] != null) { - names.add(cns[0]); - } - if (subjectAlts != null) { - for (final String subjectAlt : subjectAlts) { - if (subjectAlt != null) { - names.add(subjectAlt); - } - } - } - - if (names.isEmpty()) return false; - - // StringBuilder for building the error message. - final StringBuilder buf = new StringBuilder(); - - // We're can be case-insensitive when comparing the host we used to - // establish the socket to the hostname in the certificate. - final String hostName = normaliseIPv6Address(host.trim().toLowerCase(Locale.US)); - boolean match = false; - for (final Iterator it = names.iterator(); it.hasNext();) { - // Don't trim the CN, though! - String cn = it.next(); - cn = cn.toLowerCase(Locale.US); - // Store CN in StringBuilder in case we need to report an error. - buf.append(" <"); - buf.append(cn); - buf.append('>'); - if (it.hasNext()) { - buf.append(" OR"); - } - - // The CN better have at least two dots if it wants wildcard - // action. It also can't be [*.co.uk] or [*.co.jp] or - // [*.org.uk], etc... - final String parts[] = cn.split("\\."); - final boolean doWildcard = parts.length >= 3 && parts[0].endsWith("*") && validCountryWildcard(cn) - && !isIPAddress(host); - - if (doWildcard) { - final String firstpart = parts[0]; - if (firstpart.length() > 1) { // e.g. server* - // e.g. server - final String prefix = firstpart.substring(0, firstpart.length() - 1); - // skip wildcard part from cn - final String suffix = cn.substring(firstpart.length());// skip - // wildcard part from host - final String hostSuffix = hostName.substring(prefix.length()); - match = hostName.startsWith(prefix) && hostSuffix.endsWith(suffix); - } else { - match = hostName.endsWith(cn.substring(1)); - } - if (match && strictWithSubDomains) { - // If we're in strict mode, then [*.foo.com] is not - // allowed to match [a.b.foo.com] - match = countDots(hostName) == countDots(cn); - } - } else { - match = hostName.equals(normaliseIPv6Address(cn)); - } - if (match) { - break; - } - } - return match; - } - - /** - * Extracts the array of SubjectAlt DNS or IP names from an X509Certificate. - * Returns null if there aren't any. - * - * @param cert X509Certificate - * @param hostname - * @return Array of SubjectALT DNS or IP names stored in the certificate. - */ - private static String[] getSubjectAlts(final X509Certificate cert, final String hostname) { - final int subjectType; - if (isIPAddress(hostname)) { - subjectType = 7; - } else { - subjectType = 2; - } - - final LinkedList subjectAltList = new LinkedList(); - Collection> c = null; - try { - c = cert.getSubjectAlternativeNames(); - } catch (final CertificateParsingException cpe) { - } - if (c != null) { - for (final List aC : c) { - final List list = aC; - final int type = ((Integer) list.get(0)).intValue(); - if (type == subjectType) { - final String s = (String) list.get(1); - subjectAltList.add(s); - } - } - } - if (!subjectAltList.isEmpty()) { - final String[] subjectAlts = new String[subjectAltList.size()]; - subjectAltList.toArray(subjectAlts); - return subjectAlts; - } else - return null; - } - - private static boolean isIPAddress(final String hostname) { - return hostname != null - && (InetAddressUtilsHC4.isIPv4Address(hostname) || InetAddressUtilsHC4.isIPv6Address(hostname)); - } - - /* - * Check if hostname is IPv6, and if so, convert to standard format. - */ - private static String normaliseIPv6Address(final String hostname) { - if (hostname == null || !InetAddressUtilsHC4.isIPv6Address(hostname)) return hostname; - try { - final InetAddress inetAddress = InetAddress.getByName(hostname); - return inetAddress.getHostAddress(); - } catch (final UnknownHostException uhe) { // Should not happen, because - // we check for IPv6 address - // above - Log.e(TAG, "Unexpected error converting " + hostname, uhe); - return hostname; - } - } - - static boolean validCountryWildcard(final String cn) { - final String parts[] = cn.split("\\."); - // it's not an attempt to wildcard a 2TLD within a country code - if (parts.length != 3 || parts[2].length() != 2) return true; - return Arrays.binarySearch(BAD_COUNTRY_2LDS, parts[1]) < 0; - } -} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/HostResolvedSSLConnectionSocketFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/HostResolvedSSLConnectionSocketFactory.java deleted file mode 100644 index 89c0536ef..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/HostResolvedSSLConnectionSocketFactory.java +++ /dev/null @@ -1,194 +0,0 @@ -/* - * ==================================================================== - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - * ==================================================================== - * - * This software consists of voluntary contributions made by many - * individuals on behalf of the Apache Software Foundation. For more - * information on the Apache Software Foundation, please see - * . - * - */ - -package org.mariotaku.twidere.util.net.ssl; - -import android.net.SSLCertificateSocketFactory; -import android.os.Build; -import android.util.Log; - -import org.apache.http.HttpHost; -import org.apache.http.annotation.ThreadSafe; -import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLConnectionSocketFactory; -import org.apache.http.conn.ssl.X509HostnameVerifier; -import org.apache.http.protocol.HttpContext; -import org.apache.http.util.Args; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import javax.net.SocketFactory; -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocket; - -@ThreadSafe -public class HostResolvedSSLConnectionSocketFactory implements LayeredConnectionSocketFactory { - - private static final String TAG = "HttpClient"; - - public static final String HTTP_CONTEXT_KEY_ORIGINAL_HOST = "original_host"; - - private final javax.net.ssl.SSLSocketFactory socketfactory; - - private final X509HostnameVerifier hostnameVerifier; - - private final String[] supportedProtocols; - - private final String[] supportedCipherSuites; - - public HostResolvedSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketfactory, - final String[] supportedProtocols, final String[] supportedCipherSuites, - final X509HostnameVerifier hostnameVerifier) { - this.socketfactory = Args.notNull(socketfactory, "SSL socket factory"); - this.supportedProtocols = supportedProtocols; - this.supportedCipherSuites = supportedCipherSuites; - this.hostnameVerifier = hostnameVerifier != null ? hostnameVerifier - : SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER; - } - - public HostResolvedSSLConnectionSocketFactory(final javax.net.ssl.SSLSocketFactory socketfactory, - final X509HostnameVerifier hostnameVerifier) { - this(socketfactory, null, null, hostnameVerifier); - } - - public HostResolvedSSLConnectionSocketFactory(final SSLContext sslContext) { - this(sslContext, SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER); - } - - public HostResolvedSSLConnectionSocketFactory(final SSLContext sslContext, final String[] supportedProtocols, - final String[] supportedCipherSuites, final X509HostnameVerifier hostnameVerifier) { - this(Args.notNull(sslContext, "SSL context").getSocketFactory(), supportedProtocols, supportedCipherSuites, - hostnameVerifier); - } - - public HostResolvedSSLConnectionSocketFactory(final SSLContext sslContext, - final X509HostnameVerifier hostnameVerifier) { - this(Args.notNull(sslContext, "SSL context").getSocketFactory(), null, null, hostnameVerifier); - } - - @Override - public Socket connectSocket(final int connectTimeout, final Socket socket, final HttpHost host, - final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext context) - throws IOException { - Args.notNull(host, "HTTP host"); - Args.notNull(remoteAddress, "Remote address"); - final Socket sock = socket != null ? socket : createSocket(context); - if (localAddress != null) { - sock.bind(localAddress); - } - try { - sock.connect(remoteAddress, connectTimeout); - } catch (final IOException ex) { - try { - sock.close(); - } catch (final IOException ignore) { - } - throw ex; - } - // Setup SSL layering if necessary - if (sock instanceof SSLSocket) { - final SSLSocket sslsock = (SSLSocket) sock; - sslsock.startHandshake(); - verifyHostname(sslsock, host.getHostName(), context); - return sock; - } else - return createLayeredSocket(sock, host.getHostName(), remoteAddress.getPort(), context); - } - - @Override - public Socket createLayeredSocket(final Socket socket, final String target, final int port, - final HttpContext context) throws IOException { - final SSLSocket sslsock = (SSLSocket) socketfactory.createSocket(socket, target, port, true); - if (supportedProtocols != null) { - sslsock.setEnabledProtocols(supportedProtocols); - } - if (supportedCipherSuites != null) { - sslsock.setEnabledCipherSuites(supportedCipherSuites); - } - prepareSocket(sslsock); - - // Android specific code to enable SNI - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { - - if (socketfactory instanceof SSLCertificateSocketFactory) { - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "Enabling SNI for " + target); - } - ((SSLCertificateSocketFactory) socketfactory).setHostname(sslsock, target); - } - } - // End of Android specific code - - sslsock.startHandshake(); - verifyHostname(sslsock, target, context); - return sslsock; - } - - @Override - public Socket createSocket(final HttpContext context) throws IOException { - return SocketFactory.getDefault().createSocket(); - } - - /** - * Performs any custom initialization for a newly created SSLSocket (before - * the SSL handshake happens). - * - * The default implementation is a no-op, but could be overridden to, e.g., - * call {@link javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[])}. - */ - protected void prepareSocket(final SSLSocket socket) throws IOException { - } - - private String getHostname(final String hostname, final HttpContext context) { - if (context == null) return hostname; - final Object attr = context.getAttribute(HTTP_CONTEXT_KEY_ORIGINAL_HOST); - if (attr instanceof String) return (String) attr; - return hostname; - } - - private void verifyHostname(final SSLSocket sslsock, final String hostname, final HttpContext context) - throws IOException { - try { - hostnameVerifier.verify(getHostname(hostname, context), sslsock); - // verifyHostName() didn't blowup - good! - } catch (final IOException iox) { - // close the socket before re-throwing the exception - try { - sslsock.close(); - } catch (final Exception x) { /* ignore */ - } - throw iox; - } - } - - X509HostnameVerifier getHostnameVerifier() { - return hostnameVerifier; - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TrustAllX509TrustManager.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TrustAllX509TrustManager.java deleted file mode 100644 index 45a59d0be..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TrustAllX509TrustManager.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.mariotaku.twidere.util.net.ssl; - -import java.security.cert.X509Certificate; - -import javax.net.ssl.X509TrustManager; - -public final class TrustAllX509TrustManager implements X509TrustManager { - @Override - public void checkClientTrusted(final X509Certificate[] chain, final String authType) { - } - - @Override - public void checkServerTrusted(final X509Certificate[] chain, final String authType) { - } - - @Override - public X509Certificate[] getAcceptedIssuers() { - return new X509Certificate[0]; - } -} \ No newline at end of file diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TwidereHostnameVerifier.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TwidereHostnameVerifier.java deleted file mode 100644 index 4583a81fb..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TwidereHostnameVerifier.java +++ /dev/null @@ -1,34 +0,0 @@ -package org.mariotaku.twidere.util.net.ssl; - -import android.content.Context; - -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.X509Certificate; - -import javax.net.ssl.SSLException; - -public class TwidereHostnameVerifier extends AbstractCheckSignatureVerifier { - - private final Context context; - private final boolean ignoreSSLErrors; - - public TwidereHostnameVerifier(final Context context, final boolean ignoreSSLErrors) - throws NoSuchAlgorithmException, KeyStoreException { - this.context = context; - this.ignoreSSLErrors = ignoreSSLErrors; - } - - @Override - public void verify(final String host, final String[] cns, final String[] subjectAlts, final X509Certificate cert) - throws SSLException { - if (ignoreSSLErrors) return; - if (!checkCert(cert)) throw new SSLException(String.format("Untrusted cert %s", cert)); - if (!verify(host, cns, subjectAlts, false)) throw new SSLException(String.format("Unable to verify %s", host)); - } - - private boolean checkCert(final X509Certificate cert) { - return true; - } - -} diff --git a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TwidereSSLSocketFactory.java b/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TwidereSSLSocketFactory.java deleted file mode 100644 index 7db41d043..000000000 --- a/twidere/src/main/java/org/mariotaku/twidere/util/net/ssl/TwidereSSLSocketFactory.java +++ /dev/null @@ -1,66 +0,0 @@ -package org.mariotaku.twidere.util.net.ssl; - -import android.content.Context; - -import org.apache.http.HttpHost; -import org.apache.http.conn.socket.LayeredConnectionSocketFactory; -import org.apache.http.conn.ssl.SSLInitializationException; -import org.apache.http.conn.ssl.X509HostnameVerifier; -import org.apache.http.protocol.HttpContext; - -import java.io.IOException; -import java.net.InetSocketAddress; -import java.net.Socket; -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.TrustManager; - -public final class TwidereSSLSocketFactory implements LayeredConnectionSocketFactory { - - private final Context context; - private final boolean ignoreSSLErrors; - private final HostResolvedSSLConnectionSocketFactory delegated; - - private TwidereSSLSocketFactory(final Context context, final boolean ignoreSSLErrors) - throws KeyManagementException, NoSuchAlgorithmException, KeyStoreException { - this.context = context; - this.ignoreSSLErrors = ignoreSSLErrors; - final TrustManager[] tm = { new TrustAllX509TrustManager() }; - final SSLContext sslContext = SSLContext.getInstance("TLS"); - sslContext.init(null, tm, null); - final X509HostnameVerifier hostnameVerifier = new TwidereHostnameVerifier(context, ignoreSSLErrors); - delegated = new HostResolvedSSLConnectionSocketFactory(sslContext, hostnameVerifier); - } - - @Override - public Socket connectSocket(final int connectTimeout, final Socket socket, final HttpHost host, - final InetSocketAddress remoteAddress, final InetSocketAddress localAddress, final HttpContext httpContext) - throws IOException { - return delegated.connectSocket(connectTimeout, socket, host, remoteAddress, localAddress, httpContext); - } - - @Override - public Socket createLayeredSocket(final Socket socket, final String target, final int port, - final HttpContext httpContext) throws IOException { - return delegated.createLayeredSocket(socket, target, port, httpContext); - } - - @Override - public Socket createSocket(final HttpContext httpContext) throws IOException { - return delegated.createSocket(httpContext); - } - - public static LayeredConnectionSocketFactory getSocketFactory(final Context context, final boolean ignoreSSLErrors) - throws SSLInitializationException { - try { - return new TwidereSSLSocketFactory(context, ignoreSSLErrors); - } catch (final GeneralSecurityException e) { - throw new SSLInitializationException("Cannot create socket factory", e); - } - } - -} \ No newline at end of file diff --git a/twidere/src/main/res/drawable-hdpi/ic_launcher.png b/twidere/src/main/res/drawable-hdpi/ic_launcher.png index 29e5df6b7..1255af9e4 100644 Binary files a/twidere/src/main/res/drawable-hdpi/ic_launcher.png and b/twidere/src/main/res/drawable-hdpi/ic_launcher.png differ diff --git a/twidere/src/main/res/drawable-mdpi/ic_launcher.png b/twidere/src/main/res/drawable-mdpi/ic_launcher.png index 85f893e9e..721870626 100644 Binary files a/twidere/src/main/res/drawable-mdpi/ic_launcher.png and b/twidere/src/main/res/drawable-mdpi/ic_launcher.png differ diff --git a/twidere/src/main/res/drawable-xhdpi/ic_launcher.png b/twidere/src/main/res/drawable-xhdpi/ic_launcher.png index 8a81a4a5e..48325d589 100644 Binary files a/twidere/src/main/res/drawable-xhdpi/ic_launcher.png and b/twidere/src/main/res/drawable-xhdpi/ic_launcher.png differ diff --git a/twidere/src/main/res/drawable-xxhdpi/ic_launcher.png b/twidere/src/main/res/drawable-xxhdpi/ic_launcher.png index 036c58fa0..426840700 100644 Binary files a/twidere/src/main/res/drawable-xxhdpi/ic_launcher.png and b/twidere/src/main/res/drawable-xxhdpi/ic_launcher.png differ diff --git a/twidere/src/main/res/drawable-xxxhdpi/ic_launcher.png b/twidere/src/main/res/drawable-xxxhdpi/ic_launcher.png index ade8ae2eb..341c5b9f4 100644 Binary files a/twidere/src/main/res/drawable-xxxhdpi/ic_launcher.png and b/twidere/src/main/res/drawable-xxxhdpi/ic_launcher.png differ diff --git a/twidere/src/main/res/layout/activity_compose.xml b/twidere/src/main/res/layout/activity_compose.xml index 457a048eb..61204a576 100644 --- a/twidere/src/main/res/layout/activity_compose.xml +++ b/twidere/src/main/res/layout/activity_compose.xml @@ -27,11 +27,6 @@ android:minWidth="@dimen/compose_min_width" android:orientation="vertical"> - - @color/message_bubble_color_light - -