Refactoring

* move AccountSettings up to package context
* HttpClient: take authentication from AccountSettings in the constructor
* App: provide global instance of MemorizingTrustManager
* App: provide global Java logger, optionally with verbose and external file logging
* LoginCredentials: moved from inner-class into setup package
pull/2/head
Ricki Hirner 8 years ago
parent 50f7006e59
commit 552f6b6936

@ -26,7 +26,7 @@ public class HttpClientTest extends InstrumentationTestCase {
@Override
public void setUp() throws IOException {
httpClient = HttpClient.create(getInstrumentation().getTargetContext().getApplicationContext());
httpClient = HttpClient.create(getInstrumentation().getTargetContext().getApplicationContext(), null);
server = new MockWebServer();
server.start();

@ -3,12 +3,12 @@ package at.bitfire.davdroid.resource;
import android.test.InstrumentationTestCase;
import java.io.IOException;
import java.net.URI;
import at.bitfire.dav4android.exception.DavException;
import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.ui.setup.DavResourceFinder;
import at.bitfire.davdroid.ui.setup.LoginCredentialsFragment;
import at.bitfire.davdroid.ui.setup.LoginCredentials;
import okhttp3.HttpUrl;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
@ -30,7 +30,7 @@ public class DavResourceFinderTest extends InstrumentationTestCase {
public void testGetCurrentUserPrincipal() throws IOException, HttpException, DavException {
HttpUrl url = server.url("/dav");
LoginCredentialsFragment.LoginCredentials credentials = new LoginCredentialsFragment.LoginCredentials(url.uri(), "admin", "12345", true);
LoginCredentials credentials = new LoginCredentials(url.uri(), "admin", "12345", true);
DavResourceFinder finder = new DavResourceFinder(getInstrumentation().getTargetContext().getApplicationContext(), credentials);
// positive test case
@ -51,8 +51,8 @@ public class DavResourceFinderTest extends InstrumentationTestCase {
server.enqueue(new MockResponse() // OPTIONS response
.setResponseCode(200)
.setHeader("DAV", "addressbook"));
HttpUrl principal = finder.getCurrentUserPrincipal(url, DavResourceFinder.Service.CARDDAV);
assertEquals(url.resolve("/principals/myself"), principal);
URI principal = finder.getCurrentUserPrincipal(url, DavResourceFinder.Service.CARDDAV);
assertEquals(url.resolve("/principals/myself").uri(), principal);
// negative test case: no current-user-principal
server.enqueue(new MockResponse()

@ -43,6 +43,7 @@
<!-- ical4android declares task access permissions -->
<application
android:name=".App"
android:allowBackup="true"
android:fullBackupContent="false"
android:icon="@drawable/ic_launcher"

@ -5,7 +5,7 @@
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.syncadapter;
package at.bitfire.davdroid;
import android.accounts.Account;
import android.accounts.AccountManager;
@ -33,8 +33,6 @@ import java.net.URI;
import java.net.URISyntaxException;
import java.util.List;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.resource.LocalAddressBook;
import at.bitfire.vcard4android.ContactsStorageException;
import lombok.Cleanup;
@ -46,8 +44,6 @@ public class AccountSettings {
KEY_USERNAME = "user_name",
KEY_AUTH_PREEMPTIVE = "auth_preemptive",
KEY_LOG_TO_EXTERNAL_FILE = "log_external_file",
KEY_LOG_VERBOSE = "log_verbose",
KEY_LAST_ANDROID_VERSION = "last_android_version";
public final static long SYNC_INTERVAL_MANUALLY = -1;
@ -129,15 +125,6 @@ public class AccountSettings {
public void preemptiveAuth(boolean preemptive) { accountManager.setUserData(account, KEY_AUTH_PREEMPTIVE, Boolean.toString(preemptive)); }
// logging settings
public boolean logToExternalFile() { return Boolean.parseBoolean(accountManager.getUserData(account, KEY_LOG_TO_EXTERNAL_FILE)); }
public void logToExternalFile(boolean newValue) { accountManager.setUserData(account, KEY_LOG_TO_EXTERNAL_FILE, Boolean.toString(newValue)); }
public boolean logVerbose() { return Boolean.parseBoolean(accountManager.getUserData(account, KEY_LOG_VERBOSE)); }
public void logVerbose(boolean newValue) { accountManager.setUserData(account, KEY_LOG_VERBOSE, Boolean.toString(newValue)); }
// sync. settings
public Long getSyncInterval(String authority) {

@ -0,0 +1,110 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid;
import android.app.Application;
import android.content.SharedPreferences;
import java.io.File;
import java.io.IOException;
import java.util.logging.FileHandler;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import java.util.logging.SimpleFormatter;
import javax.net.ssl.HostnameVerifier;
import at.bitfire.dav4android.*;
import at.bitfire.davdroid.log.LogcatHandler;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Getter;
import okhttp3.internal.tls.OkHostnameVerifier;
public class App extends Application implements SharedPreferences.OnSharedPreferenceChangeListener {
public static final String
PREF_FILE = "global",
PREF_LOG_TO_FILE = "log_to_file",
PREF_VERBOSE_LOGGING = "verbose_logging";
@Getter
private static SSLSocketFactoryCompat sslSocketFactoryCompat;
@Getter
private static HostnameVerifier hostnameVerifier;
public final static Logger log = Logger.getLogger("davdroid");
@Getter
private SharedPreferences preferences;
@Override
public void onCreate() {
super.onCreate();
preferences = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
// initialize MemorizingTrustManager
MemorizingTrustManager mtm = new MemorizingTrustManager(this);
sslSocketFactoryCompat = new SSLSocketFactoryCompat(mtm);
hostnameVerifier = mtm.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE);
reinitLogger();
preferences.registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onTerminate() {
// will never be called on production devices
super.onTerminate();
preferences.unregisterOnSharedPreferenceChangeListener(this);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
reinitLogger();
}
public void reinitLogger() {
// don't use Android default logging, we have our own handlers
log.setUseParentHandlers(false);
// set logging level according to preferences
log.setLevel(preferences.getBoolean(PREF_VERBOSE_LOGGING, false) ? Level.ALL : Level.INFO);
// remove all handlers
for (Handler handler : log.getHandlers())
log.removeHandler(handler);
// add logcat handler
log.addHandler(LogcatHandler.INSTANCE);
// log to external file according to preferences
if (preferences.getBoolean(PREF_LOG_TO_FILE, false)) {
File dir = getExternalFilesDir(null);
if (dir != null)
try {
String pattern = new File(dir, "davdroid-%u.txt").toString();
log.info("Logging to external file: " + pattern);
FileHandler fileHandler = new FileHandler(pattern);
fileHandler.setFormatter(new SimpleFormatter());
log.addHandler(fileHandler);
} catch (IOException e) {
log.log(Level.SEVERE, "Can't create external log file", e);
}
else
log.severe("No external media found, can't create external log file");
}
}
}

@ -40,7 +40,6 @@ import at.bitfire.dav4android.property.CalendarHomeSet;
import at.bitfire.dav4android.property.GroupMembership;
import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB.*;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import lombok.Cleanup;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
@ -277,11 +276,7 @@ public class DavService extends Service {
@Cleanup Cursor cursor = db.query(Services._TABLE, new String[]{Services.ACCOUNT_NAME}, Services.ID + "=?", new String[] { String.valueOf(service) }, null, null, null);
if (cursor.moveToNext()) {
Account account = new Account(cursor.getString(0), Constants.ACCOUNT_TYPE);
AccountSettings settings = new AccountSettings(DavService.this, account);
OkHttpClient httpClient = HttpClient.create(DavService.this);
httpClient = HttpClient.addAuthentication(httpClient, settings.username(), settings.password(), settings.preemptiveAuth());
return httpClient;
return HttpClient.create(DavService.this, account);
} else
throw new IllegalArgumentException("Service not found");
}

@ -8,11 +8,10 @@
package at.bitfire.davdroid;
import android.accounts.Account;
import android.content.Context;
import android.os.Build;
import org.slf4j.Logger;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
@ -20,23 +19,24 @@ import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import at.bitfire.dav4android.BasicDigestAuthenticator;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import de.duenndns.ssl.MemorizingTrustManager;
import at.bitfire.davdroid.log.ExternalFileLogger;
import android.support.annotation.NonNull;
import android.text.format.DateFormat;
import lombok.RequiredArgsConstructor;
import okhttp3.Credentials;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import okhttp3.internal.tls.OkHostnameVerifier;
import okhttp3.logging.HttpLoggingInterceptor;
public class HttpClient {
private static final int MAX_LOG_LINE_LENGTH = 85;
private static final OkHttpClient client = new OkHttpClient();
private static final UserAgentInterceptor userAgentInterceptor = new UserAgentInterceptor();
@ -49,15 +49,14 @@ public class HttpClient {
private HttpClient() {
}
public static OkHttpClient create(Context context) {
public static OkHttpClient create(Context context, Account account) {
OkHttpClient.Builder builder = client.newBuilder();
if (context != null) {
// use MemorizingTrustManager to manage self-signed certificates
MemorizingTrustManager mtm = new MemorizingTrustManager(context);
builder.sslSocketFactory(new SSLSocketFactoryCompat(mtm));
builder.hostnameVerifier(mtm.wrapHostnameVerifier(OkHostnameVerifier.INSTANCE));
}
// use MemorizingTrustManager to manage self-signed certificates
if (App.getSslSocketFactoryCompat() != null)
builder.sslSocketFactory(App.getSslSocketFactoryCompat());
if (App.getHostnameVerifier() != null)
builder.hostnameVerifier(App.getHostnameVerifier());
// set timeouts
builder.connectTimeout(30, TimeUnit.SECONDS);
@ -73,58 +72,57 @@ public class HttpClient {
// add cookie store for non-persistent cookies (some services like Horde use cookies for session tracking)
builder.cookieJar(MemoryCookieStore.INSTANCE);
if (context != null && account != null) {
// use account settings for authentication and logging
AccountSettings settings = new AccountSettings(context, account);
if (settings.preemptiveAuth())
builder.addNetworkInterceptor(new PreemptiveAuthenticationInterceptor(settings.username(), settings.password()));
else
builder.authenticator(new BasicDigestAuthenticator(null, settings.username(), settings.password()));
}
if (App.log.isLoggable(Level.FINEST))
addLogger(builder, App.log);
return builder.build();
}
public static OkHttpClient addAuthentication(@NonNull OkHttpClient httpClient, @NonNull String username, @NonNull String password, boolean preemptive) {
OkHttpClient.Builder builder = httpClient.newBuilder();
private static OkHttpClient.Builder addAuthentication(@NonNull OkHttpClient.Builder builder, @NonNull String username, @NonNull String password, boolean preemptive) {
if (preemptive)
builder.addNetworkInterceptor(new PreemptiveAuthenticationInterceptor(username, password));
else
builder.authenticator(new BasicDigestAuthenticator(null, username, password));
return builder.build();
return builder;
}
public static OkHttpClient addAuthentication(@NonNull OkHttpClient httpClient, @NonNull AccountSettings accountSettings) {
return addAuthentication(httpClient, accountSettings.username(), accountSettings.password(), accountSettings.preemptiveAuth());
public static OkHttpClient addAuthentication(@NonNull OkHttpClient client, @NonNull String username, @NonNull String password, boolean preemptive) {
OkHttpClient.Builder builder = client.newBuilder();
addAuthentication(builder, username, password, preemptive);
return builder.build();
}
public static OkHttpClient addAuthentication(@NonNull OkHttpClient httpClient, @NonNull String host, @NonNull String username, @NonNull String password) {
return httpClient.newBuilder()
public static OkHttpClient addAuthentication(@NonNull OkHttpClient client, @NonNull String host, @NonNull String username, @NonNull String password) {
return client.newBuilder()
.authenticator(new BasicDigestAuthenticator(host, username, password))
.build();
}
public static OkHttpClient addLogger(@NonNull OkHttpClient httpClient, @NonNull final Logger logger) {
// enable verbose logs, if requested
if (logger.isTraceEnabled()) {
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
BufferedReader reader = new BufferedReader(new StringReader(message));
String line;
try {
while ((line = reader.readLine()) != null) {
int len = line.length();
for (int pos = 0; pos < len; pos += MAX_LOG_LINE_LENGTH)
if (pos < len - MAX_LOG_LINE_LENGTH)
logger.trace(line.substring(pos, pos + MAX_LOG_LINE_LENGTH) + "\\");
else
logger.trace(line.substring(pos));
}
} catch(IOException e) {
// for some reason, we couldn't split our message
logger.trace(message);
}
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return httpClient.newBuilder()
.addInterceptor(loggingInterceptor)
.build();
} else
return httpClient;
private static OkHttpClient.Builder addLogger(@NonNull OkHttpClient.Builder builder, @NonNull final Logger logger) {
// trace-level logging → add network traffic interceptor
HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
@Override
public void log(String message) {
logger.finest(message);
}
});
loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
return builder.addInterceptor(loggingInterceptor);
}
public static OkHttpClient addLogger(@NonNull OkHttpClient client, @NonNull final Logger logger) {
return addLogger(client.newBuilder(), logger).build();
}

@ -9,6 +9,7 @@
package at.bitfire.davdroid;
import android.os.Build;
import android.support.annotation.NonNull;
import android.text.TextUtils;
import java.io.IOException;
@ -25,12 +26,10 @@ import java.util.Locale;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import de.duenndns.ssl.MemorizingTrustManager;
import lombok.Cleanup;
import lombok.NonNull;
public class SSLSocketFactoryCompat extends SSLSocketFactory {
@ -51,7 +50,7 @@ public class SSLSocketFactoryCompat extends SSLSocketFactory {
for (String protocol : socket.getSupportedProtocols())
if (!protocol.toUpperCase(Locale.US).contains("SSL"))
protocols.add(protocol);
Constants.log.debug("Setting allowed TLS protocols: " + TextUtils.join(", ", protocols));
Constants.log.info("Setting allowed TLS protocols: " + TextUtils.join(", ", protocols));
SSLSocketFactoryCompat.protocols = protocols.toArray(new String[protocols.size()]);
/* set up reasonable cipher suites */
@ -92,7 +91,7 @@ public class SSLSocketFactoryCompat extends SSLSocketFactory {
HashSet<String> enabledCiphers = preferredCiphers;
enabledCiphers.addAll(new HashSet<>(Arrays.asList(socket.getEnabledCipherSuites())));
Constants.log.debug("Enabling (only) those TLS ciphers: " + TextUtils.join(", ", enabledCiphers));
Constants.log.info("Enabling (only) those TLS ciphers: " + TextUtils.join(", ", enabledCiphers));
SSLSocketFactoryCompat.cipherSuites = enabledCiphers.toArray(new String[enabledCiphers.size()]);
}
}
@ -112,15 +111,11 @@ public class SSLSocketFactoryCompat extends SSLSocketFactory {
}
private void upgradeTLS(SSLSocket ssl) {
if (protocols != null) {
Constants.log.trace("Setting allowed TLS protocols: " + TextUtils.join(", ", protocols));
if (protocols != null)
ssl.setEnabledProtocols(protocols);
}
if (Build.VERSION.SDK_INT < 20 && cipherSuites != null) {
Constants.log.trace("Setting allowed TLS ciphers: " + TextUtils.join(", ", cipherSuites));
if (cipherSuites != null)
ssl.setEnabledCipherSuites(cipherSuites);
}
}

@ -34,7 +34,6 @@ public abstract class CustomLogger implements Logger {
protected String name;
protected PrintWriter writer;
protected boolean verbose;
// CUSTOM LOGGING METHODS
@ -69,36 +68,32 @@ public abstract class CustomLogger implements Logger {
@Override
public boolean isTraceEnabled() {
return verbose;
return true;
}
@Override
public void trace(String msg) {
if (verbose)
log(PREFIX_TRACE, msg);
log(PREFIX_TRACE, msg);
}
@Override
public void trace(String format, Object arg) {
if (verbose)
log(PREFIX_TRACE, format, arg);
log(PREFIX_TRACE, format, arg);
}
@Override
public void trace(String format, Object arg1, Object arg2) {
if (verbose) log(PREFIX_TRACE, format, arg1, arg2);
log(PREFIX_TRACE, format, arg1, arg2);
}
@Override
public void trace(String format, Object... arguments) {
if (verbose)
log(PREFIX_TRACE, format, arguments);
log(PREFIX_TRACE, format, arguments);
}
@Override
public void trace(String msg, Throwable t) {
if (verbose)
log(PREFIX_TRACE, msg, t);
log(PREFIX_TRACE, msg, t);
}

@ -19,9 +19,7 @@ import java.io.PrintWriter;
public class ExternalFileLogger extends CustomLogger implements Closeable {
public ExternalFileLogger(Context context, String fileName, boolean verbose) throws IOException {
this.verbose = verbose;
public ExternalFileLogger(Context context, String fileName) throws IOException {
File dir = getDirectory(context);
if (dir == null)
throw new IOException("External media not available for log creation");

@ -0,0 +1,67 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.log;
import android.util.Log;
import java.util.logging.Formatter;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;
public class LogcatHandler extends Handler {
private static final String TAG = "davdroid";
public static final LogcatHandler INSTANCE = new LogcatHandler();
private LogcatHandler() {
super();
setFormatter(AdbFormatter.INSTANCE);
setLevel(Level.ALL);
}
@Override
public void publish(LogRecord record) {
String line = getFormatter().format(record);
int level = record.getLevel().intValue();
if (level >= Level.SEVERE.intValue())
Log.e(TAG, line);
else if (level >= Level.WARNING.intValue())
Log.w(TAG, line);
else if (level >= Level.CONFIG.intValue())
Log.i(TAG, line);
else if (level >= Level.FINER.intValue())
Log.d(TAG, line);
else
Log.v(TAG, line);
}
@Override
public void flush() {
}
@Override
public void close() {
}
private static class AdbFormatter extends Formatter {
public static AdbFormatter INSTANCE = new AdbFormatter();
private AdbFormatter() {
}
@Override
public String format(LogRecord r) {
return String.format("[%s] %s", r.getSourceClassName(), r.getMessage());
}
}
}

@ -14,16 +14,12 @@ import java.io.StringWriter;
import lombok.Getter;
public class StringLogger extends CustomLogger {
@Getter protected final String name;
protected final StringWriter stringWriter = new StringWriter();
public StringLogger(String name, boolean verbose) {
public StringLogger(String name) {
this.name = name;
this.verbose = verbose;
writer = new PrintWriter(stringWriter);
}
@ -31,5 +27,4 @@ public class StringLogger extends CustomLogger {
return stringWriter.toString();
}
}

@ -290,7 +290,7 @@ public class ContactsSyncManager extends SyncManager {
return null;
}
OkHttpClient resourceClient = HttpClient.create(context);
OkHttpClient resourceClient = HttpClient.create(context, null);
// authenticate only against a certain host, and only upon request
resourceClient = HttpClient.addAuthentication(resourceClient, baseUrl.host(), settings.username(), settings.password());

@ -39,6 +39,7 @@ package at.bitfire.davdroid.syncadapter;
import at.bitfire.dav4android.exception.UnauthorizedException;
import at.bitfire.dav4android.property.GetCTag;
import at.bitfire.dav4android.property.GetETag;
import at.bitfire.davdroid.AccountSettings;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.HttpClient;
import at.bitfire.davdroid.R;
@ -107,21 +108,11 @@ abstract public class SyncManager {
this.authority = authority;
this.syncResult = syncResult;
// get account settings and log to file (if requested)
// get account settings (for sync interval etc.)
settings = new AccountSettings(context, account);
try {
if (settings.logToExternalFile())
log = new ExternalFileLogger(context, "davdroid-SyncManager-" + account.name + "-" + authority + ".txt", settings.logVerbose());
} catch(IOException e) {
Constants.log.error("Couldn't log to external file", e);
}
if (log == null)
log = Constants.log;
// create HttpClient with given logger
httpClient = HttpClient.create(context);
httpClient = HttpClient.addLogger(httpClient, log);
httpClient = HttpClient.addAuthentication(httpClient, settings.username(), settings.password(), settings.preemptiveAuth());
httpClient = HttpClient.create(context, account);
// dismiss previous error notifications
notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);

@ -19,7 +19,7 @@ import android.support.v7.preference.PreferenceFragmentCompat;
import android.support.v7.preference.SwitchPreferenceCompat;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.AccountSettings;
import at.bitfire.ical4android.TaskProvider;
public class AccountSettingsFragment extends PreferenceFragmentCompat {

@ -20,6 +20,7 @@ import android.support.v7.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import at.bitfire.davdroid.App;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.ui.setup.LoginActivity;

@ -50,7 +50,6 @@ import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.Service;
import at.bitfire.davdroid.model.HomeSet;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import lombok.Cleanup;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
@ -195,8 +194,7 @@ public class CreateAddressBookActivity extends AppCompatActivity implements Load
@Override
public Exception loadInBackground() {
OkHttpClient client = HttpClient.create(getContext());
client = HttpClient.addAuthentication(client, new AccountSettings(getContext(), account));
OkHttpClient client = HttpClient.create(getContext(), account);
StringWriter writer = new StringWriter();
try {

@ -16,7 +16,6 @@ import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
@ -39,7 +38,6 @@ import at.bitfire.davdroid.HttpClient;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import lombok.Cleanup;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
@ -126,11 +124,6 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
@Override
public Exception loadInBackground() {
Constants.log.info("MKCOl !!!!");
OkHttpClient client = HttpClient.create(getContext());
client = HttpClient.addAuthentication(client, new AccountSettings(getContext(), account));
StringWriter writer = new StringWriter();
try {
XmlSerializer serializer = XmlUtils.newSerializer();
@ -212,6 +205,8 @@ public class CreateCollectionFragment extends DialogFragment implements LoaderMa
}
ServiceDB.OpenHelper dbHelper = new ServiceDB.OpenHelper(getContext());
OkHttpClient client = HttpClient.create(getContext(), account);
DavResource collection = new DavResource(null, client, HttpUrl.parse(info.url));
try {
// create collection on remote server

@ -24,6 +24,7 @@ import android.provider.CalendarContract;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.TextView;
@ -40,7 +41,7 @@ import at.bitfire.dav4android.exception.HttpException;
import at.bitfire.davdroid.BuildConfig;
import at.bitfire.davdroid.Constants;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.AccountSettings;
public class DebugInfoActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<String> {
public static final String
@ -173,8 +174,7 @@ public class DebugInfoActivity extends AppCompatActivity implements LoaderManage
if (exception != null) {
report.append("\nSTACK TRACE:\n");
for (String stackTrace : ExceptionUtils.getRootCauseStackTrace(exception))
report.append(stackTrace + "\n");
report.append(Log.getStackTraceString(exception));
report.append("\n");
}

@ -32,7 +32,6 @@ import at.bitfire.davdroid.HttpClient;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.model.CollectionInfo;
import at.bitfire.davdroid.model.ServiceDB;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
@ -109,8 +108,7 @@ public class DeleteCollectionFragment extends DialogFragment implements LoaderMa
@Override
public Exception loadInBackground() {
OkHttpClient httpClient = HttpClient.create(getContext());
httpClient = HttpClient.addAuthentication(httpClient, new AccountSettings(getContext(), account));
OkHttpClient httpClient = HttpClient.create(getContext(), account);
DavResource collection = new DavResource(null, httpClient, HttpUrl.parse(collectionInfo.url));
try {

@ -35,7 +35,7 @@ import at.bitfire.davdroid.model.ServiceDB.Collections;
import at.bitfire.davdroid.model.ServiceDB.HomeSets;
import at.bitfire.davdroid.model.ServiceDB.OpenHelper;
import at.bitfire.davdroid.model.ServiceDB.Services;
import at.bitfire.davdroid.syncadapter.AccountSettings;
import at.bitfire.davdroid.AccountSettings;
import at.bitfire.ical4android.TaskProvider;
import lombok.Cleanup;

@ -8,7 +8,7 @@
package at.bitfire.davdroid.ui.setup;
import android.content.Context;
import android.text.TextUtils;
import android.support.annotation.NonNull;
import org.slf4j.Logger;
import org.xbill.DNS.Lookup;
@ -46,7 +46,6 @@ import at.bitfire.dav4android.property.SupportedCalendarComponentSet;
import at.bitfire.davdroid.HttpClient;
import at.bitfire.davdroid.log.StringLogger;
import at.bitfire.davdroid.model.CollectionInfo;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
import okhttp3.HttpUrl;
@ -60,21 +59,21 @@ public class DavResourceFinder {
final String name;
Service(String name) { this.name = name;}
@Override public String toString() { return name; }
};
}
protected final Context context;
protected final LoginCredentialsFragment.LoginCredentials credentials;
protected final LoginCredentials credentials;
protected final Logger log = new StringLogger("DavResourceFinder", true);
protected final Logger log = new StringLogger("DavResourceFinder");
protected OkHttpClient httpClient;
public DavResourceFinder(@NonNull Context context, @NonNull LoginCredentialsFragment.LoginCredentials credentials) {
public DavResourceFinder(@NonNull Context context, @NonNull LoginCredentials credentials) {
this.context = context;
this.credentials = credentials;
httpClient = HttpClient.create(context);
httpClient = HttpClient.addLogger(httpClient, log);
httpClient = HttpClient.create(context, null);
httpClient = HttpClient.addAuthentication(httpClient, credentials.userName, credentials.password, credentials.authPreemptive);
//httpClient = HttpClient.addLogger(httpClient, log);
}

@ -14,6 +14,7 @@ import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
@ -31,9 +32,17 @@ import at.bitfire.davdroid.ui.DebugInfoActivity;
import lombok.Cleanup;
public class DetectConfigurationFragment extends DialogFragment implements LoaderManager.LoaderCallbacks<Configuration> {
protected static final String ARG_LOGIN_CREDENTIALS = "credentials";
public static DetectConfigurationFragment newInstance(LoginCredentials credentials) {
DetectConfigurationFragment frag = new DetectConfigurationFragment();
Bundle args = new Bundle(1);
args.putParcelable(ARG_LOGIN_CREDENTIALS, credentials);
frag.setArguments(args);
return frag;
}
static final String ARG_LOGIN_CREDENTIALS = "credentials";
@NonNull
@Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
ProgressDialog dialog = new ProgressDialog(getActivity());
@ -55,7 +64,7 @@ public class DetectConfigurationFragment extends DialogFragment implements Loade
@Override
public Loader<Configuration> onCreateLoader(int id, Bundle args) {
return new ServerConfigurationLoader(getContext(), args);
return new ServerConfigurationLoader(getContext(), (LoginCredentials)args.getParcelable(ARG_LOGIN_CREDENTIALS));
}
@Override
@ -117,12 +126,12 @@ public class DetectConfigurationFragment extends DialogFragment implements Loade
static class ServerConfigurationLoader extends AsyncTaskLoader<Configuration> {
final Context context;
final LoginCredentialsFragment.LoginCredentials credentials;
final LoginCredentials credentials;
public ServerConfigurationLoader(Context context, Bundle args) {
public ServerConfigurationLoader(Context context, LoginCredentials credentials) {
super(context);
this.context = context;
credentials = (LoginCredentialsFragment.LoginCredentials)args.getParcelable(ARG_LOGIN_CREDENTIALS);
this.credentials = credentials;
}
@Override

@ -0,0 +1,53 @@
/*
* Copyright © 2013 2016 Ricki Hirner (bitfire web engineering).
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the GNU Public License v3.0
* which accompanies this distribution, and is available at
* http://www.gnu.org/licenses/gpl.html
*/
package at.bitfire.davdroid.ui.setup;
import android.os.Parcel;
import android.os.Parcelable;
import java.net.URI;
import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class LoginCredentials implements Parcelable {
public final URI uri;
public final String userName, password;
public final boolean authPreemptive;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(uri);
dest.writeString(userName);
dest.writeString(password);
dest.writeValue(authPreemptive);
}
public static final Creator CREATOR = new Creator<LoginCredentials>() {
@Override
public LoginCredentials createFromParcel(Parcel source) {
LoginCredentials credentials = new LoginCredentials(
(URI)source.readSerializable(),
source.readString(), source.readString(),
(boolean)source.readValue(null)
);
return credentials;
}
@Override
public LoginCredentials[] newArray(int size) {
return new LoginCredentials[size];
}
};
}

@ -10,9 +10,6 @@ package at.bitfire.davdroid.ui.setup;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v7.widget.AppCompatCheckBox;
import android.support.v7.widget.AppCompatRadioButton;
@ -30,7 +27,6 @@ import java.net.URISyntaxException;
import at.bitfire.davdroid.R;
import at.bitfire.davdroid.ui.widget.EditPassword;
import lombok.RequiredArgsConstructor;
public class LoginCredentialsFragment extends Fragment implements CompoundButton.OnCheckedChangeListener {
@ -73,15 +69,8 @@ public class LoginCredentialsFragment extends Fragment implements CompoundButton
@Override
public void onClick(View v) {
LoginCredentials credentials = validateLoginData();
if (credentials != null) {
// login data OK, continue with DetectConfigurationFragment
Bundle args = new Bundle(1);
args.putParcelable(DetectConfigurationFragment.ARG_LOGIN_CREDENTIALS, credentials);
DialogFragment dialog = new DetectConfigurationFragment();
dialog.setArguments(args);
dialog.show(getFragmentManager(), DetectConfigurationFragment.class.getName());
}
if (credentials != null)
DetectConfigurationFragment.newInstance(credentials).show(getFragmentManager(), null);
}
});
@ -126,20 +115,17 @@ public class LoginCredentialsFragment extends Fragment implements CompoundButton
URI uri = null;
boolean valid = true;
String host = null, path = null;
int port = -1;
Uri baseUrl = Uri.parse(editBaseURL.getText().toString());
String scheme = baseUrl.getScheme();
if ("https".equalsIgnoreCase(scheme) || "http".equalsIgnoreCase(scheme)) {
host = IDN.toASCII(baseUrl.getHost());
String host = IDN.toASCII(baseUrl.getHost());
if (host.isEmpty()) {
editBaseURL.setError(getString(R.string.login_url_host_name_required));
valid = false;
}
path = baseUrl.getEncodedPath();
port = baseUrl.getPort();
String path = baseUrl.getEncodedPath();
int port = baseUrl.getPort();
try {
uri = new URI(baseUrl.getScheme(), null, host, port, path, null, null);
} catch (URISyntaxException e) {
@ -169,42 +155,4 @@ public class LoginCredentialsFragment extends Fragment implements CompoundButton
return null;
}
@RequiredArgsConstructor
public static class LoginCredentials implements Parcelable {
public final URI uri;
public final String userName, password;
public final boolean authPreemptive;
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeSerializable(uri);
dest.writeString(userName);
dest.writeString(password);
dest.writeInt(authPreemptive ? 1 : 0);
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<LoginCredentials>() {
@Override
public LoginCredentials createFromParcel(Parcel source) {
LoginCredentials credentials = new LoginCredentials(
(URI)source.readSerializable(),
source.readString(), source.readString(),
source.readInt() != 0 ? true : false
);
return null;
}
@Override
public LoginCredentials[] newArray(int size) {
return new LoginCredentials[0];
}
};
}
}

Loading…
Cancel
Save