mirror of
https://github.com/etesync/android
synced 2025-01-11 00:01:12 +00:00
Debug settings
* preference screen for debug settings * allow to disable HTTP compression * verbose network logging only when activated * single HttpClient for all threads (before: single HttpClient per adapter) * bump version to 0.5.13-alpha
This commit is contained in:
parent
ec94fe61fd
commit
3e4efe8b82
@ -1,8 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="at.bitfire.davdroid"
|
||||
android:versionCode="35"
|
||||
android:versionName="0.5.12-alpha" android:installLocation="internalOnly">
|
||||
android:versionCode="36"
|
||||
android:versionName="0.5.13-alpha" android:installLocation="internalOnly">
|
||||
|
||||
<uses-sdk
|
||||
android:minSdkVersion="14"
|
||||
@ -20,7 +20,8 @@
|
||||
android:allowBackup="false"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AppTheme" >
|
||||
android:theme="@style/AppTheme"
|
||||
android:process=":sync" >
|
||||
<service
|
||||
android:name=".syncadapter.AccountAuthenticatorService"
|
||||
android:exported="false" >
|
||||
@ -34,8 +35,7 @@
|
||||
</service>
|
||||
<service
|
||||
android:name=".syncadapter.ContactsSyncAdapterService"
|
||||
android:exported="true"
|
||||
android:process=":sync" >
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
@ -49,8 +49,7 @@
|
||||
</service>
|
||||
<service
|
||||
android:name=".syncadapter.CalendarsSyncAdapterService"
|
||||
android:exported="true"
|
||||
android:process=":sync" >
|
||||
android:exported="true" >
|
||||
<intent-filter>
|
||||
<action android:name="android.content.SyncAdapter" />
|
||||
</intent-filter>
|
||||
@ -72,6 +71,9 @@
|
||||
android:name=".syncadapter.AddAccountActivity"
|
||||
android:excludeFromRecents="true" >
|
||||
</activity>
|
||||
</application>
|
||||
<activity
|
||||
android:name=".syncadapter.GeneralSettingsActivity" >
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
@ -107,4 +107,13 @@
|
||||
<string name="account_name_info">"Verwenden Sie Ihre Email-Adresse als Kontoname, da Android den Kontonamen als ORGANIZER-Feld in Terminen benutzt. Sie können keine zwei Konten mit dem gleichen Namen anlegen.</string>
|
||||
<string name="read_only">schreibgeschützt</string>
|
||||
|
||||
<string name="general_settings">Allgemeine Einstellungen</string>
|
||||
<string name="debug_settings">Einstellungen zur Fehlersuche</string>
|
||||
<string name="disable_http_compression">HTTP-Komprimierung deaktivieren</string>
|
||||
<string name="http_compression_disabled">HTTP-Komprimierung ist deaktiviert (zur Fehlersuche)</string>
|
||||
<string name="http_compression_enabled">HTTP-Komprimierung wird verwendet, falls möglich</string>
|
||||
<string name="network_logging">Netzwerkverkehr aufzeichnen</string>
|
||||
<string name="network_logging_enabled">Der gesamte Netzwerkverkehr wird in den Android-Logs mitgeschrieben (zur Fehlersuche)</string>
|
||||
<string name="network_logging_disabled">Netzwerkverkehr wird nicht aufgezeichnet</string>
|
||||
|
||||
</resources>
|
@ -113,5 +113,14 @@
|
||||
<string name="organizer_hint">"ORGANIZER of your events; required if you use attendee info"</string>
|
||||
<string name="account_name_info">"Use your email address as account name because Android will use the account name as ORGANIZER field for events you create. You can't have two accounts with the same name.</string>
|
||||
<string name="read_only">read-only</string>
|
||||
|
||||
<string name="general_settings">General settings</string>
|
||||
<string name="debug_settings">Debug settings</string>
|
||||
<string name="disable_http_compression">Disable HTTP compression</string>
|
||||
<string name="http_compression_disabled">HTTP compression is disabled (debug mode)</string>
|
||||
<string name="http_compression_enabled">HTTP compression is used whenever possible</string>
|
||||
<string name="network_logging">Log network traffic</string>
|
||||
<string name="network_logging_enabled">All network traffic is being logged verbosely (debug mode)</string>
|
||||
<string name="network_logging_disabled">Network traffic is not being logged</string>
|
||||
|
||||
</resources>
|
||||
|
@ -1,11 +1,21 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<Preference android:title="@string/davdroid_help" >
|
||||
|
||||
<PreferenceScreen android:title="@string/davdroid_help" >
|
||||
<intent
|
||||
android:targetPackage="at.bitfire.davdroid"
|
||||
android:targetClass="at.bitfire.davdroid.MainActivity"
|
||||
android:action="ACTION_VIEW" />
|
||||
</Preference>
|
||||
</PreferenceScreen>
|
||||
|
||||
|
||||
<PreferenceCategory android:title="@string/general_settings" />
|
||||
|
||||
<PreferenceScreen android:title="@string/debug_settings">
|
||||
<intent
|
||||
android:targetPackage="at.bitfire.davdroid"
|
||||
android:targetClass="at.bitfire.davdroid.syncadapter.GeneralSettingsActivity"
|
||||
android:action="ACTION_VIEW" />
|
||||
</PreferenceScreen>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
11
res/xml/general_settings.xml
Normal file
11
res/xml/general_settings.xml
Normal file
@ -0,0 +1,11 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
|
||||
|
||||
<CheckBoxPreference
|
||||
android:key="disable_compression"
|
||||
android:summaryOff="@string/http_compression_enabled"
|
||||
android:summaryOn="@string/http_compression_disabled"
|
||||
android:title="@string/disable_http_compression" />
|
||||
<CheckBoxPreference android:title="@string/network_logging" android:summaryOn="@string/network_logging_enabled" android:key="network_logging" android:summaryOff="@string/network_logging_disabled"/>
|
||||
|
||||
</PreferenceScreen>
|
@ -12,9 +12,10 @@ package at.bitfire.davdroid;
|
||||
|
||||
public class Constants {
|
||||
public static final String
|
||||
APP_VERSION = "0.5.12-alpha",
|
||||
|
||||
APP_VERSION = "0.5.13-alpha",
|
||||
ACCOUNT_TYPE = "bitfire.at.davdroid",
|
||||
WEB_URL_HELP = "http://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app",
|
||||
|
||||
WEB_URL_HELP = "http://davdroid.bitfire.at/configuration?pk_campaign=davdroid-app";
|
||||
SETTING_DISABLE_COMPRESSION = "disable_compression",
|
||||
SETTING_NETWORK_LOGGING = "network_logging";
|
||||
}
|
||||
|
@ -15,10 +15,10 @@ import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import org.apache.http.HttpStatus;
|
||||
|
||||
import ch.boye.httpclientandroidlib.impl.client.CloseableHttpClient;
|
||||
import lombok.Getter;
|
||||
import android.accounts.Account;
|
||||
import android.accounts.AccountManager;
|
||||
import android.content.AbstractThreadedSyncAdapter;
|
||||
@ -36,6 +36,7 @@ import at.bitfire.davdroid.resource.RemoteCollection;
|
||||
import at.bitfire.davdroid.webdav.DavException;
|
||||
import at.bitfire.davdroid.webdav.DavHttpClient;
|
||||
import at.bitfire.davdroid.webdav.HttpException;
|
||||
import ch.boye.httpclientandroidlib.impl.client.CloseableHttpClient;
|
||||
|
||||
public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter implements Closeable {
|
||||
private final static String TAG = "davdroid.DavSyncAdapter";
|
||||
@ -44,8 +45,17 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
|
||||
protected AccountManager accountManager;
|
||||
|
||||
protected CloseableHttpClient httpClient = DavHttpClient.create();
|
||||
final ReentrantReadWriteLock httpClientLock = new ReentrantReadWriteLock();
|
||||
/* We use one static httpClient for
|
||||
* - all sync adapters (CalendarsSyncAdapter, ContactsSyncAdapter)
|
||||
* - and all threads (= accounts) of each sync adapter
|
||||
* so that HttpClient's threaded pool management can do its best.
|
||||
*/
|
||||
protected static CloseableHttpClient httpClient;
|
||||
|
||||
/* One static read/write lock pair for the static httpClient:
|
||||
* Use the READ lock when httpClient will only be called (to prevent it from being unset while being used).
|
||||
* Use the WRITE lock when httpClient will be modified (set/unset). */
|
||||
private final static ReentrantReadWriteLock httpClientLock = new ReentrantReadWriteLock();
|
||||
|
||||
|
||||
public DavSyncAdapter(Context context) {
|
||||
@ -61,14 +71,18 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
// apparently may be called from a GUI thread
|
||||
Log.d(TAG, "Closing httpClient");
|
||||
|
||||
// may be called from a GUI thread, so we need an AsyncTask
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
try {
|
||||
httpClientLock.writeLock().lock();
|
||||
httpClient.close();
|
||||
httpClient = null;
|
||||
if (httpClient != null) {
|
||||
httpClient.close();
|
||||
httpClient = null;
|
||||
}
|
||||
httpClientLock.writeLock().unlock();
|
||||
} catch (IOException e) {
|
||||
Log.w(TAG, "Couldn't close HTTP client", e);
|
||||
@ -78,7 +92,6 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
}.execute();
|
||||
}
|
||||
|
||||
|
||||
protected abstract Map<LocalCollection<?>, RemoteCollection<?>> getSyncPairs(Account account, ContentProviderClient provider);
|
||||
|
||||
|
||||
@ -89,42 +102,57 @@ public abstract class DavSyncAdapter extends AbstractThreadedSyncAdapter impleme
|
||||
// set class loader for iCal4j ResourceLoader
|
||||
Thread.currentThread().setContextClassLoader(getContext().getClassLoader());
|
||||
|
||||
Map<LocalCollection<?>, RemoteCollection<?>> syncCollections = getSyncPairs(account, provider);
|
||||
if (syncCollections == null)
|
||||
Log.i(TAG, "Nothing to synchronize");
|
||||
else
|
||||
try {
|
||||
// prevent httpClient shutdown until we're ready
|
||||
httpClientLock.readLock().lock();
|
||||
|
||||
for (Map.Entry<LocalCollection<?>, RemoteCollection<?>> entry : syncCollections.entrySet())
|
||||
new SyncManager(entry.getKey(), entry.getValue()).synchronize(extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL), syncResult);
|
||||
|
||||
} catch (DavException ex) {
|
||||
syncResult.stats.numParseExceptions++;
|
||||
Log.e(TAG, "Invalid DAV response", ex);
|
||||
|
||||
} catch (HttpException ex) {
|
||||
if (ex.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
Log.e(TAG, "HTTP Unauthorized " + ex.getCode(), ex);
|
||||
syncResult.stats.numAuthExceptions++;
|
||||
} else if (ex.isClientError()) {
|
||||
Log.e(TAG, "Hard HTTP error " + ex.getCode(), ex);
|
||||
// create httpClient, if necessary
|
||||
httpClientLock.writeLock().lock();
|
||||
if (httpClient == null) {
|
||||
Log.d(TAG, "Creating new DavHttpClient");
|
||||
httpClient = DavHttpClient.create(getContext());
|
||||
}
|
||||
|
||||
// prevent httpClient shutdown until we're ready by holding a read lock
|
||||
// acquiring read lock before releasing write lock will downgrade the write lock to a read lock
|
||||
httpClientLock.readLock().lock();
|
||||
httpClientLock.writeLock().unlock();
|
||||
|
||||
try {
|
||||
// get local <-> remote collection pairs
|
||||
Map<LocalCollection<?>, RemoteCollection<?>> syncCollections = getSyncPairs(account, provider);
|
||||
if (syncCollections == null)
|
||||
Log.i(TAG, "Nothing to synchronize");
|
||||
else
|
||||
try {
|
||||
for (Map.Entry<LocalCollection<?>, RemoteCollection<?>> entry : syncCollections.entrySet())
|
||||
new SyncManager(entry.getKey(), entry.getValue()).synchronize(extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL), syncResult);
|
||||
|
||||
} catch (DavException ex) {
|
||||
syncResult.stats.numParseExceptions++;
|
||||
} else {
|
||||
Log.w(TAG, "Soft HTTP error " + ex.getCode() + " (Android will try again later)", ex);
|
||||
Log.e(TAG, "Invalid DAV response", ex);
|
||||
|
||||
} catch (HttpException ex) {
|
||||
if (ex.getCode() == HttpStatus.SC_UNAUTHORIZED) {
|
||||
Log.e(TAG, "HTTP Unauthorized " + ex.getCode(), ex);
|
||||
syncResult.stats.numAuthExceptions++;
|
||||
} else if (ex.isClientError()) {
|
||||
Log.e(TAG, "Hard HTTP error " + ex.getCode(), ex);
|
||||
syncResult.stats.numParseExceptions++;
|
||||
} else {
|
||||
Log.w(TAG, "Soft HTTP error " + ex.getCode() + " (Android will try again later)", ex);
|
||||
syncResult.stats.numIoExceptions++;
|
||||
}
|
||||
|
||||
} catch (LocalStorageException ex) {
|
||||
syncResult.databaseError = true;
|
||||
Log.e(TAG, "Local storage (content provider) exception", ex);
|
||||
} catch (IOException ex) {
|
||||
syncResult.stats.numIoExceptions++;
|
||||
Log.e(TAG, "I/O error (Android will try again later)", ex);
|
||||
}
|
||||
|
||||
} catch (LocalStorageException ex) {
|
||||
syncResult.databaseError = true;
|
||||
Log.e(TAG, "Local storage (content provider) exception", ex);
|
||||
} catch (IOException ex) {
|
||||
syncResult.stats.numIoExceptions++;
|
||||
Log.e(TAG, "I/O error (Android will try again later)", ex);
|
||||
} finally {
|
||||
// allow httpClient shutdown
|
||||
httpClientLock.readLock().unlock();
|
||||
}
|
||||
} finally {
|
||||
// allow httpClient shutdown
|
||||
httpClientLock.readLock().unlock();
|
||||
}
|
||||
|
||||
Log.i(TAG, "Sync complete for " + authority);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,30 @@
|
||||
package at.bitfire.davdroid.syncadapter;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceFragment;
|
||||
import at.bitfire.davdroid.R;
|
||||
|
||||
public class GeneralSettingsActivity extends Activity {
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getFragmentManager().beginTransaction()
|
||||
.replace(android.R.id.content, new GeneralSettingsFragment())
|
||||
.commit();
|
||||
}
|
||||
|
||||
|
||||
public static class GeneralSettingsFragment extends PreferenceFragment {
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
getPreferenceManager().setSharedPreferencesMode(Context.MODE_MULTI_PROCESS);
|
||||
addPreferencesFromResource(R.xml.general_settings);
|
||||
}
|
||||
}
|
||||
}
|
@ -96,10 +96,12 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
||||
|
||||
static class ServerInfoLoader extends AsyncTaskLoader<ServerInfo> {
|
||||
private static final String TAG = "davdroid.ServerInfoLoader";
|
||||
Bundle args;
|
||||
final Bundle args;
|
||||
final Context context;
|
||||
|
||||
public ServerInfoLoader(Context context, Bundle args) {
|
||||
super(context);
|
||||
this.context = context;
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
@ -112,7 +114,7 @@ public class QueryServerDialogFragment extends DialogFragment implements LoaderC
|
||||
args.getBoolean(EXTRA_AUTH_PREEMPTIVE)
|
||||
);
|
||||
|
||||
CloseableHttpClient httpClient = DavHttpClient.create();
|
||||
CloseableHttpClient httpClient = DavHttpClient.create(context);
|
||||
try {
|
||||
// (1/5) detect capabilities
|
||||
WebDavResource base = new WebDavResource(httpClient, new URI(serverInfo.getProvidedURL()), serverInfo.getUserName(),
|
||||
|
@ -10,6 +10,10 @@
|
||||
******************************************************************************/
|
||||
package at.bitfire.davdroid.webdav;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.util.Log;
|
||||
import at.bitfire.davdroid.Constants;
|
||||
import ch.boye.httpclientandroidlib.client.config.RequestConfig;
|
||||
import ch.boye.httpclientandroidlib.config.Registry;
|
||||
@ -17,11 +21,13 @@ import ch.boye.httpclientandroidlib.config.RegistryBuilder;
|
||||
import ch.boye.httpclientandroidlib.conn.socket.ConnectionSocketFactory;
|
||||
import ch.boye.httpclientandroidlib.conn.socket.PlainConnectionSocketFactory;
|
||||
import ch.boye.httpclientandroidlib.impl.client.CloseableHttpClient;
|
||||
import ch.boye.httpclientandroidlib.impl.client.HttpClientBuilder;
|
||||
import ch.boye.httpclientandroidlib.impl.client.HttpClients;
|
||||
import ch.boye.httpclientandroidlib.impl.conn.ManagedHttpClientConnectionFactory;
|
||||
import ch.boye.httpclientandroidlib.impl.conn.PoolingHttpClientConnectionManager;
|
||||
|
||||
public class DavHttpClient {
|
||||
private final static String TAG = "davdroid.DavHttpClient";
|
||||
|
||||
private final static RequestConfig defaultRqConfig;
|
||||
private final static Registry<ConnectionSocketFactory> socketFactoryRegistry;
|
||||
@ -38,28 +44,34 @@ public class DavHttpClient {
|
||||
.setSocketTimeout(20*1000)
|
||||
.setStaleConnectionCheckEnabled(false)
|
||||
.build();
|
||||
|
||||
// enable logging
|
||||
ManagedHttpClientConnectionFactory.INSTANCE.wirelog.enableDebug(true);
|
||||
ManagedHttpClientConnectionFactory.INSTANCE.log.enableDebug(true);
|
||||
}
|
||||
|
||||
|
||||
public static CloseableHttpClient create() {
|
||||
|
||||
public static CloseableHttpClient create(Context context) {
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
|
||||
// limits per DavHttpClient (= per DavSyncAdapter extends AbstractThreadedSyncAdapter)
|
||||
connectionManager.setMaxTotal(2); // max. 2 connections in total
|
||||
connectionManager.setMaxTotal(3); // max. 3 connections in total
|
||||
connectionManager.setDefaultMaxPerRoute(2); // max. 2 connections per host
|
||||
|
||||
return HttpClients.custom()
|
||||
HttpClientBuilder builder = HttpClients.custom()
|
||||
.useSystemProperties()
|
||||
.setConnectionManager(connectionManager)
|
||||
.setDefaultRequestConfig(defaultRqConfig)
|
||||
.setRetryHandler(DavHttpRequestRetryHandler.INSTANCE)
|
||||
.setUserAgent("DAVdroid/" + Constants.APP_VERSION)
|
||||
.disableCookieManagement()
|
||||
.build();
|
||||
.disableCookieManagement();
|
||||
|
||||
// debug options
|
||||
SharedPreferences settings = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
if (settings.getBoolean(Constants.SETTING_DISABLE_COMPRESSION, false))
|
||||
builder = builder.disableContentCompression();
|
||||
|
||||
boolean networkLogging = settings.getBoolean(Constants.SETTING_NETWORK_LOGGING, false);
|
||||
Log.d(TAG, "Network logging: " + networkLogging);
|
||||
ManagedHttpClientConnectionFactory.INSTANCE.wirelog.enableDebug(networkLogging);
|
||||
ManagedHttpClientConnectionFactory.INSTANCE.log.enableDebug(networkLogging);
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user