mirror of
https://github.com/bitfireAT/davx5-ose.git
synced 2026-01-06 05:47:50 -05:00
Compare commits
22 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f1f16ffe4f | ||
|
|
0214a3adb5 | ||
|
|
7cea2a8379 | ||
|
|
d07df21b47 | ||
|
|
0459c9844c | ||
|
|
de2b4ad506 | ||
|
|
38e28b1b20 | ||
|
|
da2567c49c | ||
|
|
a51e903324 | ||
|
|
5da5506754 | ||
|
|
e0cb048802 | ||
|
|
b1a09eecb5 | ||
|
|
1bb6a0de89 | ||
|
|
678b3824c2 | ||
|
|
83054635d5 | ||
|
|
33a6494389 | ||
|
|
5913892bb6 | ||
|
|
69b3273fdc | ||
|
|
88c8f88c88 | ||
|
|
28af03749a | ||
|
|
c54da0812a | ||
|
|
7454d21a52 |
@@ -12,13 +12,13 @@ apply plugin: 'kotlin-android-extensions'
|
||||
|
||||
android {
|
||||
compileSdkVersion 26
|
||||
buildToolsVersion '26.0.0'
|
||||
buildToolsVersion '26.0.1'
|
||||
|
||||
defaultConfig {
|
||||
applicationId "at.bitfire.davdroid"
|
||||
resValue "string", "packageID", applicationId
|
||||
|
||||
versionCode 163
|
||||
versionCode 167
|
||||
buildConfigField "long", "buildTime", System.currentTimeMillis() + "L"
|
||||
|
||||
minSdkVersion 16
|
||||
@@ -30,19 +30,19 @@ android {
|
||||
|
||||
productFlavors {
|
||||
standard {
|
||||
versionName "1.7"
|
||||
versionName "1.7.3"
|
||||
buildConfigField "boolean", "customCerts", "true"
|
||||
}
|
||||
|
||||
gplay {
|
||||
versionName "1.7-gplay"
|
||||
versionName "1.7.3-gplay"
|
||||
buildConfigField "boolean", "customCerts", "true"
|
||||
}
|
||||
icloud {
|
||||
applicationId "at.bitfire.cloudsync"
|
||||
resValue "string", "packageID", applicationId
|
||||
|
||||
versionName "1.7-cloud"
|
||||
versionName "1.7.3-cloud"
|
||||
buildConfigField "at.bitfire.vcard4android.GroupMethod", "settingContactGroupMethod", "at.bitfire.vcard4android.GroupMethod.GROUP_VCARDS"
|
||||
}
|
||||
soldupe {
|
||||
@@ -50,7 +50,7 @@ android {
|
||||
resValue "string", "packageID", applicationId
|
||||
minSdkVersion 21
|
||||
|
||||
versionName "1.7-soldupe"
|
||||
versionName "1.7.3-soldupe"
|
||||
buildConfigField "boolean", "customCerts", "true"
|
||||
buildConfigField "at.bitfire.vcard4android.GroupMethod", "settingContactGroupMethod", "at.bitfire.vcard4android.GroupMethod.CATEGORIES"
|
||||
}
|
||||
@@ -122,18 +122,14 @@ dependencies {
|
||||
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
|
||||
|
||||
//noinspection GradleDynamicVersion
|
||||
compile 'com.android.support:appcompat-v7:26.+'
|
||||
//noinspection GradleDynamicVersion
|
||||
compile 'com.android.support:cardview-v7:26.+'
|
||||
//noinspection GradleDynamicVersion
|
||||
compile 'com.android.support:design:26.+'
|
||||
//noinspection GradleDynamicVersion
|
||||
compile 'com.android.support:preference-v14:26.+'
|
||||
compile 'com.android.support:appcompat-v7:26.0.1'
|
||||
compile 'com.android.support:cardview-v7:26.0.1'
|
||||
compile 'com.android.support:design:26.0.1'
|
||||
compile 'com.android.support:preference-v14:26.0.1'
|
||||
|
||||
compile 'com.github.yukuku:ambilwarna:2.0.1'
|
||||
|
||||
compile 'com.squareup.okhttp3:logging-interceptor:3.8.1'
|
||||
compile 'com.squareup.okhttp3:logging-interceptor:3.9.0'
|
||||
compile 'commons-io:commons-io:2.5'
|
||||
compile 'dnsjava:dnsjava:2.1.8'
|
||||
compile 'org.apache.commons:commons-lang3:3.6'
|
||||
@@ -149,8 +145,8 @@ dependencies {
|
||||
exclude group: 'com.android.support', module: 'support-annotations'
|
||||
}
|
||||
androidTestCompile 'junit:junit:4.12'
|
||||
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.8.1'
|
||||
androidTestCompile 'com.squareup.okhttp3:mockwebserver:3.9.0'
|
||||
|
||||
testCompile 'junit:junit:4.12'
|
||||
testCompile 'com.squareup.okhttp3:mockwebserver:3.8.1'
|
||||
testCompile 'com.squareup.okhttp3:mockwebserver:3.9.0'
|
||||
}
|
||||
|
||||
@@ -12,20 +12,23 @@
|
||||
-allowaccessmodification
|
||||
-dontpreverify
|
||||
|
||||
# Kotlin
|
||||
-dontwarn kotlin.**
|
||||
|
||||
# ez-vcard
|
||||
-dontwarn ezvcard.io.json.** # JSON serializer (for jCards) not used
|
||||
-dontwarn freemarker.** # freemarker templating library (for creating hCards) not used
|
||||
-dontwarn org.jsoup.** # jsoup library (for hCard parsing) not used
|
||||
-dontwarn sun.misc.Perf
|
||||
-keep class ezvcard.property.** { *; } # keep all VCard properties (created at runtime)
|
||||
|
||||
# ical4j: ignore unused dynamic libraries
|
||||
-dontwarn aQute.**
|
||||
-dontwarn groovy.** # Groovy-based ContentBuilder not used
|
||||
-dontwarn net.fortuna.ical4j.model.**
|
||||
-dontwarn org.codehaus.groovy.**
|
||||
-dontwarn net.fortuna.ical4j.model.** # ignore warnings from Groovy dependency
|
||||
-dontwarn org.apache.log4j.** # ignore warnings from log4j dependency
|
||||
-keep class net.fortuna.ical4j.** { *; } # keep all model classes (properties/factories, created at runtime)
|
||||
-keep class org.threeten.bp.** { *; } # keep ThreeTen (for time zone processing)
|
||||
|
||||
# okhttp
|
||||
-dontwarn okio.**
|
||||
|
||||
@@ -16,10 +16,13 @@ import java.io.IOException;
|
||||
import java.net.Socket;
|
||||
|
||||
import javax.net.ssl.SSLSocket;
|
||||
import javax.net.ssl.TrustManagerFactory;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
|
||||
import at.bitfire.cert4android.CustomCertManager;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
|
||||
import static android.support.test.InstrumentationRegistry.getInstrumentation;
|
||||
import static android.support.test.InstrumentationRegistry.getTargetContext;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static org.apache.commons.lang3.ArrayUtils.contains;
|
||||
@@ -27,18 +30,21 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class SSLSocketFactoryCompatTest {
|
||||
|
||||
CustomCertManager certMgr;
|
||||
SSLSocketFactoryCompat factory;
|
||||
MockWebServer server = new MockWebServer();
|
||||
|
||||
@Before
|
||||
public void startServer() throws Exception {
|
||||
factory = new SSLSocketFactoryCompat(new CustomCertManager(getTargetContext().getApplicationContext(), true));
|
||||
certMgr = new CustomCertManager(getInstrumentation().getContext(), true, null);
|
||||
factory = new SSLSocketFactoryCompat(certMgr);
|
||||
server.start();
|
||||
}
|
||||
|
||||
@After
|
||||
public void stopServer() throws Exception {
|
||||
server.shutdown();
|
||||
certMgr.close();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@ package at.bitfire.davdroid.model;
|
||||
|
||||
import android.content.ContentValues;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
@@ -30,8 +32,20 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class CollectionInfoTest {
|
||||
|
||||
HttpClient httpClient;
|
||||
MockWebServer server = new MockWebServer();
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
httpClient = new HttpClient.Builder().build();
|
||||
}
|
||||
|
||||
@After
|
||||
public void shutDown() {
|
||||
httpClient.close();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testFromDavResource() throws IOException, HttpException, DavException {
|
||||
// r/w address book
|
||||
@@ -48,7 +62,7 @@ public class CollectionInfoTest {
|
||||
"</response>" +
|
||||
"</multistatus>"));
|
||||
|
||||
DavResource dav = new DavResource(HttpClient.create(null), server.url("/"));
|
||||
DavResource dav = new DavResource(httpClient.getOkHttpClient(), server.url("/"));
|
||||
dav.propfind(0, ResourceType.NAME);
|
||||
CollectionInfo info = new CollectionInfo(dav);
|
||||
assertEquals(CollectionInfo.Type.ADDRESS_BOOK, info.getType());
|
||||
@@ -72,7 +86,7 @@ public class CollectionInfoTest {
|
||||
"</response>" +
|
||||
"</multistatus>"));
|
||||
|
||||
dav = new DavResource(HttpClient.create(null), server.url("/"));
|
||||
dav = new DavResource(httpClient.getOkHttpClient(), server.url("/"));
|
||||
dav.propfind(0, ResourceType.NAME);
|
||||
info = new CollectionInfo(dav);
|
||||
assertEquals(CollectionInfo.Type.CALENDAR, info.getType());
|
||||
|
||||
@@ -23,7 +23,6 @@ import at.bitfire.dav4android.property.ResourceType;
|
||||
import at.bitfire.davdroid.HttpClient;
|
||||
import at.bitfire.davdroid.log.Logger;
|
||||
import at.bitfire.davdroid.ui.setup.DavResourceFinder.Configuration.ServiceInfo;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.mockwebserver.Dispatcher;
|
||||
import okhttp3.mockwebserver.MockResponse;
|
||||
import okhttp3.mockwebserver.MockWebServer;
|
||||
@@ -40,7 +39,7 @@ public class DavResourceFinderTest {
|
||||
MockWebServer server = new MockWebServer();
|
||||
|
||||
DavResourceFinder finder;
|
||||
OkHttpClient client;
|
||||
HttpClient client;
|
||||
LoginCredentials credentials;
|
||||
|
||||
private static final String
|
||||
@@ -62,8 +61,9 @@ public class DavResourceFinderTest {
|
||||
credentials = new LoginCredentials(URI.create("/"), "mock", "12345");
|
||||
finder = new DavResourceFinder(getTargetContext(), credentials);
|
||||
|
||||
client = HttpClient.create(null);
|
||||
client = HttpClient.addAuthentication(client, credentials.getUserName(), credentials.getPassword());
|
||||
client = new HttpClient.Builder()
|
||||
.addAuthentication(null, credentials.getUserName(), credentials.getPassword())
|
||||
.build();
|
||||
}
|
||||
|
||||
@After
|
||||
@@ -76,7 +76,7 @@ public class DavResourceFinderTest {
|
||||
ServiceInfo info;
|
||||
|
||||
// before dav.propfind(), no info is available
|
||||
DavResource dav = new DavResource(client, server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL));
|
||||
DavResource dav = new DavResource(client.getOkHttpClient(), server.url(PATH_CARDDAV + SUBPATH_PRINCIPAL));
|
||||
finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo());
|
||||
assertEquals(0, info.getCollections().size());
|
||||
assertEquals(0, info.getHomeSets().size());
|
||||
@@ -89,7 +89,7 @@ public class DavResourceFinderTest {
|
||||
assertEquals(server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK_HOMESET + "/").uri(), info.getHomeSets().iterator().next());
|
||||
|
||||
// recognize address book
|
||||
dav = new DavResource(client, server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK));
|
||||
dav = new DavResource(client.getOkHttpClient(), server.url(PATH_CARDDAV + SUBPATH_ADDRESSBOOK));
|
||||
dav.propfind(0, ResourceType.NAME);
|
||||
finder.rememberIfAddressBookOrHomeset(dav, info = new ServiceInfo());
|
||||
assertEquals(1, info.getCollections().size());
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<string name="startup_battery_optimization_message">Android peut désactiver/réduire la synchronisation de DAVdroid après quelques jours. Pour éviter cela, désactivez l\'optimisation de la batterie.</string>
|
||||
<string name="startup_battery_optimization_disable">Désactiver pour DAVdroid</string>
|
||||
<string name="startup_dont_show_again">Ne plus afficher</string>
|
||||
<string name="startup_development_version">Aperçu de la version finale</string>
|
||||
<string name="startup_development_version_give_feedback">Faire un commentaire</string>
|
||||
<string name="startup_donate">Open-Source Information</string>
|
||||
<string name="startup_donate_message">Nous sommes heureux que vous utilisez DAVdroid, qui est un logiciel open-source (GPLv3). Parce que développer DAVdroid est un travail difficile et nous a pris de nombreuses heures, s\'il vous plaît envisager de faire un don.</string>
|
||||
@@ -21,7 +22,7 @@
|
||||
<string name="startup_google_play_accounts_removed">Erreur information Play Store DRM</string>
|
||||
<string name="startup_google_play_accounts_removed_message">Dans certaines conditions, Play Store DRM peut provoquer la disparition de tous les comptes DAVdroid après un redémarrage ou après la mise à niveau de DAVdroid. Si vous êtes concerné par ce problème (et seulement alors), s\'il vous plaît installer \"DAVdroid JB Solution\" du Play Store.</string>
|
||||
<string name="startup_google_play_accounts_removed_more_info">Plus d\'informations</string>
|
||||
<string name="startup_opentasks_not_installed">OpenTasks n\'est pas installé</string>
|
||||
<string name="startup_opentasks_not_installed">L\'application OpenTasks n\'est pas installée</string>
|
||||
<string name="startup_opentasks_not_installed_message">L\'application OpenTasks n\'est pas disponible, donc DAVdroid ne pourra pas synchroniser des listes de tâches.</string>
|
||||
<string name="startup_opentasks_reinstall_davdroid">Après l\'installation OpenTasks, vous devez RE-INSTALLER DAVdroid et ajoutez vos comptes à nouveau (bug Android).</string>
|
||||
<string name="startup_opentasks_not_installed_install">Installer OpenTasks</string>
|
||||
@@ -40,12 +41,13 @@
|
||||
<string name="navigation_drawer_subtitle">Adaptateur de synchronisation CalDAV/CardDAV</string>
|
||||
<string name="navigation_drawer_about">A propos / Licence</string>
|
||||
<string name="navigation_drawer_settings">Paramètres</string>
|
||||
<string name="navigation_drawer_news_updates">Actualité & mise à jour</string>
|
||||
<string name="navigation_drawer_news_updates">Actualités & mises à jour</string>
|
||||
<string name="navigation_drawer_external_links">Liens externes</string>
|
||||
<string name="navigation_drawer_website">Site Web</string>
|
||||
<string name="navigation_drawer_faq">FAQ</string>
|
||||
<string name="navigation_drawer_faq">Foire aux questions</string>
|
||||
<string name="navigation_drawer_forums">Aide/Forum</string>
|
||||
<string name="navigation_drawer_donate">Faire un don</string>
|
||||
<string name="account_list_empty">Bienvenue sur DAVdroid!\n\nVous pouvez maintenant ajouter un compte CalDAV/CardDAV.</string>
|
||||
<string name="account_list_empty">Bienvenue sur DAVdroid!\n\nVous pouvez maintenant ajouter un compte CalDAV ou CardDAV.</string>
|
||||
<string name="accounts_global_sync_disabled">La synchronisation automatique globale est désactivée</string>
|
||||
<string name="accounts_global_sync_enable">Activer</string>
|
||||
<!--DavService-->
|
||||
@@ -95,7 +97,7 @@
|
||||
<string name="permissions_calendar">Autorisations calendrier</string>
|
||||
<string name="permissions_calendar_details">Pour synchroniser les événements CalDAV avec vos calendriers locaux, DAVdroid a besoin d\'accéder à vos calendriers.</string>
|
||||
<string name="permissions_calendar_request">Demande d\'autorisations d\'accéder au calendrier</string>
|
||||
<string name="permissions_contacts">Autorisations contacts</string>
|
||||
<string name="permissions_contacts">Autorisations d\'accès aux contacts</string>
|
||||
<string name="permissions_contacts_details">Pour synchroniser les carnets d\'adresses de CardDAV avec votre carnet d\'adresses local, DAVdroid a besoin d\'accéder à vos contacts.</string>
|
||||
<string name="permissions_contacts_request">Demande d\'autorisations d\'accéder aux contacts</string>
|
||||
<string name="permissions_opentasks">Autorisations OpenTasks</string>
|
||||
@@ -124,8 +126,8 @@
|
||||
<string name="login_account_name_required">Nom du compte requis</string>
|
||||
<string name="login_account_not_created">Le compte n\'a pas pu être créé</string>
|
||||
<string name="login_configuration_detection">Détection de la configuration</string>
|
||||
<string name="login_querying_server">S\'il vous plaît patienter, nous interrogeons le serveur ...</string>
|
||||
<string name="login_no_caldav_carddav">Aucun service CalDAV ou CardDAV trouvé.</string>
|
||||
<string name="login_querying_server">Veuillez patienter, nous interrogeons le serveur ...</string>
|
||||
<string name="login_no_caldav_carddav">Aucun accès possible au service CalDAV ou CardDAV.</string>
|
||||
<string name="login_view_logs">Voir infos de débogage</string>
|
||||
<!--AccountSettingsActivity-->
|
||||
<string name="settings_title">Paramètres: %s</string>
|
||||
@@ -164,6 +166,10 @@
|
||||
<string name="settings_sync_wifi_only">Synchronisation en Wifi seulement</string>
|
||||
<string name="settings_sync_wifi_only_on">La synchronisation est limitée aux connexions WiFi</string>
|
||||
<string name="settings_sync_wifi_only_off">Le type de connexion n\'est pas pris en charge</string>
|
||||
<string name="settings_sync_wifi_only_ssids">Restrictions concernant le nom de réseau WiFi (SSID)</string>
|
||||
<string name="settings_sync_wifi_only_ssids_on">Synchronisation possible seulement en %s</string>
|
||||
<string name="settings_sync_wifi_only_ssids_off">Toutes les connexions WiFi seront utilisées</string>
|
||||
<string name="settings_sync_wifi_only_ssids_message">Liste des points d\'accès WiFi (SSID) autorisés, séparés par des virgules. (Laissez vide pour tous)</string>
|
||||
<string name="settings_carddav">CardDAV</string>
|
||||
<string name="settings_contact_group_method">Méthode pour les contacts de type groupe</string>
|
||||
<string-array name="settings_contact_group_method_values">
|
||||
@@ -185,6 +191,10 @@
|
||||
<string name="settings_manage_calendar_colors">Choisir couleur du calendrier</string>
|
||||
<string name="settings_manage_calendar_colors_on">Les couleurs de calendrier sont gérées par DAVdroid</string>
|
||||
<string name="settings_manage_calendar_colors_off">Les couleurs de calendrier ne sont pas gérées par DAVdroid</string>
|
||||
<string name="settings_event_colors">Couleur associée aux événements</string>
|
||||
<string name="settings_event_colors_on">Synchroniser la couleur associée aux événements</string>
|
||||
<string name="settings_event_colors_off">Ne pas synchroniser la couleur associée aux événements</string>
|
||||
<string name="settings_event_colors_off_confirm">Modifier la couleur associée aux événements peut affecter les valeurs déjà synchronisées.</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">Créer un carnet d\'adresses</string>
|
||||
<string name="create_addressbook_display_name_hint">Mon carnet d\'adresses</string>
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
<string name="startup_development_version">プレビュー リリース</string>
|
||||
<string name="startup_development_version_message">これは %s の開発版です。期待した通りに動作しない可能性があります。フィードバックを歓迎します。</string>
|
||||
<string name="startup_development_version_give_feedback">フィードバックする</string>
|
||||
<string name="startup_development_version_feedback_url">https://davdroid.bitfire.at/forums/?pk_campaign=davdroid-app</string>
|
||||
<string name="startup_donate">オープンソース情報</string>
|
||||
<string name="startup_donate_message">あなたがオープンソース ソフトウェア (GPLv3) の DAVdroid を使用していただくことに、私たちは満足しています。 DAVdroid の開発はハードワークで、何千もの作業時間がかかりました。寄付をご検討ください。</string>
|
||||
<string name="startup_donate_now">寄付ページを表示</string>
|
||||
@@ -184,6 +183,10 @@
|
||||
<string name="settings_manage_calendar_colors">カレンダーの色を管理</string>
|
||||
<string name="settings_manage_calendar_colors_on">カレンダーの色は DAVdroid が管理します</string>
|
||||
<string name="settings_manage_calendar_colors_off">カレンダーの色を DAVdroid が設定しません</string>
|
||||
<string name="settings_event_colors">イベントカラーサポート</string>
|
||||
<string name="settings_event_colors_on">イベントカラーを同期</string>
|
||||
<string name="settings_event_colors_off">イベントカラーを同期しない</string>
|
||||
<string name="settings_event_colors_off_confirm">イベントカラーをオフにすると、すでに同期しているイベントカラーが削除されることがあります。</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">アドレス帳を作成</string>
|
||||
<string name="create_addressbook_display_name_hint">マイ アドレス帳</string>
|
||||
|
||||
154
app/src/davdroid/res/values-nb-rNO/strings.xml
Normal file
154
app/src/davdroid/res/values-nb-rNO/strings.xml
Normal file
@@ -0,0 +1,154 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--common strings-->
|
||||
<string name="app_name">DAVdroid</string>
|
||||
<string name="account_title_address_book">DAVdroid-adressebok</string>
|
||||
<string name="address_books_authority_title">Adressebøker</string>
|
||||
<string name="help">Hjelp</string>
|
||||
<string name="manage_accounts">Behandle kontoer</string>
|
||||
<string name="please_wait">Vent…</string>
|
||||
<string name="send">Send</string>
|
||||
<!--startup dialogs-->
|
||||
<string name="startup_battery_optimization">Batterioptimisering</string>
|
||||
<string name="startup_battery_optimization_message">Det kan hende Android skrur av/reduserer DAVdroid-synkronisering etter et par dager. For å forhindre dette, skru av batterioptimisering.</string>
|
||||
<string name="startup_battery_optimization_disable">Skru av for DAVdroid</string>
|
||||
<string name="startup_dont_show_again">Ikke vis igjen</string>
|
||||
<string name="startup_development_version">Forhåndsutgivelse</string>
|
||||
<string name="startup_development_version_message">Dette er en utviklingsversjon av %s. Det kan hende ting ikke svarer til forventningene. Dine tilbakemeldinger er kjærkomne.</string>
|
||||
<string name="startup_development_version_give_feedback">Gi tilbakemelding</string>
|
||||
<string name="startup_donate">Friprog-informasjon</string>
|
||||
<string name="startup_donate_message">Vi er glade for at du bruker DAVdroid, som er fri programvare (GPLv3). Siden utvikling av DAVdroid er hardt arbeid og har tatt tusenvis av arbeidstimer, bes du overveie en donasjon.</string>
|
||||
<string name="startup_donate_now">Vis donasjonsside</string>
|
||||
<string name="startup_donate_later">Kanskje senere</string>
|
||||
<string name="startup_google_play_accounts_removed_more_info">Mer informasjon</string>
|
||||
<!--AboutActivity-->
|
||||
<string name="about_license_terms">Lisensvilkår</string>
|
||||
<!--global settings-->
|
||||
<string name="logging_to_external_storage">Logger til ekstern lagringsmedium: %s</string>
|
||||
<string name="logging_to_external_storage_warning">Slett logger så snart som mulig!</string>
|
||||
<string name="logging_couldnt_create_file">Kan ikke opprette ekstern loggfil: %s</string>
|
||||
<string name="logging_no_external_storage">Fant ingen ekstern lagringsplass</string>
|
||||
<!--AccountsActivity-->
|
||||
<string name="navigation_drawer_open">Åpne navigasjonsskuff</string>
|
||||
<string name="navigation_drawer_close">Lukk navigasjonsskuff</string>
|
||||
<string name="navigation_drawer_about">Om / Lisens</string>
|
||||
<string name="navigation_drawer_settings">Innstillinger</string>
|
||||
<string name="navigation_drawer_external_links">Eksterne lenker</string>
|
||||
<string name="navigation_drawer_website">Nettside</string>
|
||||
<string name="navigation_drawer_faq">O-S-S</string>
|
||||
<string name="navigation_drawer_forums">Hjelp / Forum</string>
|
||||
<string name="navigation_drawer_donate">Doner</string>
|
||||
<string name="accounts_global_sync_disabled">Systemomspennende automatisk synkronisering avskrudd</string>
|
||||
<string name="accounts_global_sync_enable">Skru på</string>
|
||||
<!--DavService-->
|
||||
<string name="dav_service_refresh_failed">Tjenesteoppdagelse mislyktes</string>
|
||||
<string name="dav_service_refresh_couldnt_refresh">Kunne ikke gjenoppfriske innsamlingsliste</string>
|
||||
<!--AppSettingsActivity-->
|
||||
<string name="app_settings">Innstillinger</string>
|
||||
<string name="app_settings_user_interface">Brukergrensesnitt</string>
|
||||
<string name="app_settings_reset_hints">Tilbakestill hint</string>
|
||||
<string name="app_settings_reset_hints_summary">Skrur på hint som har blitt avslått tidligere</string>
|
||||
<string name="app_settings_reset_hints_success">Alle hint vil bli vist igjen</string>
|
||||
<string name="app_settings_connection">Tilkobling</string>
|
||||
<string name="app_settings_override_proxy">Overstyr mellomtjenerinnstillinger</string>
|
||||
<string name="app_settings_override_proxy_on">Bruk egendefinerte mellomtjenerinnstillinger</string>
|
||||
<string name="app_settings_override_proxy_off">Bruk systemets forvalgte mellomtjenerinnstillinger</string>
|
||||
<string name="app_settings_override_proxy_host">Vertsnavn for HTTP-mellomtjener</string>
|
||||
<string name="app_settings_override_proxy_port">HTTP-mellomtjeningsport</string>
|
||||
<string name="app_settings_security">Sikkerhet</string>
|
||||
<string name="app_settings_distrust_system_certs">Fjern tiltro til systemsertifikater</string>
|
||||
<string name="app_settings_debug">Feilretting</string>
|
||||
<string name="app_settings_log_to_external_storage">Logg til ekstern fil</string>
|
||||
<string name="app_settings_log_to_external_storage_on">Logger til eksternt lagringsmedium (hvis tilgjengelig)</string>
|
||||
<string name="app_settings_show_debug_info">Vis feilrettingsinfo</string>
|
||||
<string name="app_settings_show_debug_info_details">Vis/del programvare- og oppsettsdetaljer</string>
|
||||
<!--AccountActivity-->
|
||||
<string name="account_synchronize_now">Synkroniser nå</string>
|
||||
<string name="account_synchronizing_now">Synkroniserer nå</string>
|
||||
<string name="account_settings">Kontoinnstillinger</string>
|
||||
<string name="account_rename">Gi konto nytt navn</string>
|
||||
<string name="account_rename_rename">Gi nytt navn</string>
|
||||
<string name="account_delete">Slett konto</string>
|
||||
<string name="account_delete_confirmation_title">Vil du virkeling slette kontoen?</string>
|
||||
<string name="account_refresh_address_book_list">Gjenoppfrisk adressebokliste</string>
|
||||
<string name="account_create_new_address_book">Opprett ny adressebok</string>
|
||||
<string name="account_refresh_calendar_list">Gjenoppfrisk kalenderliste</string>
|
||||
<string name="account_create_new_calendar">Opprett ny kalender</string>
|
||||
<!--PermissionsActivity-->
|
||||
<string name="permissions_title">DAVdroid-tilgang</string>
|
||||
<string name="permissions_calendar">Kalender-tilgang</string>
|
||||
<string name="permissions_calendar_request">Forespør kalender-tilganger</string>
|
||||
<string name="permissions_contacts">Kontakt-tilgang</string>
|
||||
<string name="permissions_contacts_request">Forespør kontakt-tilgang</string>
|
||||
<!--AddAccountActivity-->
|
||||
<string name="login_title">Legg til konto</string>
|
||||
<string name="login_email_address">E-postadresse</string>
|
||||
<string name="login_email_address_error">Gyldig e-postadresse påkrevd</string>
|
||||
<string name="login_password">Passord</string>
|
||||
<string name="login_password_required">Passord kreves</string>
|
||||
<string name="login_url_must_be_http_or_https">Nettadresse må begynned med http(s)://</string>
|
||||
<string name="login_url_host_name_required">Vertsnavn kreves</string>
|
||||
<string name="login_back">Tilbake</string>
|
||||
<string name="login_create_account">Opprett konto</string>
|
||||
<string name="login_account_name">Kontonavn</string>
|
||||
<string name="login_account_name_required">Kontonavn påkrevd</string>
|
||||
<string name="login_account_not_created">Kontonavnet kan ikke opprettes</string>
|
||||
<string name="login_configuration_detection">Oppdagelse av oppsett</string>
|
||||
<string name="login_querying_server">Vent, spør tjener…</string>
|
||||
<string name="login_no_caldav_carddav">Fant ikke CalDAV eller CardDAV-tjeneste.</string>
|
||||
<string name="login_view_logs">Vis logger</string>
|
||||
<!--AccountSettingsActivity-->
|
||||
<string name="settings_title">Innstillinger: %s</string>
|
||||
<string name="settings_authentication">Identitetsbekreftelse</string>
|
||||
<string name="settings_username">Brukernavn</string>
|
||||
<string name="settings_enter_username">Skriv inn brukernavn:</string>
|
||||
<string name="settings_password">Passord</string>
|
||||
<string name="settings_password_summary">Oppdater passordet i henhold til din tjener.</string>
|
||||
<string name="settings_enter_password">Skriv inn passordet ditt:</string>
|
||||
<string name="settings_sync">Synkronisering</string>
|
||||
<string name="settings_sync_interval_contacts">Intervall for kontaktsynkronisering</string>
|
||||
<string name="settings_sync_summary_manually">Åpne manuelt</string>
|
||||
<string name="settings_sync_wifi_only">Bare synk. over Wi-Fi</string>
|
||||
<string name="settings_sync_wifi_only_off">Tilkoblingstypen blir ikke tatt i betraktning</string>
|
||||
<string name="settings_carddav">CardDAV</string>
|
||||
<string name="settings_caldav">CalDAV</string>
|
||||
<string name="settings_sync_time_range_past_none">Alle gjøremål vil bli synkronisert</string>
|
||||
<plurals name="settings_sync_time_range_past_days">
|
||||
<item quantity="one">Gjøremål for mer enn én dag siden vil bli sett bort fra</item>
|
||||
<item quantity="other">Gjøremål for mer enn %d dager siden vil bli sett bort fra</item>
|
||||
</plurals>
|
||||
<string name="settings_manage_calendar_colors">Velg kalenderfarger</string>
|
||||
<string name="settings_manage_calendar_colors_on">Kalenderfarger behandles av DAVdroid</string>
|
||||
<string name="settings_manage_calendar_colors_off">Kalenderfarger settes ikke av DAVdroid</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">Opprett adressebok</string>
|
||||
<string name="create_addressbook_display_name_hint">Min adressebok</string>
|
||||
<string name="create_calendar">Opprett CalDAV-samling</string>
|
||||
<string name="create_calendar_display_name_hint">Min kalender</string>
|
||||
<string name="create_calendar_time_zone">Tidssone</string>
|
||||
<string name="create_calendar_type">Samlingstype:</string>
|
||||
<string name="create_calendar_type_only_events">Kalender (bare hendelser)</string>
|
||||
<string name="create_calendar_type_only_tasks">Gjøremålsliste (bare gjøremål)</string>
|
||||
<string name="create_calendar_type_events_and_tasks">Kombinert (hendelser og gjøremål)</string>
|
||||
<string name="create_collection_color">Velg en samlingsfarge</string>
|
||||
<string name="create_collection_creating">Oppretter samling</string>
|
||||
<string name="create_collection_display_name">Vis navn (tittel) for denne samlingen:</string>
|
||||
<string name="create_collection_display_name_required">Tittel kreves</string>
|
||||
<string name="create_collection_description">Beskrivelse (valgfri):</string>
|
||||
<string name="create_collection_create">Opprett</string>
|
||||
<string name="delete_collection">Slett samling</string>
|
||||
<string name="delete_collection_confirm_title">Er du sikker?</string>
|
||||
<string name="delete_collection_deleting_collection">Sletter samling</string>
|
||||
<!--ExceptionInfoFragment-->
|
||||
<string name="exception">En feil har inntruffet</string>
|
||||
<string name="exception_httpexception">En HTTP-feil har inntruffet.</string>
|
||||
<string name="exception_ioexception">En I/O-feil har inntruffet.</string>
|
||||
<string name="exception_show_details">Vis detaljer</string>
|
||||
<!--sync errors and DebugInfoActivity-->
|
||||
<string name="debug_info_title">Feilrettingsinfo</string>
|
||||
<string name="sync_error_tasks">Gjøremålssynkronisering mislyktes (%s)</string>
|
||||
<string name="sync_error_unauthorized">Brukernavn-/passord feil</string>
|
||||
<!--cert4android-->
|
||||
<string name="certificate_notification_connection_security">DAVdroid: Tilkoblingssikkerhet</string>
|
||||
<string name="trust_certificate_unknown_certificate_found">DAVdroid har støtt på et ukjent sertifikat. Har du tiltro til det?</string>
|
||||
</resources>
|
||||
@@ -17,7 +17,6 @@
|
||||
<string name="startup_development_version">Voorvertoning van uitgave</string>
|
||||
<string name="startup_development_version_message">Dit is ontwikkelversie %s. Onderdelen werken niet zoals verwacht. Je terugkoppeling is welkom.</string>
|
||||
<string name="startup_development_version_give_feedback">Feedback geven</string>
|
||||
<string name="startup_development_version_feedback_url">https://davdroid.bitfire.at/forums/?pk_campaign=davdroid-app</string>
|
||||
<string name="startup_donate">Open-Source informatie</string>
|
||||
<string name="startup_donate_message">We zijn blij dat je DAVdroid gebruikt, wat open-source software (GPLv3) is. Omdat de ontwikkeling van DAVdroid hard werk is en duizenden uren in beslag neemt. overweeg alstublieft een donatie.</string>
|
||||
<string name="startup_donate_now">Toon donatie pagina</string>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<string name="navigation_drawer_external_links">Zewnętrzne odnośniki</string>
|
||||
<string name="navigation_drawer_website">Strona WWW</string>
|
||||
<string name="navigation_drawer_faq">FQA</string>
|
||||
<string name="navigation_drawer_forums">Pomoc / Forum</string>
|
||||
<string name="navigation_drawer_donate">Dotacja</string>
|
||||
<string name="account_list_empty">Witamy w DAVdroid!\n\nMożesz teraz dodać konto CalDAV/CardDAV.</string>
|
||||
<string name="accounts_global_sync_disabled">Automatyczna synchronizacja dla całego systemu jest wyłączona</string>
|
||||
@@ -165,6 +166,10 @@
|
||||
<string name="settings_sync_wifi_only">Synchronizuj tylko przez WiFi</string>
|
||||
<string name="settings_sync_wifi_only_on">Synchronizacja jest ograniczony do połączeń WiFi</string>
|
||||
<string name="settings_sync_wifi_only_off">Rodzaj połączenia nie jest brany pod uwagę</string>
|
||||
<string name="settings_sync_wifi_only_ssids">Ograniczenia WiFi SSID</string>
|
||||
<string name="settings_sync_wifi_only_ssids_on">Będzie synchronizować tylko w %s</string>
|
||||
<string name="settings_sync_wifi_only_ssids_off">Wszystkie połączenia WiFi będą używane</string>
|
||||
<string name="settings_sync_wifi_only_ssids_message">Nazwy oddzielone przecinkami (SSID) dozwolonych sieci WiFi (pozostaw puste dla wszystkich)</string>
|
||||
<string name="settings_carddav">CardDAV</string>
|
||||
<string name="settings_contact_group_method">Metoda grupowania kontaktów</string>
|
||||
<string-array name="settings_contact_group_method_values">
|
||||
@@ -184,6 +189,10 @@
|
||||
<string name="settings_manage_calendar_colors">Zarządzaj kolorami kalendarza</string>
|
||||
<string name="settings_manage_calendar_colors_on">Kolory kalendarza są zarządzane przez DAVdroid</string>
|
||||
<string name="settings_manage_calendar_colors_off">Kolory kalendarze nie są ustawiane przez DAVdroid</string>
|
||||
<string name="settings_event_colors">Obsługa kolorów wydarzeń</string>
|
||||
<string name="settings_event_colors_on">Synchronizuj kolorów zdarzeń</string>
|
||||
<string name="settings_event_colors_off">Nie synchronizuj kolorów zdarzeń</string>
|
||||
<string name="settings_event_colors_off_confirm">Wyłączenie kolorów zdarzeń może usunąć już zsynchronizowane kolory zdarzeń.</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">Stwórz książkę adresową</string>
|
||||
<string name="create_addressbook_display_name_hint">Moja książka adresowa</string>
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
<string name="navigation_drawer_external_links">Links externos</string>
|
||||
<string name="navigation_drawer_website">Site na Web</string>
|
||||
<string name="navigation_drawer_faq">Perguntas fequentes</string>
|
||||
<string name="navigation_drawer_forums">Ajuda / Fóruns</string>
|
||||
<string name="navigation_drawer_donate">Doações</string>
|
||||
<string name="account_list_empty">Bem-vindo ao DAVdroid!\n\nVocê pode adicionar uma conta CalDAV/CardDAV agora.</string>
|
||||
<string name="accounts_global_sync_disabled">A sincronização automática pelo sistema está desativada</string>
|
||||
@@ -165,6 +166,10 @@
|
||||
<string name="settings_sync_wifi_only">Sincronizar apenas por Wi-Fi</string>
|
||||
<string name="settings_sync_wifi_only_on">Sincronização restrita a conexões Wi-Fi</string>
|
||||
<string name="settings_sync_wifi_only_off">O tipo de conexão não é considerado</string>
|
||||
<string name="settings_sync_wifi_only_ssids">Restrição de WiFi SSID</string>
|
||||
<string name="settings_sync_wifi_only_ssids_on">Sincronizar apenas com %s</string>
|
||||
<string name="settings_sync_wifi_only_ssids_off">Todas as conexões WiFi serão usadas</string>
|
||||
<string name="settings_sync_wifi_only_ssids_message">Nomes separados por vírgula (SSIDs) das redes WiFi (deixe em branco para todas)</string>
|
||||
<string name="settings_carddav">CardDAV</string>
|
||||
<string name="settings_contact_group_method">Método do grupo Contato</string>
|
||||
<string-array name="settings_contact_group_method_values">
|
||||
@@ -186,6 +191,10 @@
|
||||
<string name="settings_manage_calendar_colors">Gerenciar cores dos calendários</string>
|
||||
<string name="settings_manage_calendar_colors_on">Cores dos calendários definidas pelo DAVdroid</string>
|
||||
<string name="settings_manage_calendar_colors_off">Cores dos calendários não definidas pelo DAVdroid</string>
|
||||
<string name="settings_event_colors">Suporte para cor de evento</string>
|
||||
<string name="settings_event_colors_on">Sincronizar cores de eventos</string>
|
||||
<string name="settings_event_colors_off">Não sincronizar cores de eventos</string>
|
||||
<string name="settings_event_colors_off_confirm">Desativar as cores de eventos poderá remover as que já foram sincronizadas</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">Criar livro de endereços</string>
|
||||
<string name="create_addressbook_display_name_hint">Meu livro de endereços</string>
|
||||
|
||||
232
app/src/davdroid/res/values-zh-rTW/strings.xml
Normal file
232
app/src/davdroid/res/values-zh-rTW/strings.xml
Normal file
@@ -0,0 +1,232 @@
|
||||
<?xml version='1.0' encoding='UTF-8'?>
|
||||
<resources xmlns:tools="http://schemas.android.com/tools">
|
||||
<!--common strings-->
|
||||
<string name="app_name">DAVdroid</string>
|
||||
<string name="account_title_address_book">DAVdroid 通訊錄</string>
|
||||
<string name="address_books_authority_title">通訊錄</string>
|
||||
<string name="help">幫助</string>
|
||||
<string name="manage_accounts">管理帳號</string>
|
||||
<string name="please_wait">請稍待 ...</string>
|
||||
<string name="send">送出</string>
|
||||
<string name="homepage_url">https://davdroid.bitfire.at/?pk_campaign=davdroid-app</string>
|
||||
<!--startup dialogs-->
|
||||
<string name="startup_battery_optimization">電池最佳化</string>
|
||||
<string name="startup_battery_optimization_message">Android 在數日之後可能會關閉或減少 DAVdroid 的同步。為了避免這發生,請關閉電池最佳化。</string>
|
||||
<string name="startup_battery_optimization_disable">關閉 DAVdroid 的電池最佳化</string>
|
||||
<string name="startup_dont_show_again">不要再顯示此訊息</string>
|
||||
<string name="startup_development_version_give_feedback">給回饋意見</string>
|
||||
<string name="startup_donate">開源資訊</string>
|
||||
<string name="startup_donate_message">很高興您使用 DAVdroid,這是個開源軟體 (GPLv3授權)。因為開發 DAVdroid 是艱難的工作,需要上千個小時,請考慮捐款支持我們。</string>
|
||||
<string name="startup_donate_now">開啟捐款頁面</string>
|
||||
<string name="startup_donate_later">下次再說</string>
|
||||
<string name="startup_google_play_accounts_removed">Play商店數位權利管理錯誤訊息</string>
|
||||
<string name="startup_google_play_accounts_removed_message">在某些情況下,Play商店 的數位權利管理可能導致在重開機後或更新 DAVdroid 後,DAVdroid 全部帳號消失。如果您遇到此問題 (且只有在遇到此問題時),請到 Play商店 安裝 \"DAVdroid JB Workaround\"。</string>
|
||||
<string name="startup_google_play_accounts_removed_more_info">更多資訊</string>
|
||||
<string name="startup_opentasks_not_installed">OpenTasks 未安裝</string>
|
||||
<string name="startup_opentasks_not_installed_message">OpenTasks 這個 app 不存在您的裝置上,所以 DAVdroid 無法同步工作清單。</string>
|
||||
<string name="startup_opentasks_reinstall_davdroid">安裝 OpenTasks 後,您必須「重新安裝」 DAVdroid 並且重新加入要同步的帳號 (這是 Android 的設計問題)</string>
|
||||
<string name="startup_opentasks_not_installed_install">安裝 OpenTasks</string>
|
||||
<!--AboutActivity-->
|
||||
<string name="about_license_terms">授權條款</string>
|
||||
<string name="about_license_info_no_warranty">我們「完全不保證」本程式無瑕疵。這是個自由軟體,歡迎您在符合公用授權條款的情況下任意散布它。</string>
|
||||
<!--global settings-->
|
||||
<string name="logging_davdroid_file_logging">DAVdroid 正在記錄除錯訊息</string>
|
||||
<string name="logging_to_external_storage">正在將除錯訊息存到外部檔案: %s</string>
|
||||
<string name="logging_to_external_storage_warning">盡快刪除除錯訊息!</string>
|
||||
<string name="logging_couldnt_create_file">無法新增除錯訊息檔案: %s</string>
|
||||
<string name="logging_no_external_storage">找不到外部儲存空間</string>
|
||||
<!--AccountsActivity-->
|
||||
<string name="navigation_drawer_open">開啟瀏覽窗格</string>
|
||||
<string name="navigation_drawer_close">關閉瀏覽窗格</string>
|
||||
<string name="navigation_drawer_subtitle">CalDAV/CardDAV 同步器</string>
|
||||
<string name="navigation_drawer_about">關於我們 / 授權條款</string>
|
||||
<string name="navigation_drawer_settings">設定</string>
|
||||
<string name="navigation_drawer_news_updates">新聞 & 更新</string>
|
||||
<string name="navigation_drawer_external_links">外部連結</string>
|
||||
<string name="navigation_drawer_website">我們的網站</string>
|
||||
<string name="navigation_drawer_faq">常見問答</string>
|
||||
<string name="navigation_drawer_faq_url">https://davdroid.bitfire.at/faq/?pk_campaign=davdroid-app</string>
|
||||
<string name="navigation_drawer_donate">贊助我們</string>
|
||||
<string name="account_list_empty">歡迎使用 DAVdroid!\n\n您現在可以新增 CalDAV/CardDAV 帳號</string>
|
||||
<string name="accounts_global_sync_enable">啟用</string>
|
||||
<!--DavService-->
|
||||
<string name="dav_service_refresh_failed">未發現遠端服務</string>
|
||||
<string name="dav_service_refresh_couldnt_refresh">無法更新清單</string>
|
||||
<!--AppSettingsActivity-->
|
||||
<string name="app_settings">設定</string>
|
||||
<string name="app_settings_user_interface">使用介面</string>
|
||||
<string name="app_settings_reset_hints">重新開啟提示</string>
|
||||
<string name="app_settings_reset_hints_summary">重新啟用之前取消的提示</string>
|
||||
<string name="app_settings_reset_hints_success">所有提示將再次顯示</string>
|
||||
<string name="app_settings_connection">網路連線</string>
|
||||
<string name="app_settings_override_proxy">自訂代理伺服器</string>
|
||||
<string name="app_settings_override_proxy_on">正在使用自訂的代理伺服器設定值</string>
|
||||
<string name="app_settings_override_proxy_off">正在使用系統預設的代理伺服器設定值</string>
|
||||
<string name="app_settings_override_proxy_host">HTTP 代理伺服器主機名稱或網址</string>
|
||||
<string name="app_settings_override_proxy_port">HTTP 代理伺服器通訊埠</string>
|
||||
<string name="app_settings_security">安全性</string>
|
||||
<string name="app_settings_distrust_system_certs">不信任系統憑證</string>
|
||||
<string name="app_settings_distrust_system_certs_on">系統憑證和使用者自訂憑證將不被信任</string>
|
||||
<string name="app_settings_distrust_system_certs_off">系統憑證和使用者自訂憑證將被信任 (推薦設定)</string>
|
||||
<string name="app_settings_reset_certificates">重新開啟之前關閉的提示</string>
|
||||
<string name="app_settings_reset_certificates_summary">重設對所有自訂憑證的信任</string>
|
||||
<string name="app_settings_reset_certificates_success">所有自訂憑證已清除</string>
|
||||
<string name="app_settings_debug">除錯</string>
|
||||
<string name="app_settings_log_to_external_storage">將除錯訊息存到外部檔案</string>
|
||||
<string name="app_settings_log_to_external_storage_on">除錯訊息將存到外部檔案 (如果發生)</string>
|
||||
<string name="app_settings_log_to_external_storage_off">目前不將除錯訊息存到外部檔案</string>
|
||||
<string name="app_settings_show_debug_info">顯示除錯訊息</string>
|
||||
<string name="app_settings_show_debug_info_details">檢視/分享本軟體及設定檔細節</string>
|
||||
<!--AccountActivity-->
|
||||
<string name="account_synchronize_now">立即同步</string>
|
||||
<string name="account_synchronizing_now">同步中</string>
|
||||
<string name="account_settings">帳號設定</string>
|
||||
<string name="account_rename">重新命名帳號</string>
|
||||
<string name="account_rename_new_name">尚未儲存的本地資料可能會消失。重新命名後必須再次執行同步。新的帳號名稱: </string>
|
||||
<string name="account_rename_rename">重新命名</string>
|
||||
<string name="account_delete">刪除帳號</string>
|
||||
<string name="account_delete_confirmation_title">真的要刪除帳號?</string>
|
||||
<string name="account_delete_confirmation_text">這台裝置上這個帳號的通訊錄、行事曆和工作清單將被刪除。</string>
|
||||
<string name="account_refresh_address_book_list">刷新通訊錄清單</string>
|
||||
<string name="account_create_new_address_book">建立新的通訊錄</string>
|
||||
<string name="account_refresh_calendar_list">刷新行事曆清單</string>
|
||||
<string name="account_create_new_calendar">建立新的行事曆</string>
|
||||
<!--PermissionsActivity-->
|
||||
<string name="permissions_title">DAVdroid 權限</string>
|
||||
<string name="permissions_calendar">行事曆權限</string>
|
||||
<string name="permissions_calendar_details">為了將 CalDAV 行事曆與您裝置上的行事曆同步,DAVdroid 需要存取行事曆的權限。</string>
|
||||
<string name="permissions_calendar_request">要求行事曆權限</string>
|
||||
<string name="permissions_contacts">通訊錄權限</string>
|
||||
<string name="permissions_contacts_details">為了將 CardDAV 通訊錄與您裝置上的通訊錄同步,DAVdroid 需要存取通訊錄的權限。</string>
|
||||
<string name="permissions_contacts_request">要求通訊錄權限</string>
|
||||
<string name="permissions_opentasks">OpenTasks 權限</string>
|
||||
<string name="permissions_opentasks_details">為了將 CalDAV 工作清單與您裝置上的工作清單同步,DAVdroid 需要存取 OpenTasks 的權限。</string>
|
||||
<string name="permissions_opentasks_request">要求 OpenTasks 權限</string>
|
||||
<!--AddAccountActivity-->
|
||||
<string name="login_help_url">https://davdroid.bitfire.at/configuration/?pk_campaign=davdroid-app</string>
|
||||
<string name="login_title">新增帳號</string>
|
||||
<string name="login_type_email">用 Email 地址登入</string>
|
||||
<string name="login_email_address">Email 地址</string>
|
||||
<string name="login_email_address_error">請輸入有效的 Email 地址</string>
|
||||
<string name="login_password">密碼</string>
|
||||
<string name="login_password_required">必須填寫密碼</string>
|
||||
<string name="login_type_url">用網址和帳號登入</string>
|
||||
<string name="login_url_must_be_http_or_https">網址開頭必須是 http(s)://</string>
|
||||
<string name="login_url_host_name_required">必須輸入伺服器主機名稱</string>
|
||||
<string name="login_user_name">使用者帳號</string>
|
||||
<string name="login_user_name_required">必須填寫使用者帳號</string>
|
||||
<string name="login_base_url">根 URL</string>
|
||||
<string name="login_login">登入</string>
|
||||
<string name="login_back">上一步</string>
|
||||
<string name="login_create_account">新建帳號</string>
|
||||
<string name="login_account_name">帳號名稱</string>
|
||||
<string name="login_account_name_info">使用 Email 地址當作裝置上的帳號顯示名稱,因為當您在行事曆創建活動時,Android 會把帳號顯示名稱放到「活動發起人」欄位。兩個帳號不能有相同的名稱。</string>
|
||||
<string name="login_account_contact_group_method">聯絡人群組的儲存格式</string>
|
||||
<string name="login_account_name_required">需要帳號名稱</string>
|
||||
<string name="login_account_not_created">無法建立帳號</string>
|
||||
<string name="login_configuration_detection">設定錯誤</string>
|
||||
<string name="login_querying_server">請稍待,正在詢問伺服器...</string>
|
||||
<string name="login_no_caldav_carddav">找不到 CalDAV 或 CardDAV 服務。</string>
|
||||
<string name="login_view_logs">檢視除錯訊息</string>
|
||||
<!--AccountSettingsActivity-->
|
||||
<string name="settings_title">設定: %s</string>
|
||||
<string name="settings_authentication">登入驗證</string>
|
||||
<string name="settings_username">使用者帳號</string>
|
||||
<string name="settings_enter_username">輸入帳號名稱:</string>
|
||||
<string name="settings_password">密碼</string>
|
||||
<string name="settings_password_summary">您在伺服器上使用中的密碼</string>
|
||||
<string name="settings_enter_password">輸入密碼: </string>
|
||||
<string name="settings_sync">同步設定</string>
|
||||
<string name="settings_sync_interval_contacts">聯絡人同步間隔</string>
|
||||
<string name="settings_sync_summary_manually">只手動同步</string>
|
||||
<string name="settings_sync_summary_periodically" tools:ignore="PluralsCandidate">每 %d 分鐘,以及在本裝置上修改時</string>
|
||||
<string name="settings_sync_interval_calendars">行事曆同步間隔</string>
|
||||
<string name="settings_sync_interval_tasks">工作清單同步間隔</string>
|
||||
<string-array name="settings_sync_interval_names">
|
||||
<item>只手動</item>
|
||||
<item>每 5 分鐘</item>
|
||||
<item>每 10 分鐘</item>
|
||||
<item>每 15 分鐘</item>
|
||||
<item>每 1 小時</item>
|
||||
<item>每 2 小時</item>
|
||||
<item>每 4 小時</item>
|
||||
<item>每 1 天</item>
|
||||
</string-array>
|
||||
<string name="settings_sync_wifi_only">只用 WiFi 同步</string>
|
||||
<string name="settings_sync_wifi_only_on">只於 WiFi 連線時同步</string>
|
||||
<string name="settings_sync_wifi_only_off">任何網路連線都可使用</string>
|
||||
<string name="settings_carddav">CardDAV(聯絡人檔案)</string>
|
||||
<string name="settings_contact_group_method">聯絡人群組的儲存格式</string>
|
||||
<string-array name="settings_contact_group_method_values">
|
||||
<item>GROUP_VCARDS</item>
|
||||
<item>CATEGORIES</item>
|
||||
</string-array>
|
||||
<string-array name="settings_contact_group_method_entries">
|
||||
<item>群組存成額外的 VCard 檔案</item>
|
||||
<item>群組存成每個聯絡人的分類屬性</item>
|
||||
</string-array>
|
||||
<string name="settings_caldav">CalDav(行事曆檔案)</string>
|
||||
<string name="settings_sync_time_range_past">過去項目的時間限制</string>
|
||||
<string name="settings_sync_time_range_past_none">將會同步所有項目</string>
|
||||
<plurals name="settings_sync_time_range_past_days">
|
||||
<item quantity="other">%d 天之前的項目會被忽略</item>
|
||||
</plurals>
|
||||
<string name="settings_sync_time_range_past_message">這個天數之前的項目將被忽略 (可設為0)。留白,則所有項目都會同步。</string>
|
||||
<string name="settings_manage_calendar_colors">管理行事曆的顏色</string>
|
||||
<string name="settings_manage_calendar_colors_on">行事曆顏色由 DAVdroid 管理</string>
|
||||
<string name="settings_manage_calendar_colors_off">行事曆顏色不由 DAVdroid 管理</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">建立通訊錄</string>
|
||||
<string name="create_addressbook_display_name_hint">我的通訊錄</string>
|
||||
<string name="create_calendar">建立行事曆</string>
|
||||
<string name="create_calendar_display_name_hint">我的行事曆</string>
|
||||
<string name="create_calendar_time_zone">時區: </string>
|
||||
<string name="create_calendar_type">類型</string>
|
||||
<string name="create_calendar_type_only_events">行事曆 (只有事件)</string>
|
||||
<string name="create_calendar_type_only_tasks">工作清單 (只有任務)</string>
|
||||
<string name="create_calendar_type_events_and_tasks">合併 (事件和任務)</string>
|
||||
<string name="create_collection_color">設定顏色</string>
|
||||
<string name="create_collection_creating">建立新行事曆或工作清單</string>
|
||||
<string name="create_collection_display_name">顯示這份清單的名稱 (標題): </string>
|
||||
<string name="create_collection_display_name_required">必須輸入標題</string>
|
||||
<string name="create_collection_description">描述 (可留白): </string>
|
||||
<string name="create_collection_home_set">Home set: </string>
|
||||
<string name="create_collection_create">建立</string>
|
||||
<string name="delete_collection">刪除行事曆或工作清單</string>
|
||||
<string name="delete_collection_confirm_title">您確定嗎? </string>
|
||||
<string name="delete_collection_confirm_warning">這本行事曆或工作清單 (%s) 和它的所有資料將從伺服器上刪除。</string>
|
||||
<string name="delete_collection_deleting_collection">正在刪除</string>
|
||||
<!--ExceptionInfoFragment-->
|
||||
<string name="exception">發生錯誤</string>
|
||||
<string name="exception_httpexception">HTTP 發生錯誤</string>
|
||||
<string name="exception_ioexception">讀寫錯誤</string>
|
||||
<string name="exception_show_details">顯示細節</string>
|
||||
<!--sync errors and DebugInfoActivity-->
|
||||
<string name="debug_info_title">除錯訊息</string>
|
||||
<string name="sync_error_permissions">DAVdroid 權限</string>
|
||||
<string name="sync_error_permissions_text">需要額外的權限</string>
|
||||
<string name="sync_error_calendar">行事曆同步失敗 (%s)</string>
|
||||
<string name="sync_error_contacts">通訊錄同步失敗 (%s)</string>
|
||||
<string name="sync_error_tasks">工作清單同步失敗 (%s)</string>
|
||||
<string name="sync_error">在 %s 發生錯誤</string>
|
||||
<string name="sync_error_http_dav">在 %s 發生伺服器錯誤</string>
|
||||
<string name="sync_error_local_storage">在 %s 發生資料庫錯誤</string>
|
||||
<string-array name="sync_error_phases">
|
||||
<item>準備同步</item>
|
||||
<item>詢問能力</item>
|
||||
<item>處理裝置上的項目刪除</item>
|
||||
<item>準備新建 / 修改項目</item>
|
||||
<item>上傳新建 / 修改的項目</item>
|
||||
<item>檢查同步狀態</item>
|
||||
<item>列出裝置上項目</item>
|
||||
<item>列出伺服器上項目</item>
|
||||
<item>比對裝置上 / 伺服器上項目</item>
|
||||
<item>從伺服器下載項目</item>
|
||||
<item>傳輸後處理中</item>
|
||||
<item>儲存同步狀態</item>
|
||||
</string-array>
|
||||
<string name="sync_error_unauthorized">使用者帳號 / 密碼錯誤</string>
|
||||
<!--cert4android-->
|
||||
<string name="certificate_notification_connection_security">DAVdroid: 連線安全性</string>
|
||||
<string name="trust_certificate_unknown_certificate_found">DAVdroid 發現未知的憑證,您要信任它嗎?</string>
|
||||
</resources>
|
||||
@@ -63,6 +63,11 @@ class AccountSettings @Throws(InvalidAccountException::class) constructor(
|
||||
"0" false */
|
||||
val KEY_MANAGE_CALENDAR_COLORS = "manage_calendar_colors"
|
||||
|
||||
/* Whether DAVdroid populates and uses CalendarContract.Colors
|
||||
value = null (not existing) false (default)
|
||||
"1" true */
|
||||
val KEY_EVENT_COLORS = "event_colors"
|
||||
|
||||
/** Contact group method:
|
||||
value = null (not existing) groups as separate VCards (default)
|
||||
"CATEGORIES" groups are per-contact CATEGORIES
|
||||
@@ -158,6 +163,9 @@ class AccountSettings @Throws(InvalidAccountException::class) constructor(
|
||||
fun setManageCalendarColors(manage: Boolean) =
|
||||
accountManager.setUserData(account, KEY_MANAGE_CALENDAR_COLORS, if (manage) null else "0")
|
||||
|
||||
fun getEventColors() = accountManager.getUserData(account, KEY_EVENT_COLORS) != null
|
||||
fun setEventColors(useColors: Boolean) =
|
||||
accountManager.setUserData(account, KEY_EVENT_COLORS, if (useColors) "1" else null)
|
||||
|
||||
// CardDAV settings
|
||||
|
||||
|
||||
@@ -54,7 +54,6 @@ class App: Application() {
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
|
||||
CustomCertificates.reinitCertManager(this)
|
||||
Logger.reinitLogger(this)
|
||||
|
||||
addressBookAccountType = getString(R.string.account_type_address_book)
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
/*
|
||||
* Copyright © 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.content.Context
|
||||
import android.os.Build
|
||||
import at.bitfire.cert4android.CustomCertManager
|
||||
import at.bitfire.davdroid.model.ServiceDB
|
||||
import at.bitfire.davdroid.model.Settings
|
||||
import okhttp3.internal.tls.OkHostnameVerifier
|
||||
import javax.net.ssl.HostnameVerifier
|
||||
import javax.net.ssl.SSLSocketFactory
|
||||
|
||||
object CustomCertificates {
|
||||
|
||||
@JvmField var certManager: CustomCertManager? = null
|
||||
var sslSocketFactoryCompat: SSLSocketFactory? = null
|
||||
var hostnameVerifier: HostnameVerifier? = null
|
||||
|
||||
fun reinitCertManager(context: Context) {
|
||||
if (BuildConfig.customCerts) {
|
||||
certManager?.close()
|
||||
|
||||
ServiceDB.OpenHelper(context).use { dbHelper ->
|
||||
val settings = Settings(dbHelper.readableDatabase)
|
||||
|
||||
val mgr = CustomCertManager(context.applicationContext, !settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false))
|
||||
certManager = mgr
|
||||
hostnameVerifier = mgr.hostnameVerifier(OkHostnameVerifier.INSTANCE)
|
||||
sslSocketFactoryCompat = SSLSocketFactoryCompat(mgr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -241,103 +241,107 @@ class DavService: Service() {
|
||||
Logger.log.info("Refreshing $serviceType collections of service #$service")
|
||||
|
||||
// create authenticating OkHttpClient (credentials taken from account settings)
|
||||
val httpClient = HttpClient.create(this@DavService, account)
|
||||
HttpClient.Builder(this@DavService, account)
|
||||
.setForeground(true)
|
||||
.build().use { client ->
|
||||
val httpClient = client.okHttpClient
|
||||
|
||||
// refresh home set list (from principal)
|
||||
readPrincipal()?.let { principalUrl ->
|
||||
Logger.log.fine("Querying principal $principalUrl for home sets")
|
||||
val principal = DavResource(httpClient, principalUrl)
|
||||
queryHomeSets(principal)
|
||||
// refresh home set list (from principal)
|
||||
readPrincipal()?.let { principalUrl ->
|
||||
Logger.log.fine("Querying principal $principalUrl for home sets")
|
||||
val principal = DavResource(httpClient, principalUrl)
|
||||
queryHomeSets(principal)
|
||||
|
||||
// refresh home sets: calendar-proxy-read/write-for
|
||||
for ((resource, proxyRead) in principal.findProperties(CalendarProxyReadFor.NAME) as List<Pair<DavResource, CalendarProxyReadFor>>)
|
||||
for (href in proxyRead.hrefs) {
|
||||
Logger.log.fine("Principal is a read-only proxy for $href, checking for home sets")
|
||||
resource.location.resolve(href)?.let { queryHomeSets(DavResource(httpClient, it)) }
|
||||
}
|
||||
for ((resource, proxyWrite) in principal.findProperties(CalendarProxyWriteFor.NAME) as List<Pair<DavResource, CalendarProxyWriteFor>>)
|
||||
for (href in proxyWrite.hrefs) {
|
||||
Logger.log.fine("Principal is a read/write proxy for $href, checking for home sets")
|
||||
resource.location.resolve(href)?.let { queryHomeSets(DavResource(httpClient, it)) }
|
||||
}
|
||||
// refresh home sets: calendar-proxy-read/write-for
|
||||
for ((resource, proxyRead) in principal.findProperties(CalendarProxyReadFor.NAME) as List<Pair<DavResource, CalendarProxyReadFor>>)
|
||||
for (href in proxyRead.hrefs) {
|
||||
Logger.log.fine("Principal is a read-only proxy for $href, checking for home sets")
|
||||
resource.location.resolve(href)?.let { queryHomeSets(DavResource(httpClient, it)) }
|
||||
}
|
||||
for ((resource, proxyWrite) in principal.findProperties(CalendarProxyWriteFor.NAME) as List<Pair<DavResource, CalendarProxyWriteFor>>)
|
||||
for (href in proxyWrite.hrefs) {
|
||||
Logger.log.fine("Principal is a read/write proxy for $href, checking for home sets")
|
||||
resource.location.resolve(href)?.let { queryHomeSets(DavResource(httpClient, it)) }
|
||||
}
|
||||
|
||||
// refresh home sets: direct group memberships
|
||||
(principal.properties[GroupMembership.NAME] as GroupMembership?)?.let { groupMembership ->
|
||||
for (href in groupMembership.hrefs) {
|
||||
Logger.log.fine("Principal is member of group $href, checking for home sets")
|
||||
principal.location.resolve(href)?.let { url ->
|
||||
try {
|
||||
queryHomeSets(DavResource(httpClient, url))
|
||||
} catch(e: HttpException) {
|
||||
Logger.log.log(Level.WARNING, "Couldn't query member group", e)
|
||||
} catch(e: DavException) {
|
||||
Logger.log.log(Level.WARNING, "Couldn't query member group", e)
|
||||
// refresh home sets: direct group memberships
|
||||
(principal.properties[GroupMembership.NAME] as GroupMembership?)?.let { groupMembership ->
|
||||
for (href in groupMembership.hrefs) {
|
||||
Logger.log.fine("Principal is member of group $href, checking for home sets")
|
||||
principal.location.resolve(href)?.let { url ->
|
||||
try {
|
||||
queryHomeSets(DavResource(httpClient, url))
|
||||
} catch(e: HttpException) {
|
||||
Logger.log.log(Level.WARNING, "Couldn't query member group", e)
|
||||
} catch(e: DavException) {
|
||||
Logger.log.log(Level.WARNING, "Couldn't query member group", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remember selected collections
|
||||
val selectedCollections = HashSet<HttpUrl>()
|
||||
collections.values
|
||||
.filter { it.selected }
|
||||
.forEach { (url,_) -> HttpUrl.parse(url)?.let { selectedCollections.add(it) } }
|
||||
// remember selected collections
|
||||
val selectedCollections = HashSet<HttpUrl>()
|
||||
collections.values
|
||||
.filter { it.selected }
|
||||
.forEach { (url,_) -> HttpUrl.parse(url)?.let { selectedCollections.add(it) } }
|
||||
|
||||
// now refresh collections (taken from home sets)
|
||||
val itHomeSets = homeSets.iterator()
|
||||
while (itHomeSets.hasNext()) {
|
||||
val homeSetUrl = itHomeSets.next()
|
||||
Logger.log.fine("Listing home set $homeSetUrl")
|
||||
// now refresh collections (taken from home sets)
|
||||
val itHomeSets = homeSets.iterator()
|
||||
while (itHomeSets.hasNext()) {
|
||||
val homeSetUrl = itHomeSets.next()
|
||||
Logger.log.fine("Listing home set $homeSetUrl")
|
||||
|
||||
val homeSet = DavResource(httpClient, homeSetUrl)
|
||||
try {
|
||||
homeSet.propfind(1, *CollectionInfo.DAV_PROPERTIES)
|
||||
val itCollections = IteratorChain<DavResource>(homeSet.members.iterator(), SingletonIterator(homeSet))
|
||||
while (itCollections.hasNext()) {
|
||||
val member = itCollections.next()
|
||||
val info = CollectionInfo(member)
|
||||
info.confirmed = true
|
||||
Logger.log.log(Level.FINE, "Found collection", info)
|
||||
|
||||
if ((serviceType == Services.SERVICE_CARDDAV && info.type == CollectionInfo.Type.ADDRESS_BOOK) ||
|
||||
(serviceType == Services.SERVICE_CALDAV && info.type == CollectionInfo.Type.CALENDAR))
|
||||
collections[member.location] = info
|
||||
}
|
||||
} catch(e: HttpException) {
|
||||
if (e.status in arrayOf(403, 404, 410))
|
||||
// delete home set only if it was not accessible (40x)
|
||||
itHomeSets.remove()
|
||||
}
|
||||
}
|
||||
|
||||
// check/refresh unconfirmed collections
|
||||
val itCollections = collections.entries.iterator()
|
||||
while (itCollections.hasNext()) {
|
||||
val (url, info) = itCollections.next()
|
||||
if (!info.confirmed)
|
||||
val homeSet = DavResource(httpClient, homeSetUrl)
|
||||
try {
|
||||
val collection = DavResource(httpClient, url)
|
||||
collection.propfind(0, *CollectionInfo.DAV_PROPERTIES)
|
||||
val info = CollectionInfo(collection)
|
||||
info.confirmed = true
|
||||
homeSet.propfind(1, *CollectionInfo.DAV_PROPERTIES)
|
||||
val itCollections = IteratorChain<DavResource>(homeSet.members.iterator(), SingletonIterator(homeSet))
|
||||
while (itCollections.hasNext()) {
|
||||
val member = itCollections.next()
|
||||
val info = CollectionInfo(member)
|
||||
info.confirmed = true
|
||||
Logger.log.log(Level.FINE, "Found collection", info)
|
||||
|
||||
// remove unusable collections
|
||||
if ((serviceType == Services.SERVICE_CARDDAV && info.type != CollectionInfo.Type.ADDRESS_BOOK) ||
|
||||
(serviceType == Services.SERVICE_CALDAV && info.type != CollectionInfo.Type.CALENDAR))
|
||||
itCollections.remove()
|
||||
if ((serviceType == Services.SERVICE_CARDDAV && info.type == CollectionInfo.Type.ADDRESS_BOOK) ||
|
||||
(serviceType == Services.SERVICE_CALDAV && info.type == CollectionInfo.Type.CALENDAR))
|
||||
collections[member.location] = info
|
||||
}
|
||||
} catch(e: HttpException) {
|
||||
if (e.status in arrayOf(403, 404, 410))
|
||||
// delete collection only if it was not accessible (40x)
|
||||
itCollections.remove()
|
||||
else
|
||||
throw e
|
||||
// delete home set only if it was not accessible (40x)
|
||||
itHomeSets.remove()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// restore selections
|
||||
for (url in selectedCollections)
|
||||
collections[url]?.let { it.selected = true }
|
||||
// check/refresh unconfirmed collections
|
||||
val itCollections = collections.entries.iterator()
|
||||
while (itCollections.hasNext()) {
|
||||
val (url, info) = itCollections.next()
|
||||
if (!info.confirmed)
|
||||
try {
|
||||
val collection = DavResource(httpClient, url)
|
||||
collection.propfind(0, *CollectionInfo.DAV_PROPERTIES)
|
||||
val info = CollectionInfo(collection)
|
||||
info.confirmed = true
|
||||
|
||||
// remove unusable collections
|
||||
if ((serviceType == Services.SERVICE_CARDDAV && info.type != CollectionInfo.Type.ADDRESS_BOOK) ||
|
||||
(serviceType == Services.SERVICE_CALDAV && info.type != CollectionInfo.Type.CALENDAR))
|
||||
itCollections.remove()
|
||||
} catch(e: HttpException) {
|
||||
if (e.status in arrayOf(403, 404, 410))
|
||||
// delete collection only if it was not accessible (40x)
|
||||
itCollections.remove()
|
||||
else
|
||||
throw e
|
||||
}
|
||||
}
|
||||
|
||||
// restore selections
|
||||
for (url in selectedCollections)
|
||||
collections[url]?.let { it.selected = true }
|
||||
}
|
||||
|
||||
db.beginTransactionNonExclusive()
|
||||
try {
|
||||
|
||||
@@ -11,6 +11,7 @@ package at.bitfire.davdroid;
|
||||
import android.accounts.Account
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import at.bitfire.cert4android.CustomCertManager
|
||||
import at.bitfire.dav4android.BasicDigestAuthHandler
|
||||
import at.bitfire.dav4android.UrlUtils
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
@@ -19,7 +20,9 @@ import at.bitfire.davdroid.model.Settings
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import okhttp3.internal.tls.OkHostnameVerifier
|
||||
import okhttp3.logging.HttpLoggingInterceptor
|
||||
import java.io.Closeable
|
||||
import java.net.InetSocketAddress
|
||||
import java.net.Proxy
|
||||
import java.text.SimpleDateFormat
|
||||
@@ -27,12 +30,113 @@ import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
import java.util.logging.Level
|
||||
|
||||
class HttpClient private constructor() {
|
||||
class HttpClient private constructor(
|
||||
val okHttpClient: OkHttpClient,
|
||||
private val certManager: CustomCertManager?
|
||||
): Closeable {
|
||||
|
||||
companion object {
|
||||
override fun close() {
|
||||
certManager?.close()
|
||||
}
|
||||
|
||||
private val client = OkHttpClient()
|
||||
private val userAgentInterceptor = UserAgentInterceptor()
|
||||
|
||||
class Builder @JvmOverloads constructor(
|
||||
val context: Context? = null,
|
||||
accountSettings: AccountSettings? = null,
|
||||
logger: java.util.logging.Logger = Logger.log
|
||||
) {
|
||||
var certManager: CustomCertManager? = null
|
||||
private val orig = OkHttpClient.Builder()
|
||||
|
||||
init {
|
||||
// set timeouts
|
||||
orig.connectTimeout(30, TimeUnit.SECONDS)
|
||||
orig.writeTimeout(30, TimeUnit.SECONDS)
|
||||
orig.readTimeout(120, TimeUnit.SECONDS)
|
||||
|
||||
// don't allow redirects by default, because it would break PROPFIND handling
|
||||
orig.followRedirects(false)
|
||||
|
||||
// add User-Agent to every request
|
||||
orig.addNetworkInterceptor(UserAgentInterceptor)
|
||||
|
||||
// add cookie store for non-persistent cookies (some services like Horde use cookies for session tracking)
|
||||
orig.cookieJar(MemoryCookieStore())
|
||||
|
||||
// add network logging, if requested
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
val loggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
|
||||
message -> logger.finest(message)
|
||||
})
|
||||
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
||||
orig.addInterceptor(loggingInterceptor)
|
||||
}
|
||||
|
||||
context?.let {
|
||||
ServiceDB.OpenHelper(context).use { dbHelper ->
|
||||
val settings = Settings(dbHelper.readableDatabase)
|
||||
|
||||
// custom proxy support
|
||||
try {
|
||||
if (settings.getBoolean(App.OVERRIDE_PROXY, false)) {
|
||||
val address = InetSocketAddress(
|
||||
settings.getString(App.OVERRIDE_PROXY_HOST, App.OVERRIDE_PROXY_HOST_DEFAULT),
|
||||
settings.getInt(App.OVERRIDE_PROXY_PORT, App.OVERRIDE_PROXY_PORT_DEFAULT)
|
||||
)
|
||||
|
||||
val proxy = Proxy(Proxy.Type.HTTP, address)
|
||||
orig.proxy(proxy)
|
||||
Logger.log.log(Level.INFO, "Using proxy", proxy)
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
||||
}
|
||||
|
||||
// use cert4android to manage self-signed certificates
|
||||
if (BuildConfig.customCerts)
|
||||
customCertManager(CustomCertManager(context, !settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)))
|
||||
}
|
||||
}
|
||||
|
||||
// use account settings for authentication
|
||||
accountSettings?.let {
|
||||
val userName = it.username()
|
||||
val password = it.password()
|
||||
if (userName != null && password != null)
|
||||
addAuthentication(null, userName, password)
|
||||
}
|
||||
}
|
||||
|
||||
constructor(context: Context, account: Account): this(context, AccountSettings(context, account))
|
||||
|
||||
constructor(context: Context, host: String?, username: String, password: String): this(context) {
|
||||
addAuthentication(host, username, password)
|
||||
}
|
||||
|
||||
fun followRedirects(follow: Boolean) { orig.followRedirects(follow) }
|
||||
|
||||
fun customCertManager(manager: CustomCertManager) {
|
||||
certManager = manager
|
||||
orig.sslSocketFactory(SSLSocketFactoryCompat(manager), manager)
|
||||
orig.hostnameVerifier(manager.hostnameVerifier(OkHostnameVerifier.INSTANCE))
|
||||
}
|
||||
fun setForeground(foreground: Boolean): Builder {
|
||||
certManager?.appInForeground = foreground
|
||||
return this
|
||||
}
|
||||
|
||||
fun addAuthentication(host: String?, username: String, password: String): Builder {
|
||||
val authHandler = BasicDigestAuthHandler(UrlUtils.hostToDomain(host), username, password)
|
||||
orig .addNetworkInterceptor(authHandler)
|
||||
.authenticator(authHandler)
|
||||
return this
|
||||
}
|
||||
|
||||
fun build() = HttpClient(orig.build(), certManager)
|
||||
}
|
||||
|
||||
|
||||
private object UserAgentInterceptor: Interceptor {
|
||||
|
||||
private val productName = when(BuildConfig.FLAVOR) {
|
||||
App.FLAVOR_ICLOUD -> "MultiSync for Cloud"
|
||||
@@ -42,104 +146,6 @@ class HttpClient private constructor() {
|
||||
private val userAgentDate = SimpleDateFormat("yyyy/MM/dd", Locale.US).format(Date(BuildConfig.buildTime))
|
||||
private val userAgent = "$productName/${BuildConfig.VERSION_NAME} ($userAgentDate; dav4android; okhttp3) Android/${Build.VERSION.RELEASE}"
|
||||
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun create(context: Context?, settings: AccountSettings? = null, logger: java.util.logging.Logger = Logger.log): OkHttpClient {
|
||||
var builder = defaultBuilder(context, logger)
|
||||
|
||||
// use account settings for authentication
|
||||
settings?.let {
|
||||
val userName = it.username()
|
||||
val password = it.password()
|
||||
if (userName != null && password != null)
|
||||
builder = addAuthentication(builder, null, userName, password)
|
||||
}
|
||||
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(InvalidAccountException::class)
|
||||
fun create(context: Context, account: Account) =
|
||||
create(context, AccountSettings(context, account))
|
||||
|
||||
|
||||
private fun defaultBuilder(context: Context?, logger: java.util.logging.Logger): OkHttpClient.Builder {
|
||||
val builder = client.newBuilder()
|
||||
|
||||
// use MemorizingTrustManager to manage self-signed certificates
|
||||
if (CustomCertificates.sslSocketFactoryCompat != null && CustomCertificates.certManager != null)
|
||||
builder.sslSocketFactory(CustomCertificates.sslSocketFactoryCompat, CustomCertificates.certManager)
|
||||
CustomCertificates.hostnameVerifier?.let { builder.hostnameVerifier(it) }
|
||||
|
||||
// set timeouts
|
||||
builder.connectTimeout(30, TimeUnit.SECONDS)
|
||||
builder.writeTimeout(30, TimeUnit.SECONDS)
|
||||
builder.readTimeout(120, TimeUnit.SECONDS)
|
||||
|
||||
// don't allow redirects, because it would break PROPFIND handling
|
||||
builder.followRedirects(false)
|
||||
|
||||
// custom proxy support
|
||||
context?.let {
|
||||
ServiceDB.OpenHelper(it).use { dbHelper ->
|
||||
try {
|
||||
val settings = Settings(dbHelper.readableDatabase)
|
||||
if (settings.getBoolean(App.OVERRIDE_PROXY, false)) {
|
||||
val address = InetSocketAddress(
|
||||
settings.getString(App.OVERRIDE_PROXY_HOST, App.OVERRIDE_PROXY_HOST_DEFAULT),
|
||||
settings.getInt(App.OVERRIDE_PROXY_PORT, App.OVERRIDE_PROXY_PORT_DEFAULT)
|
||||
)
|
||||
|
||||
val proxy = Proxy(Proxy.Type.HTTP, address)
|
||||
builder.proxy(proxy)
|
||||
Logger.log.log(Level.INFO, "Using proxy", proxy)
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
Logger.log.log(Level.SEVERE, "Can't set proxy, ignoring", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// add User-Agent to every request
|
||||
builder.addNetworkInterceptor(userAgentInterceptor)
|
||||
|
||||
// add cookie store for non-persistent cookies (some services like Horde use cookies for session tracking)
|
||||
builder.cookieJar(MemoryCookieStore())
|
||||
|
||||
// add network logging, if requested
|
||||
if (logger.isLoggable(Level.FINEST)) {
|
||||
val loggingInterceptor = HttpLoggingInterceptor(HttpLoggingInterceptor.Logger {
|
||||
message -> logger.finest(message)
|
||||
})
|
||||
loggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
|
||||
builder.addInterceptor(loggingInterceptor)
|
||||
}
|
||||
|
||||
return builder
|
||||
}
|
||||
|
||||
fun addAuthentication(builder: OkHttpClient.Builder, host: String?, username: String, password: String): OkHttpClient.Builder {
|
||||
val authHandler = BasicDigestAuthHandler(UrlUtils.hostToDomain(host), username, password);
|
||||
return builder
|
||||
.addNetworkInterceptor(authHandler)
|
||||
.authenticator(authHandler)
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
@JvmStatic
|
||||
fun addAuthentication(client: OkHttpClient, host: String? = null, username: String, password: String): OkHttpClient {
|
||||
val builder = client.newBuilder()
|
||||
addAuthentication(builder, host, username, password)
|
||||
return builder.build()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class UserAgentInterceptor: Interceptor {
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val locale = Locale.getDefault()
|
||||
val request = chain.request().newBuilder()
|
||||
|
||||
@@ -32,14 +32,11 @@ object Logger {
|
||||
|
||||
@JvmField
|
||||
val log = Logger.getLogger("davdroid")!!
|
||||
init {
|
||||
at.bitfire.dav4android.Constants.log = Logger.getLogger("davdroid.dav4android")
|
||||
at.bitfire.cert4android.Constants.log = Logger.getLogger("davdroid.cert4android")
|
||||
}
|
||||
|
||||
|
||||
fun reinitLogger(context: Context) {
|
||||
ServiceDB.OpenHelper(context).use { dbHelper ->
|
||||
val settings = Settings(dbHelper.getReadableDatabase())
|
||||
val settings = Settings(dbHelper.readableDatabase)
|
||||
|
||||
val logToFile = settings.getBoolean(App.LOG_TO_EXTERNAL_STORAGE, false)
|
||||
val logVerbose = logToFile || Log.isLoggable(log.name, Log.DEBUG)
|
||||
@@ -72,7 +69,7 @@ object Logger {
|
||||
|
||||
val fileHandler = FileHandler(fileName)
|
||||
fileHandler.formatter = PlainTextFormatter.DEFAULT
|
||||
log.addHandler(fileHandler)
|
||||
rootLogger.addHandler(fileHandler)
|
||||
|
||||
val prefIntent = Intent(context, AppSettingsActivity::class.java)
|
||||
prefIntent.putExtra(AppSettingsActivity.EXTRA_SCROLL_TO, "log_to_external_storage")
|
||||
@@ -86,7 +83,7 @@ object Logger {
|
||||
.bigText(context.getString(R.string.logging_to_external_storage, dir.path)))
|
||||
.setOngoing(true)
|
||||
|
||||
} catch (e: IOException) {
|
||||
} catch(e: IOException) {
|
||||
log.log(Level.SEVERE, "Couldn't create external log file", e)
|
||||
|
||||
builder .setContentText(context.getString(R.string.logging_couldnt_create_file, e.localizedMessage))
|
||||
|
||||
@@ -29,11 +29,9 @@ class PlainTextFormatter private constructor(
|
||||
builder .append(DateFormatUtils.format(r.millis, "yyyy-MM-dd HH:mm:ss"))
|
||||
.append(" ").append(r.threadID).append(" ")
|
||||
|
||||
if (r.sourceClassName.replaceFirst("\\$.*", "") != r.loggerName) {
|
||||
val className = shortClassName(r.sourceClassName)
|
||||
if (className != "ical4android.AndroidAppender")
|
||||
builder.append("[").append(className).append("] ")
|
||||
}
|
||||
val className = shortClassName(r.sourceClassName)
|
||||
if (className != r.loggerName)
|
||||
builder.append("[").append(className).append("] ")
|
||||
|
||||
builder.append(r.message)
|
||||
|
||||
@@ -54,8 +52,7 @@ class PlainTextFormatter private constructor(
|
||||
}
|
||||
|
||||
private fun shortClassName(className: String) = className
|
||||
.replace("at.bitfire.davdroid.", "")
|
||||
.replace("at.bitfire.", "")
|
||||
.replace(Regex("^at\\.bitfire\\.(dav|cert4an|dav4an|ical4an|vcard4an)droid\\."), "")
|
||||
.replace(Regex("\\$.*$"), "")
|
||||
|
||||
}
|
||||
|
||||
@@ -9,11 +9,10 @@
|
||||
package at.bitfire.davdroid.model
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.ContentValues;
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.database.sqlite.SQLiteDatabase
|
||||
import at.bitfire.davdroid.CustomCertificates
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
|
||||
class Settings(
|
||||
@@ -54,6 +53,23 @@ class Settings(
|
||||
}
|
||||
|
||||
|
||||
fun getLong(name: String, defaultValue: Long): Long {
|
||||
db.query(ServiceDB.Settings._TABLE, arrayOf(ServiceDB.Settings.VALUE),
|
||||
"${ServiceDB.Settings.NAME}=?", arrayOf(name), null, null, null)?.use { cursor ->
|
||||
if (cursor.moveToNext() && !cursor.isNull(0))
|
||||
return if (cursor.isNull(0)) defaultValue else cursor.getLong(0)
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
fun putLong(name: String, value: Long?) {
|
||||
val values = ContentValues(2)
|
||||
values.put(ServiceDB.Settings.NAME, name)
|
||||
values.put(ServiceDB.Settings.VALUE, value)
|
||||
db.insertWithOnConflict(ServiceDB.Settings._TABLE, null, values, SQLiteDatabase.CONFLICT_REPLACE)
|
||||
}
|
||||
|
||||
|
||||
fun getString(name: String, defaultValue: String?): String? {
|
||||
db.query(ServiceDB.Settings._TABLE, arrayOf(ServiceDB.Settings.VALUE),
|
||||
"${ServiceDB.Settings.NAME}=?", arrayOf(name), null, null, null)?.use { cursor ->
|
||||
@@ -83,9 +99,7 @@ class Settings(
|
||||
}
|
||||
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
Logger.log.info("Received broadcast: re-initializing settings (logger/cert manager)")
|
||||
|
||||
CustomCertificates.reinitCertManager(context)
|
||||
Logger.log.info("Received broadcast: re-initializing settings (logger)")
|
||||
Logger.reinitLogger(context)
|
||||
}
|
||||
|
||||
|
||||
@@ -58,9 +58,6 @@ class LocalCalendar private constructor(
|
||||
values.put(Calendars.SYNC_EVENTS, 1)
|
||||
val uri = create(account, provider, values)
|
||||
|
||||
// create calendar colors
|
||||
AndroidCalendar.insertColors(provider, account)
|
||||
|
||||
return uri
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,6 @@ class CalendarSyncManager(
|
||||
|
||||
val MAX_MULTIGET = 20
|
||||
|
||||
|
||||
init {
|
||||
localCollection = localCalendar
|
||||
}
|
||||
@@ -65,7 +64,7 @@ class CalendarSyncManager(
|
||||
|
||||
override fun prepare(): Boolean {
|
||||
collectionURL = HttpUrl.parse(localCalendar.name ?: return false) ?: return false
|
||||
davCollection = DavCalendar(httpClient, collectionURL)
|
||||
davCollection = DavCalendar(httpClient.okHttpClient, collectionURL)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -41,12 +41,18 @@ class CalendarsSyncAdapterService: SyncAdapterService() {
|
||||
if (!extras.containsKey(ContentResolver.SYNC_EXTRAS_MANUAL) && !checkSyncConditions(settings))
|
||||
return
|
||||
|
||||
if (settings.getEventColors())
|
||||
AndroidCalendar.insertColors(provider, account)
|
||||
else
|
||||
AndroidCalendar.removeColors(provider, account)
|
||||
|
||||
updateLocalCalendars(provider, account, settings)
|
||||
|
||||
for (calendar in AndroidCalendar.find(account, provider, LocalCalendar.Factory, "${CalendarContract.Calendars.SYNC_EVENTS}!=0", null)) {
|
||||
Logger.log.info("Synchronizing calendar #${calendar.id}, URL: ${calendar.name}")
|
||||
CalendarSyncManager(context, account, settings, extras, authority, syncResult, provider, calendar)
|
||||
.performSync()
|
||||
CalendarSyncManager(context, account, settings, extras, authority, syncResult, provider, calendar).use {
|
||||
it.performSync()
|
||||
}
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't sync calendars", e)
|
||||
|
||||
@@ -39,8 +39,9 @@ class ContactsSyncAdapterService: SyncAdapterService() {
|
||||
Logger.log.info("Synchronizing address book: ${addressBook.getURL()}")
|
||||
Logger.log.info("Taking settings from: ${addressBook.getMainAccount()}")
|
||||
|
||||
ContactsSyncManager(context, account, settings, extras, authority, syncResult, provider, addressBook)
|
||||
.performSync()
|
||||
ContactsSyncManager(context, account, settings, extras, authority, syncResult, provider, addressBook).use {
|
||||
it.performSync()
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't sync contacts", e)
|
||||
}
|
||||
|
||||
@@ -120,7 +120,7 @@ class ContactsSyncManager(
|
||||
localAddressBook.updateSettings(values)
|
||||
|
||||
collectionURL = HttpUrl.parse(localAddressBook.getURL()) ?: return false
|
||||
davCollection = DavAddressBook(httpClient, collectionURL)
|
||||
davCollection = DavAddressBook(httpClient.okHttpClient, collectionURL)
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -425,21 +425,20 @@ class ContactsSyncManager(
|
||||
return null
|
||||
}
|
||||
|
||||
var resourceClient = HttpClient.create(context)
|
||||
|
||||
// authenticate only against a certain host, and only upon request
|
||||
val username = settings.username()
|
||||
val password = settings.password()
|
||||
if (username != null && password != null)
|
||||
resourceClient = HttpClient.addAuthentication(resourceClient, baseUrl.host(), username, password)
|
||||
val builder = if (username != null && password != null)
|
||||
HttpClient.Builder(context, baseUrl.host(), username, password)
|
||||
else
|
||||
HttpClient.Builder(context)
|
||||
|
||||
// allow redirects
|
||||
resourceClient = resourceClient.newBuilder()
|
||||
.followRedirects(true)
|
||||
.build()
|
||||
builder.followRedirects(true)
|
||||
|
||||
val client = builder.build()
|
||||
try {
|
||||
val response = resourceClient.newCall(Request.Builder()
|
||||
val response = client.okHttpClient.newCall(Request.Builder()
|
||||
.get()
|
||||
.url(httpUrl)
|
||||
.build()).execute()
|
||||
@@ -450,6 +449,8 @@ class ContactsSyncManager(
|
||||
Logger.log.warning("Couldn't download external resource")
|
||||
} catch(e: IOException) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't download external resource", e)
|
||||
} finally {
|
||||
client.close()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import at.bitfire.ical4android.CalendarStorageException
|
||||
import at.bitfire.vcard4android.ContactsStorageException
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.RequestBody
|
||||
import java.io.Closeable
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.logging.Level
|
||||
@@ -46,7 +47,7 @@ abstract class SyncManager(
|
||||
val authority: String,
|
||||
val syncResult: SyncResult,
|
||||
val uniqueCollectionId: String
|
||||
) {
|
||||
): Closeable {
|
||||
|
||||
val SYNC_PHASE_PREPARE = 0
|
||||
val SYNC_PHASE_QUERY_CAPABILITIES = 1
|
||||
@@ -65,7 +66,7 @@ abstract class SyncManager(
|
||||
|
||||
protected lateinit var localCollection: LocalCollection<*>
|
||||
|
||||
protected val httpClient = HttpClient.create(context, settings)
|
||||
protected val httpClient = HttpClient.Builder(context, settings).build()
|
||||
protected lateinit var collectionURL: HttpUrl
|
||||
protected lateinit var davCollection: DavResource
|
||||
|
||||
@@ -235,6 +236,10 @@ abstract class SyncManager(
|
||||
}
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
httpClient.close()
|
||||
}
|
||||
|
||||
|
||||
/** Prepares synchronization (for instance, allocates necessary resources).
|
||||
* @return whether actual synchronization is required / can be made. true = synchronization
|
||||
@@ -261,7 +266,7 @@ abstract class SyncManager(
|
||||
if (fileName != null) {
|
||||
Logger.log.info("$fileName has been deleted locally -> deleting from server")
|
||||
|
||||
val remote = DavResource(httpClient, collectionURL.newBuilder().addPathSegment(fileName).build())
|
||||
val remote = DavResource(httpClient.okHttpClient, collectionURL.newBuilder().addPathSegment(fileName).build())
|
||||
currentDavResource = remote
|
||||
try {
|
||||
remote.delete(local.eTag)
|
||||
@@ -306,7 +311,7 @@ abstract class SyncManager(
|
||||
currentLocalResource = local
|
||||
val fileName = local.fileName
|
||||
|
||||
val remote = DavResource(httpClient, collectionURL.newBuilder().addPathSegment(fileName).build())
|
||||
val remote = DavResource(httpClient.okHttpClient, collectionURL.newBuilder().addPathSegment(fileName).build())
|
||||
currentDavResource = remote
|
||||
|
||||
// generate entity to upload (VCard, iCal, whatever)
|
||||
|
||||
@@ -50,8 +50,9 @@ class TasksSyncAdapterService: SyncAdapterService() {
|
||||
|
||||
for (taskList in AndroidTaskList.find(account, taskProvider, LocalTaskList.Factory, "${TaskContract.TaskLists.SYNC_ENABLED}!=0", null)) {
|
||||
Logger.log.info("Synchronizing task list #${taskList.id} [${taskList.syncId}]")
|
||||
TasksSyncManager(context, account, settings, extras, authority, syncResult, taskProvider, taskList)
|
||||
.performSync()
|
||||
TasksSyncManager(context, account, settings, extras, authority, syncResult, taskProvider, taskList).use {
|
||||
it.performSync()
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
Logger.log.log(Level.SEVERE, "Couldn't sync task lists", e)
|
||||
|
||||
@@ -62,7 +62,7 @@ class TasksSyncManager(
|
||||
|
||||
override fun prepare(): Boolean {
|
||||
collectionURL = HttpUrl.parse(localTaskList.syncId ?: return false) ?: return false
|
||||
davCollection = DavCalendar(httpClient, collectionURL)
|
||||
davCollection = DavCalendar(httpClient.okHttpClient, collectionURL)
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,6 @@ package at.bitfire.davdroid.ui
|
||||
|
||||
import android.accounts.Account
|
||||
import android.accounts.AccountManager
|
||||
import android.app.AlertDialog
|
||||
import android.app.Dialog
|
||||
import android.app.LoaderManager
|
||||
import android.content.*
|
||||
@@ -23,12 +22,12 @@ import android.provider.CalendarContract
|
||||
import android.provider.ContactsContract
|
||||
import android.support.design.widget.Snackbar
|
||||
import android.support.v4.app.DialogFragment
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.widget.Toolbar
|
||||
import android.view.*
|
||||
import android.widget.*
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.CustomCertificates
|
||||
import at.bitfire.davdroid.DavService
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
@@ -40,6 +39,7 @@ import at.bitfire.davdroid.resource.LocalAddressBook
|
||||
import at.bitfire.davdroid.resource.LocalTaskList
|
||||
import at.bitfire.ical4android.TaskProvider
|
||||
import at.bitfire.vcard4android.ContactsStorageException
|
||||
import kotlinx.android.synthetic.main.account_caldav_item.view.*
|
||||
import kotlinx.android.synthetic.main.activity_account.*
|
||||
import java.util.*
|
||||
import java.util.logging.Level
|
||||
@@ -97,16 +97,6 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
|
||||
loaderManager.initLoader(0, intent.extras, this)
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
CustomCertificates.certManager?.let { it.appInForeground = false }
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
CustomCertificates.certManager?.let { it.appInForeground = true }
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.activity_account, menu)
|
||||
return true
|
||||
@@ -178,11 +168,13 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
|
||||
}
|
||||
|
||||
|
||||
private val onItemClickListener = AdapterView.OnItemClickListener { parent, _, position, _ ->
|
||||
private val onItemClickListener = AdapterView.OnItemClickListener { parent, view, position, _ ->
|
||||
if (!view.isEnabled)
|
||||
return@OnItemClickListener
|
||||
|
||||
val list = parent as ListView
|
||||
val adapter = list.adapter as ArrayAdapter<CollectionInfo>
|
||||
val info = adapter.getItem(position)
|
||||
|
||||
val nowChecked = !info.selected
|
||||
|
||||
OpenHelper(this@AccountActivity).use { dbHelper ->
|
||||
@@ -406,7 +398,6 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
|
||||
class AddressBookAdapter(
|
||||
context: Context
|
||||
): ArrayAdapter<CollectionInfo>(context, R.layout.account_carddav_item) {
|
||||
|
||||
override fun getView(position: Int, v: View?, parent: ViewGroup?): View {
|
||||
val v = v ?: LayoutInflater.from(context).inflate(R.layout.account_carddav_item, parent, false)
|
||||
val info = getItem(position)
|
||||
@@ -435,11 +426,14 @@ class AccountActivity: AppCompatActivity(), Toolbar.OnMenuItemClickListener, Pop
|
||||
class CalendarAdapter(
|
||||
context: Context
|
||||
): ArrayAdapter<CollectionInfo>(context, R.layout.account_caldav_item) {
|
||||
|
||||
override fun getView(position: Int, v: View?, parent: ViewGroup?): View {
|
||||
val v = v ?: LayoutInflater.from(context).inflate(R.layout.account_caldav_item, parent, false)
|
||||
val info = getItem(position)
|
||||
|
||||
val enabled = info.selected || info.supportsVEVENT || info.supportsVTODO
|
||||
v.isEnabled = enabled
|
||||
v.checked.isEnabled = enabled
|
||||
|
||||
val checked: CheckBox = v.findViewById(R.id.checked)
|
||||
checked.isChecked = info.selected
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.support.v4.app.LoaderManager
|
||||
import android.support.v4.app.NavUtils
|
||||
import android.support.v4.content.AsyncTaskLoader
|
||||
import android.support.v4.content.Loader
|
||||
import android.support.v7.app.AlertDialog
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.support.v7.preference.*
|
||||
import android.support.v7.preference.Preference.OnPreferenceChangeListener
|
||||
@@ -227,6 +228,26 @@ class AccountSettingsActivity: AppCompatActivity() {
|
||||
} else
|
||||
prefManageColors.isEnabled = false
|
||||
|
||||
val prefEventColors = findPreference("event_colors") as SwitchPreferenceCompat
|
||||
prefEventColors.isChecked = settings.getEventColors()
|
||||
prefEventColors.onPreferenceChangeListener = OnPreferenceChangeListener { _, newValue ->
|
||||
if (newValue as Boolean) {
|
||||
settings.setEventColors(true)
|
||||
loaderManager.restartLoader(0, arguments, this)
|
||||
} else
|
||||
AlertDialog.Builder(activity)
|
||||
.setIcon(R.drawable.ic_error_dark)
|
||||
.setTitle(R.string.settings_event_colors)
|
||||
.setMessage(R.string.settings_event_colors_off_confirm)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.setPositiveButton(android.R.string.ok, { _, _ ->
|
||||
settings.setEventColors(false)
|
||||
loaderManager.restartLoader(0, arguments, this)
|
||||
})
|
||||
.show()
|
||||
false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun onLoaderReset(loader: Loader<AccountSettings>) {
|
||||
|
||||
@@ -16,8 +16,9 @@ import android.support.v7.preference.EditTextPreference
|
||||
import android.support.v7.preference.Preference
|
||||
import android.support.v7.preference.PreferenceFragmentCompat
|
||||
import android.support.v7.preference.SwitchPreferenceCompat
|
||||
import at.bitfire.cert4android.CustomCertManager
|
||||
import at.bitfire.davdroid.App
|
||||
import at.bitfire.davdroid.CustomCertificates
|
||||
import at.bitfire.davdroid.BuildConfig
|
||||
import at.bitfire.davdroid.R
|
||||
import at.bitfire.davdroid.log.Logger
|
||||
import at.bitfire.davdroid.model.ServiceDB
|
||||
@@ -112,17 +113,17 @@ class AppSettingsActivity: AppCompatActivity() {
|
||||
}
|
||||
|
||||
val prefDistrustSystemCerts = findPreference("distrust_system_certs") as SwitchPreferenceCompat
|
||||
if (CustomCertificates.certManager == null)
|
||||
prefDistrustSystemCerts.isVisible = false
|
||||
else
|
||||
if (BuildConfig.customCerts)
|
||||
prefDistrustSystemCerts.isChecked = settings.getBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, false)
|
||||
else
|
||||
prefDistrustSystemCerts.isVisible = false
|
||||
prefDistrustSystemCerts.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
setDistrustSystemCerts(prefDistrustSystemCerts.isChecked)
|
||||
true
|
||||
}
|
||||
|
||||
val prefResetCertificates = findPreference("reset_certificates")
|
||||
if (CustomCertificates.certManager == null)
|
||||
if (!BuildConfig.customCerts)
|
||||
prefResetCertificates.isVisible = false
|
||||
prefResetCertificates.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||
resetCertificates()
|
||||
@@ -148,17 +149,11 @@ class AppSettingsActivity: AppCompatActivity() {
|
||||
|
||||
private fun setDistrustSystemCerts(distrust: Boolean) {
|
||||
settings.putBoolean(App.DISTRUST_SYSTEM_CERTIFICATES, distrust)
|
||||
|
||||
// re-initialize certificate manager
|
||||
CustomCertificates.reinitCertManager(context)
|
||||
|
||||
// reinitialize certificate manager of :sync process
|
||||
context.sendBroadcast(Intent(Settings.ReinitSettingsReceiver.ACTION_REINIT_SETTINGS))
|
||||
}
|
||||
|
||||
private fun resetCertificates() {
|
||||
CustomCertificates.certManager?.resetCertificates()
|
||||
Snackbar.make(view!!, getString(R.string.app_settings_reset_certificates_success), Snackbar.LENGTH_LONG).show()
|
||||
if (CustomCertManager.resetCertificates(activity))
|
||||
Snackbar.make(view!!, getString(R.string.app_settings_reset_certificates_success), Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
private fun setExternalLogging(externalLogging: Boolean) {
|
||||
|
||||
@@ -182,9 +182,12 @@ class CreateCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
|
||||
Logger.log.log(Level.SEVERE, "Couldn't assemble Extended MKCOL request", e)
|
||||
}
|
||||
|
||||
var httpClient: HttpClient? = null
|
||||
try {
|
||||
val client = HttpClient.create(context, account)
|
||||
val collection = DavResource(client, HttpUrl.parse(info.url)!!)
|
||||
httpClient = HttpClient.Builder(context, account)
|
||||
.setForeground(true)
|
||||
.build()
|
||||
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(info.url)!!)
|
||||
|
||||
// create collection on remote server
|
||||
collection.mkCol(writer.toString())
|
||||
@@ -214,6 +217,8 @@ class CreateCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
|
||||
}
|
||||
} catch(e: Exception) {
|
||||
return e
|
||||
} finally {
|
||||
httpClient?.close()
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -82,9 +82,12 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
|
||||
override fun onStartLoading() = forceLoad()
|
||||
|
||||
override fun loadInBackground(): Exception? {
|
||||
var httpClient: HttpClient? = null
|
||||
try {
|
||||
val httpClient = HttpClient.create(context, account)
|
||||
val collection = DavResource(httpClient, HttpUrl.parse(collectionInfo.url)!!)
|
||||
httpClient = HttpClient.Builder(context, account)
|
||||
.setForeground(true)
|
||||
.build()
|
||||
val collection = DavResource(httpClient.okHttpClient, HttpUrl.parse(collectionInfo.url)!!)
|
||||
|
||||
// delete collection from server
|
||||
collection.delete(null)
|
||||
@@ -98,6 +101,8 @@ class DeleteCollectionFragment: DialogFragment(), LoaderManager.LoaderCallbacks<
|
||||
return null
|
||||
} catch(e: Exception) {
|
||||
return e
|
||||
} finally {
|
||||
httpClient?.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,9 +53,9 @@ class PermissionsActivity: AppCompatActivity() {
|
||||
noTaskPermissions =
|
||||
ActivityCompat.checkSelfPermission(this, PERMISSION_READ_TASKS) != PackageManager.PERMISSION_GRANTED ||
|
||||
ActivityCompat.checkSelfPermission(this, PERMISSION_WRITE_TASKS) != PackageManager.PERMISSION_GRANTED
|
||||
findViewById(R.id.opentasks_permissions).visibility = if (noTaskPermissions) View.VISIBLE else View.GONE
|
||||
findViewById<View>(R.id.opentasks_permissions).visibility = if (noTaskPermissions) View.VISIBLE else View.GONE
|
||||
} else {
|
||||
findViewById(R.id.opentasks_permissions).visibility = View.GONE;
|
||||
findViewById<View>(R.id.opentasks_permissions).visibility = View.GONE;
|
||||
noTaskPermissions = false
|
||||
}
|
||||
|
||||
|
||||
@@ -38,11 +38,14 @@ class StartupDialogFragment: DialogFragment() {
|
||||
BATTERY_OPTIMIZATIONS,
|
||||
DEVELOPMENT_VERSION,
|
||||
GOOGLE_PLAY_ACCOUNTS_REMOVED,
|
||||
OPENTASKS_NOT_INSTALLED
|
||||
OPENTASKS_NOT_INSTALLED,
|
||||
OSE_DONATE
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private val SETTING_NEXT_DONATION_POPUP = "time_nextDonationPopup"
|
||||
|
||||
@JvmField val HINT_BATTERY_OPTIMIZATIONS = "hint_BatteryOptimizations"
|
||||
@JvmField val HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED = "hint_GooglePlayAccountsRemoved"
|
||||
@JvmField val HINT_OPENTASKS_NOT_INSTALLED = "hint_OpenTasksNotInstalled"
|
||||
@@ -57,14 +60,15 @@ class StartupDialogFragment: DialogFragment() {
|
||||
|
||||
if (BuildConfig.VERSION_NAME.contains("-alpha") || BuildConfig.VERSION_NAME.contains("-beta") || BuildConfig.VERSION_NAME.contains("-rc"))
|
||||
dialogs += StartupDialogFragment.instantiate(Mode.DEVELOPMENT_VERSION)
|
||||
else {
|
||||
// store-specific information
|
||||
if (BuildConfig.FLAVOR == App.FLAVOR_GOOGLE_PLAY) {
|
||||
// Play store
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && // only on Android <5
|
||||
settings.getBoolean(HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, true)) // and only when "Don't show again" hasn't been clicked yet
|
||||
dialogs += StartupDialogFragment.instantiate(Mode.GOOGLE_PLAY_ACCOUNTS_REMOVED)
|
||||
}
|
||||
/* else if (System.currentTimeMillis() > settings.getLong(SETTING_NEXT_DONATION_POPUP, 0))
|
||||
dialogs += StartupDialogFragment.instantiate(Mode.OSE_DONATE) */
|
||||
|
||||
// store-specific information
|
||||
if (BuildConfig.FLAVOR == App.FLAVOR_GOOGLE_PLAY) {
|
||||
// Play store
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP && // only on Android <5
|
||||
settings.getBoolean(HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, true)) // and only when "Don't show again" hasn't been clicked yet
|
||||
dialogs += StartupDialogFragment.instantiate(Mode.GOOGLE_PLAY_ACCOUNTS_REMOVED)
|
||||
}
|
||||
|
||||
// battery optimization white-listing
|
||||
@@ -97,6 +101,8 @@ class StartupDialogFragment: DialogFragment() {
|
||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
isCancelable = false
|
||||
|
||||
|
||||
|
||||
val mode = Mode.valueOf(arguments.getString(ARGS_MODE))
|
||||
return when (mode) {
|
||||
Mode.BATTERY_OPTIMIZATIONS ->
|
||||
@@ -104,8 +110,8 @@ class StartupDialogFragment: DialogFragment() {
|
||||
.setIcon(R.drawable.ic_info_dark)
|
||||
.setTitle(R.string.startup_battery_optimization)
|
||||
.setMessage(R.string.startup_battery_optimization_message)
|
||||
.setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int -> })
|
||||
.setNeutralButton(R.string.startup_battery_optimization_disable, { _: DialogInterface, _: Int ->
|
||||
.setPositiveButton(android.R.string.ok, { _, _ -> })
|
||||
.setNeutralButton(R.string.startup_battery_optimization_disable, { _, _ ->
|
||||
val intent = Intent(android.provider.Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS,
|
||||
Uri.parse("package:" + BuildConfig.APPLICATION_ID))
|
||||
if (intent.resolveActivity(context.packageManager) != null)
|
||||
@@ -141,12 +147,12 @@ class StartupDialogFragment: DialogFragment() {
|
||||
.setIcon(icon)
|
||||
.setTitle(R.string.startup_google_play_accounts_removed)
|
||||
.setMessage(R.string.startup_google_play_accounts_removed_message)
|
||||
.setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int -> })
|
||||
.setNeutralButton(R.string.startup_google_play_accounts_removed_more_info, { _: DialogInterface, _: Int ->
|
||||
.setPositiveButton(android.R.string.ok, { _, _ -> })
|
||||
.setNeutralButton(R.string.startup_google_play_accounts_removed_more_info, { _, _ ->
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.navigation_drawer_faq_url)))
|
||||
context.startActivity(intent)
|
||||
})
|
||||
.setNegativeButton(R.string.startup_dont_show_again, { _: DialogInterface, _: Int ->
|
||||
.setNegativeButton(R.string.startup_dont_show_again, { _, _ ->
|
||||
ServiceDB.OpenHelper(context).use { dbHelper ->
|
||||
val settings = Settings(dbHelper.writableDatabase)
|
||||
settings.putBoolean(HINT_GOOGLE_PLAY_ACCOUNTS_REMOVED, false)
|
||||
@@ -163,8 +169,8 @@ class StartupDialogFragment: DialogFragment() {
|
||||
.setIcon(R.drawable.ic_alarm_on_dark)
|
||||
.setTitle(R.string.startup_opentasks_not_installed)
|
||||
.setMessage(builder.toString())
|
||||
.setPositiveButton(android.R.string.ok, { _: DialogInterface, _: Int -> })
|
||||
.setNeutralButton(R.string.startup_opentasks_not_installed_install, { _: DialogInterface, _: Int ->
|
||||
.setPositiveButton(android.R.string.ok, { _, _ -> })
|
||||
.setNeutralButton(R.string.startup_opentasks_not_installed_install, { _, _ ->
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=org.dmfs.tasks"))
|
||||
if (intent.resolveActivity(context.packageManager) != null)
|
||||
context.startActivity(intent)
|
||||
@@ -179,6 +185,31 @@ class StartupDialogFragment: DialogFragment() {
|
||||
})
|
||||
.create()
|
||||
}
|
||||
|
||||
Mode.OSE_DONATE ->
|
||||
return AlertDialog.Builder(activity)
|
||||
.setIcon(R.mipmap.ic_launcher)
|
||||
.setTitle(R.string.startup_donate)
|
||||
.setMessage(R.string.startup_donate_message)
|
||||
.setPositiveButton(R.string.startup_donate_now, { _, _ ->
|
||||
val uri = Uri.parse(getString(R.string.homepage_url))
|
||||
.buildUpon()
|
||||
.appendEncodedPath("donate/")
|
||||
.build()
|
||||
startActivity(Intent(Intent.ACTION_VIEW, uri))
|
||||
ServiceDB.OpenHelper(context).use { dbHelper ->
|
||||
val settings = Settings(dbHelper.writableDatabase)
|
||||
settings.putLong(SETTING_NEXT_DONATION_POPUP, System.currentTimeMillis() + 30 * 86400000L) // 30 days
|
||||
}
|
||||
})
|
||||
.setNegativeButton(R.string.startup_donate_later, { _, _ ->
|
||||
ServiceDB.OpenHelper(context).use { dbHelper ->
|
||||
val settings = Settings(dbHelper.writableDatabase)
|
||||
settings.putLong(SETTING_NEXT_DONATION_POPUP, System.currentTimeMillis() + 14 * 86400000L) // 14 days
|
||||
}
|
||||
})
|
||||
.create()
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,10 +17,10 @@ import at.bitfire.davdroid.HttpClient
|
||||
import at.bitfire.davdroid.log.StringHandler
|
||||
import at.bitfire.davdroid.model.CollectionInfo
|
||||
import okhttp3.HttpUrl
|
||||
import okhttp3.OkHttpClient
|
||||
import org.apache.commons.lang3.builder.ReflectionToStringBuilder
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder
|
||||
import org.xbill.DNS.*
|
||||
import java.io.Closeable
|
||||
import java.io.IOException
|
||||
import java.io.Serializable
|
||||
import java.net.URI
|
||||
@@ -31,8 +31,8 @@ import java.util.logging.Logger
|
||||
|
||||
class DavResourceFinder(
|
||||
val context: Context,
|
||||
val credentials: LoginCredentials
|
||||
) {
|
||||
private val credentials: LoginCredentials
|
||||
): Closeable {
|
||||
|
||||
enum class Service(val wellKnownName: String) {
|
||||
CALDAV("caldav"),
|
||||
@@ -42,22 +42,25 @@ class DavResourceFinder(
|
||||
}
|
||||
|
||||
val log = Logger.getLogger("davdroid.DavResourceFinder")!!
|
||||
val logBuffer = StringHandler()
|
||||
private val logBuffer = StringHandler()
|
||||
init {
|
||||
log.level = Level.FINEST
|
||||
log.addHandler(logBuffer)
|
||||
}
|
||||
|
||||
val httpClient: OkHttpClient
|
||||
init {
|
||||
val builder = HttpClient.create(context, null, log).newBuilder()
|
||||
httpClient = HttpClient.addAuthentication(builder, null, credentials.userName, credentials.password).build()
|
||||
}
|
||||
private val httpClient: HttpClient = HttpClient.Builder(context, null, log)
|
||||
.addAuthentication(null, credentials.userName, credentials.password)
|
||||
.setForeground(true)
|
||||
.build()
|
||||
|
||||
fun cancel() {
|
||||
log.warning("Shutting down resource detection")
|
||||
httpClient.dispatcher().executorService().shutdownNow()
|
||||
httpClient.connectionPool().evictAll()
|
||||
httpClient.okHttpClient.dispatcher().executorService().shutdownNow()
|
||||
httpClient.okHttpClient.connectionPool().evictAll()
|
||||
}
|
||||
|
||||
override fun close() {
|
||||
httpClient.close()
|
||||
}
|
||||
|
||||
|
||||
@@ -120,7 +123,7 @@ class DavResourceFinder(
|
||||
|
||||
if (config.principal != null && service == Service.CALDAV) {
|
||||
// query email address (CalDAV scheduling: calendar-user-address-set)
|
||||
val davPrincipal = DavResource(httpClient, HttpUrl.get(config.principal)!!, log)
|
||||
val davPrincipal = DavResource(httpClient.okHttpClient, HttpUrl.get(config.principal)!!, log)
|
||||
try {
|
||||
davPrincipal.propfind(0, CalendarUserAddressSet.NAME)
|
||||
(davPrincipal.properties[CalendarUserAddressSet.NAME] as CalendarUserAddressSet?)?.let { addressSet ->
|
||||
@@ -151,7 +154,7 @@ class DavResourceFinder(
|
||||
|
||||
var principal: HttpUrl? = null
|
||||
try {
|
||||
val davBase = DavResource(httpClient, baseURL, log)
|
||||
val davBase = DavResource(httpClient.okHttpClient, baseURL, log)
|
||||
|
||||
when (service) {
|
||||
Service.CARDDAV -> {
|
||||
@@ -258,7 +261,7 @@ class DavResourceFinder(
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun providesService(url: HttpUrl, service: Service): Boolean {
|
||||
val davPrincipal = DavResource(httpClient, url, log)
|
||||
val davPrincipal = DavResource(httpClient.okHttpClient, url, log)
|
||||
try {
|
||||
davPrincipal.options()
|
||||
|
||||
@@ -348,7 +351,7 @@ class DavResourceFinder(
|
||||
*/
|
||||
@Throws(IOException::class, HttpException::class, DavException::class)
|
||||
fun getCurrentUserPrincipal(url: HttpUrl, service: Service?): URI? {
|
||||
val dav = DavResource(httpClient, url, log)
|
||||
val dav = DavResource(httpClient.okHttpClient, url, log)
|
||||
dav.propfind(0, CurrentUserPrincipal.NAME)
|
||||
|
||||
dav.findProperty(CurrentUserPrincipal.NAME)?.let { (dav, second) ->
|
||||
|
||||
@@ -14,7 +14,6 @@ import android.os.Bundle
|
||||
import android.support.v7.app.AppCompatActivity
|
||||
import android.view.Menu
|
||||
import android.view.MenuItem
|
||||
import at.bitfire.davdroid.CustomCertificates
|
||||
import at.bitfire.davdroid.R
|
||||
import java.util.*
|
||||
|
||||
@@ -59,16 +58,6 @@ class LoginActivity: AppCompatActivity() {
|
||||
.commit()
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
CustomCertificates.certManager?.let { it.appInForeground = true }
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
super.onPause()
|
||||
CustomCertificates.certManager?.let { it.appInForeground = false }
|
||||
}
|
||||
|
||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||
menuInflater.inflate(R.menu.activity_login, menu)
|
||||
return true
|
||||
|
||||
@@ -191,6 +191,10 @@
|
||||
<string name="settings_manage_calendar_colors">Kalenderfarben verwalten</string>
|
||||
<string name="settings_manage_calendar_colors_on">Kalenderfarben werden von DAVdroid verwaltet</string>
|
||||
<string name="settings_manage_calendar_colors_off">DAVdroid setzt keine Kalenderfarben</string>
|
||||
<string name="settings_event_colors">Unterstützung für Terminfarben</string>
|
||||
<string name="settings_event_colors_on">Terminfarben werden synchronisiert</string>
|
||||
<string name="settings_event_colors_off">Terminfarben werden nicht synchronisiert</string>
|
||||
<string name="settings_event_colors_off_confirm">Die Deaktivierung der Terminfarben kann bereits synchronisierte Terminfarben löschen!</string>
|
||||
<!--collection management-->
|
||||
<string name="create_addressbook">Adressbuch erstellen</string>
|
||||
<string name="create_addressbook_display_name_hint">Meine Adressen</string>
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
<string name="startup_development_version">Preview Release</string>
|
||||
<string name="startup_development_version_message">This is a development version of %s. Things may not work as expected. Your feedback is welcome.</string>
|
||||
<string name="startup_development_version_give_feedback">Give feedback</string>
|
||||
<string name="startup_development_version_feedback_url">https://davdroid.bitfire.at/forums/?pk_campaign=davdroid-app</string>
|
||||
<string name="startup_development_version_feedback_url">https://forums.bitfire.at/category/9/beta-test-discussion?pk_campaign=davdroid-app</string>
|
||||
<string name="startup_donate">Open-Source Information</string>
|
||||
<string name="startup_donate_message">We\'re happy that you use DAVdroid, which is open-source software (GPLv3). Because developing DAVdroid is hard work and took us thousands of working hours, please consider a donation.</string>
|
||||
<string name="startup_donate_now">Show donation page</string>
|
||||
@@ -220,6 +220,10 @@
|
||||
<string name="settings_manage_calendar_colors">Manage calendar colors</string>
|
||||
<string name="settings_manage_calendar_colors_on">Calendar colors are managed by DAVdroid</string>
|
||||
<string name="settings_manage_calendar_colors_off">Calendar colors are not set by DAVdroid</string>
|
||||
<string name="settings_event_colors">Event color support</string>
|
||||
<string name="settings_event_colors_on">Sync event colors</string>
|
||||
<string name="settings_event_colors_off">Do not sync event colors</string>
|
||||
<string name="settings_event_colors_off_confirm">Turning off event colors may remove already synchronized event colors.</string>
|
||||
|
||||
<!-- collection management -->
|
||||
<string name="create_addressbook">Create address book</string>
|
||||
|
||||
@@ -94,6 +94,13 @@
|
||||
android:summaryOn="@string/settings_manage_calendar_colors_on"
|
||||
android:summaryOff="@string/settings_manage_calendar_colors_off"/>
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:key="event_colors"
|
||||
android:persistent="false"
|
||||
android:title="@string/settings_event_colors"
|
||||
android:summaryOn="@string/settings_event_colors_on"
|
||||
android:summaryOff="@string/settings_event_colors_off"/>
|
||||
|
||||
</PreferenceCategory>
|
||||
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -27,11 +27,11 @@ import static org.junit.Assert.assertNull;
|
||||
public class HttpClientTest {
|
||||
|
||||
MockWebServer server;
|
||||
OkHttpClient httpClient;
|
||||
HttpClient httpClient;
|
||||
|
||||
@Before
|
||||
public void setUp() throws IOException {
|
||||
httpClient = HttpClient.create(null);
|
||||
httpClient = new HttpClient.Builder().build();
|
||||
|
||||
server = new MockWebServer();
|
||||
server.start(30000);
|
||||
@@ -40,6 +40,7 @@ public class HttpClientTest {
|
||||
@After
|
||||
public void tearDown() throws IOException {
|
||||
server.shutdown();
|
||||
httpClient.close();
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +54,7 @@ public class HttpClientTest {
|
||||
.addHeader("Set-Cookie", "cookie1=1; path=/")
|
||||
.addHeader("Set-Cookie", "cookie2=2")
|
||||
.setBody("Cookie set"));
|
||||
httpClient.newCall(new Request.Builder()
|
||||
httpClient.getOkHttpClient().newCall(new Request.Builder()
|
||||
.get().url(url)
|
||||
.build()).execute();
|
||||
assertNull(server.takeRequest().getHeader("Cookie"));
|
||||
@@ -64,14 +65,14 @@ public class HttpClientTest {
|
||||
.addHeader("Set-Cookie", "cookie1=1a; path=/; Max-Age=0")
|
||||
.addHeader("Set-Cookie", "cookie2=2a")
|
||||
.setResponseCode(200));
|
||||
httpClient.newCall(new Request.Builder()
|
||||
httpClient.getOkHttpClient().newCall(new Request.Builder()
|
||||
.get().url(url)
|
||||
.build()).execute();
|
||||
assertEquals("cookie2=2; cookie1=1", server.takeRequest().getHeader("Cookie"));
|
||||
|
||||
server.enqueue(new MockResponse()
|
||||
.setResponseCode(200));
|
||||
httpClient.newCall(new Request.Builder()
|
||||
httpClient.getOkHttpClient().newCall(new Request.Builder()
|
||||
.get().url(url)
|
||||
.build()).execute();
|
||||
assertEquals("cookie2=2a", server.takeRequest().getHeader("Cookie"));
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.1.4'
|
||||
ext.kotlin_version = '1.1.4-3'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
@@ -22,6 +22,9 @@ buildscript {
|
||||
allprojects {
|
||||
repositories {
|
||||
jcenter()
|
||||
maven {
|
||||
url "https://maven.google.com"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Submodule cert4android updated: d44ef38816...25e369a99b
Submodule dav4android updated: 4b13645363...4272709f3e
Submodule ical4android updated: d501bd45f2...c862ca02d3
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash
|
||||
|
||||
declare -A android
|
||||
android=([ca]=ca [cs]=cs [da]=da [de]=de [es]=es [fr]=fr [hu]=hu [it]=it [ja]=ja [nl]=nl [pl]=pl [pt]=pt [pt_BR]=pt-rBR [ru]=ru [sr]=sr [tr_TR]=tr-rTR [uk]=uk [zh_CN]=zh-rCN)
|
||||
android=([ca]=ca [cs]=cs [da]=da [de]=de [es]=es [fr]=fr [hu]=hu [it]=it [ja]=ja [nl]=nl [nb_NO]=nb-rNO [pl]=pl [pt]=pt [pt_BR]=pt-rBR [ru]=ru [sr]=sr [tr_TR]=tr-rTR [uk]=uk [zh_CN]=zh-rCN [zh_TW]=zh-rTW)
|
||||
|
||||
for lang in ${!android[@]}
|
||||
do
|
||||
|
||||
Submodule vcard4android updated: 48c64fc885...9f5a0b3bf7
Reference in New Issue
Block a user